Integrating latest from github/TIF/Runtime
parent
eee1597929
commit
c2a6addf1f
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Convinience namespace for allowing bitwise operations on enum classes.
|
||||
//! @note Any types declared in this namespace will have the bitwise operator overloads declared within.
|
||||
namespace Bitwise
|
||||
{
|
||||
template<typename Flags>
|
||||
Flags operator|(Flags lhs, Flags rhs)
|
||||
{
|
||||
return static_cast<Flags>(
|
||||
static_cast<std::underlying_type<Flags>::type>(lhs) | static_cast<std::underlying_type<Flags>::type>(rhs));
|
||||
}
|
||||
|
||||
template<typename Flags>
|
||||
bool IsFlagSet(Flags flags, Flags flag)
|
||||
{
|
||||
return static_cast<bool>(
|
||||
static_cast<std::underlying_type<Flags>::type>(flags) & static_cast<std::underlying_type<Flags>::type>(flag));
|
||||
}
|
||||
} // namespace Bitwise
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Generic callback result used by test impact systems.
|
||||
enum class CallbackResult : bool
|
||||
{
|
||||
Continue,
|
||||
Abort
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
//! Evaluates the specified condition and throws the specified exception with the specified
|
||||
// !message upon failure.
|
||||
#define AZ_TestImpact_Eval(CONDITION, EXCEPTION_TYPE, MSG) \
|
||||
do \
|
||||
{ \
|
||||
static_assert( \
|
||||
AZStd::is_base_of_v<TestImpact::Exception, EXCEPTION_TYPE>, \
|
||||
"TestImpact Eval macro must only be used with TestImpact exceptions"); \
|
||||
if(!(CONDITION)) \
|
||||
{ \
|
||||
throw(EXCEPTION_TYPE(MSG)); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Base class for test impact framework exceptions.
|
||||
//! @note The message passed in to the constructor is copied and thus safe with dynamic strings.
|
||||
class Exception
|
||||
: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit Exception() = default;
|
||||
explicit Exception(const AZStd::string& msg);
|
||||
explicit Exception(const char* msg);
|
||||
const char* what() const noexcept override;
|
||||
|
||||
private:
|
||||
//! Error message detailing the reason for the exception.
|
||||
AZStd::string m_msg;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Wrapper for OS paths relative to a specified parent path.
|
||||
//! @note Mimics path semantics only, makes no guarantees about validity.
|
||||
class FrameworkPath
|
||||
{
|
||||
public:
|
||||
FrameworkPath() = default;
|
||||
//! Creates a path with no parent.
|
||||
explicit FrameworkPath(const AZ::IO::Path& absolutePath);
|
||||
//! Creates a path with an absolute path and path relative to the specified parent path.
|
||||
explicit FrameworkPath(const AZ::IO::Path& absolutePath, const FrameworkPath& relativeTo);
|
||||
|
||||
//! Retrieves the absolute path.
|
||||
const AZ::IO::Path& Absolute() const;
|
||||
//! Retrieves the path relative to the specified parent path.
|
||||
const AZ::IO::Path& Relative() const;
|
||||
|
||||
private:
|
||||
//! The absolute path value.
|
||||
AZ::IO::Path m_absolutePath;
|
||||
//! The path value relative to the specified parent path.
|
||||
AZ::IO::Path m_relativePath;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Artifact produced by the unified diff parsing process representing the file CRUD operations of a given diff.
|
||||
struct ChangeList
|
||||
{
|
||||
AZStd::vector<AZStd::string> m_createdFiles;
|
||||
AZStd::vector<AZStd::string> m_updatedFiles;
|
||||
AZStd::vector<AZStd::string> m_deletedFiles;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Coverage information about a particular line.
|
||||
struct LineCoverage
|
||||
{
|
||||
size_t m_lineNumber = 0; //!< The source line number this covers.
|
||||
size_t m_hitCount = 0; //!< Number of times this line was covered (zero if not covered).
|
||||
};
|
||||
|
||||
//! Coverage information about a particular source file.
|
||||
struct SourceCoverage
|
||||
{
|
||||
AZ::IO::Path m_path; //!< Source file path.
|
||||
AZStd::optional<AZStd::vector<LineCoverage>> m_coverage; //!< Source file line coverage (empty if source level coverage only).
|
||||
};
|
||||
|
||||
//! Coverage information about a particular module (executable, shared library).
|
||||
struct ModuleCoverage
|
||||
{
|
||||
AZ::IO::Path m_path; //!< Module path.
|
||||
AZStd::vector<SourceCoverage> m_sources; //!< Sources of this module that are covered.
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestSuite.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
using TestEnumerationCase = TestCase; //!< Test case for test enumeration artifacts.
|
||||
using TestEnumerationSuite = TestSuite<TestEnumerationCase>; //!< Test suite for test enumeration artifacts.
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestSuite.h>
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Result of a test that was ran.
|
||||
enum class TestRunResult : bool
|
||||
{
|
||||
Failed, //! The given test failed.
|
||||
Passed //! The given test passed.
|
||||
};
|
||||
|
||||
//! Status of test as to whether or not it was ran.
|
||||
enum class TestRunStatus : bool
|
||||
{
|
||||
NotRun, //!< The test was not run (typically because the test run was aborted by the client or runner before the test could run).
|
||||
Run //!< The test was run (see TestRunResult for the result of this test).
|
||||
};
|
||||
|
||||
//! Test case for test run artifacts.
|
||||
struct TestRunCase
|
||||
: public TestCase
|
||||
{
|
||||
AZStd::optional<TestRunResult> m_result;
|
||||
AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds{0}; //! Duration this test took to run.
|
||||
TestRunStatus m_status = TestRunStatus::NotRun;
|
||||
};
|
||||
|
||||
//! Test suite for test run artifacts.
|
||||
struct TestRunSuite
|
||||
: public TestSuite<TestRunCase>
|
||||
{
|
||||
AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds{0}; //!< Duration this test suite took to run all of its tests.
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Artifact describing basic information about a test case.
|
||||
struct TestCase
|
||||
{
|
||||
AZStd::string m_name;
|
||||
bool m_enabled = false;
|
||||
};
|
||||
|
||||
//! Artifact describing basic information about a test suite.
|
||||
template<typename Test>
|
||||
struct TestSuite
|
||||
{
|
||||
AZStd::string m_name;
|
||||
bool m_enabled = false;
|
||||
AZStd::vector<Test> m_tests;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactBuildTargetDescriptorFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent JSON node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"target",
|
||||
"name",
|
||||
"output_name",
|
||||
"path",
|
||||
"sources",
|
||||
"static",
|
||||
"input",
|
||||
"output"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TargetKey,
|
||||
NameKey,
|
||||
OutputNameKey,
|
||||
PathKey,
|
||||
SourcesKey,
|
||||
StaticKey,
|
||||
InputKey,
|
||||
OutputKey
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
AutogenSources PairAutogenSources(
|
||||
const AZStd::vector<AZ::IO::Path>& inputSources,
|
||||
const AZStd::vector<AZ::IO::Path>& outputSources,
|
||||
const AZStd::string& autogenMatcher)
|
||||
{
|
||||
AutogenSources autogenSources;
|
||||
const auto matcherPattern = AZStd::regex(autogenMatcher);
|
||||
AZStd::smatch inputMatches, outputMatches;
|
||||
|
||||
// This has the potential to be optimized to O(n(n-1)/2) time complexity but to be perfectly honest it's not a serious
|
||||
// bottleneck right now and easier gains would be achieved by constructing build target artifacts in parallel rather than
|
||||
// trying to squeeze any more juice here as each build target is independent of one and other with no shared memory
|
||||
for (const auto& input : inputSources)
|
||||
{
|
||||
AutogenPairs autogenPairs;
|
||||
autogenPairs.m_input = input.String();
|
||||
const AZStd::string inputString = input.Stem().Native();
|
||||
if (AZStd::regex_search(inputString, inputMatches, matcherPattern))
|
||||
{
|
||||
for (const auto& output : outputSources)
|
||||
{
|
||||
const AZStd::string outputString = output.Stem().Native();
|
||||
if (AZStd::regex_search(outputString, outputMatches, matcherPattern))
|
||||
{
|
||||
// Note: [0] contains the whole match, [1] contains the first capture group
|
||||
const auto& inputMatch = inputMatches[1];
|
||||
const auto& outputMatch = outputMatches[1];
|
||||
if (inputMatch == outputMatch)
|
||||
{
|
||||
autogenPairs.m_outputs.emplace_back(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!autogenPairs.m_outputs.empty())
|
||||
{
|
||||
autogenSources.emplace_back(AZStd::move(autogenPairs));
|
||||
}
|
||||
}
|
||||
|
||||
return autogenSources;
|
||||
}
|
||||
|
||||
BuildTargetDescriptor BuildTargetDescriptorFactory(
|
||||
const AZStd::string& buildTargetData,
|
||||
const AZStd::vector<AZStd::string>& staticSourceExtensionExcludes,
|
||||
const AZStd::vector<AZStd::string>& autogenInputExtensionExcludes,
|
||||
const AZStd::string& autogenMatcher)
|
||||
{
|
||||
AZ_TestImpact_Eval(!autogenMatcher.empty(), ArtifactException, "Autogen matcher cannot be empty");
|
||||
|
||||
BuildTargetDescriptor buildTargetDescriptor;
|
||||
rapidjson::Document buildTarget;
|
||||
|
||||
if (buildTarget.Parse(buildTargetData.c_str()).HasParseError())
|
||||
{
|
||||
throw TestImpact::ArtifactException("Could not parse build target data");
|
||||
}
|
||||
|
||||
const auto& target = buildTarget[Keys[TargetKey]];
|
||||
buildTargetDescriptor.m_buildMetaData.m_name = target[Keys[NameKey]].GetString();
|
||||
buildTargetDescriptor.m_buildMetaData.m_outputName = target[Keys[OutputNameKey]].GetString();
|
||||
buildTargetDescriptor.m_buildMetaData.m_path = target["path"].GetString();
|
||||
|
||||
AZ_TestImpact_Eval(!buildTargetDescriptor.m_buildMetaData.m_name.empty(), ArtifactException, "Target name cannot be empty");
|
||||
AZ_TestImpact_Eval(
|
||||
!buildTargetDescriptor.m_buildMetaData.m_outputName.empty(), ArtifactException, "Target output name cannot be empty");
|
||||
AZ_TestImpact_Eval(!buildTargetDescriptor.m_buildMetaData.m_path.empty(), ArtifactException, "Target path cannot be empty");
|
||||
|
||||
const auto& sources = buildTarget[Keys[SourcesKey]];
|
||||
const auto& staticSources = sources[Keys[StaticKey]].GetArray();
|
||||
if (!staticSources.Empty())
|
||||
{
|
||||
buildTargetDescriptor.m_sources.m_staticSources = AZStd::vector<AZStd::string>();
|
||||
|
||||
for (const auto& source : staticSources)
|
||||
{
|
||||
const AZ::IO::Path sourcePath = AZ::IO::Path(source.GetString());
|
||||
if (AZStd::find(
|
||||
staticSourceExtensionExcludes.begin(), staticSourceExtensionExcludes.end(), sourcePath.Extension().Native()) ==
|
||||
staticSourceExtensionExcludes.end())
|
||||
{
|
||||
buildTargetDescriptor.m_sources.m_staticSources.emplace_back(AZStd::move(sourcePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto& inputSources = buildTarget[Keys[SourcesKey]][Keys[InputKey]].GetArray();
|
||||
const auto& outputSources = buildTarget[Keys[SourcesKey]][Keys[OutputKey]].GetArray();
|
||||
if (!inputSources.Empty() || !outputSources.Empty())
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!inputSources.Empty() && !outputSources.Empty(), ArtifactException, "Autogen malformed, input or output sources are empty");
|
||||
|
||||
AZStd::vector<AZ::IO::Path> inputPaths;
|
||||
AZStd::vector<AZ::IO::Path> outputPaths;
|
||||
inputPaths.reserve(inputSources.Size());
|
||||
outputPaths.reserve(outputSources.Size());
|
||||
|
||||
for (const auto& source : inputSources)
|
||||
{
|
||||
const AZ::IO::Path sourcePath = AZ::IO::Path(source.GetString());
|
||||
if (AZStd::find(
|
||||
autogenInputExtensionExcludes.begin(), autogenInputExtensionExcludes.end(), sourcePath.Extension().Native()) ==
|
||||
autogenInputExtensionExcludes.end())
|
||||
{
|
||||
inputPaths.emplace_back(AZStd::move(sourcePath));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& source : outputSources)
|
||||
{
|
||||
outputPaths.emplace_back(AZStd::move(AZ::IO::Path(source.GetString())));
|
||||
}
|
||||
|
||||
buildTargetDescriptor.m_sources.m_autogenSources = PairAutogenSources(inputPaths, outputPaths, autogenMatcher);
|
||||
}
|
||||
|
||||
return buildTargetDescriptor;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactBuildTargetDescriptor.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Constructs a build target artifact from the specified build target data.
|
||||
//! @param buildTargetData The raw build target data in JSON format.
|
||||
//! @param staticSourceExcludes The list of file extensions to exclude for static sources.
|
||||
//! @param autogenInputExtentsionExcludes The list of file extensions to exclude for autogen input sources.
|
||||
//! @param autogenMatcher The regex pattern used to match autogen input filenames with output filenames.
|
||||
//! @return The constructed build target artifact.
|
||||
BuildTargetDescriptor BuildTargetDescriptorFactory(
|
||||
const AZStd::string& buildTargetData,
|
||||
const AZStd::vector<AZStd::string>& staticSourceExtentsionExcludes,
|
||||
const AZStd::vector<AZStd::string>& autogenInputExtentsionExcludes,
|
||||
const AZStd::string& autogenMatcher);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactChangeListFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
template<typename C>
|
||||
auto split(C&& str, const AZStd::string& delimiter)
|
||||
{
|
||||
AZStd::vector<C> strings;
|
||||
|
||||
for (auto p = str.data(), end = p + str.length(); p != end; p += ((p == end) ? 0 : delimiter.length()))
|
||||
{
|
||||
const auto pre = p;
|
||||
p = AZStd::search(pre, end, delimiter.cbegin(), delimiter.cend());
|
||||
|
||||
if (p != pre)
|
||||
{
|
||||
strings.emplace_back(pre, p - pre);
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
} // namespace Utils
|
||||
|
||||
namespace UnifiedDiff
|
||||
{
|
||||
class UnifiedDiffParser
|
||||
{
|
||||
public:
|
||||
ChangeList Parse(const AZStd::string& unifiedDiff);
|
||||
|
||||
private:
|
||||
AZStd::optional<AZStd::string_view> GetTargetFile(const AZStd::string_view& targetFile);
|
||||
ChangeList GenerateChangelist(
|
||||
const AZStd::vector<AZStd::optional<AZStd::string_view>>& src,
|
||||
const AZStd::vector<AZStd::optional<AZStd::string_view>>& dst);
|
||||
|
||||
const AZStd::string m_srcFilePrefix = "--- ";
|
||||
const AZStd::string m_dstFilePrefix = "+++ ";
|
||||
const AZStd::string m_gitTargetPrefix = "b/";
|
||||
const AZStd::string m_perforceTargetPrefix = "/b/";
|
||||
const AZStd::string m_renameFromPrefix = "rename from ";
|
||||
const AZStd::string m_renameToPrefix = "rename to ";
|
||||
const AZStd::string m_nullFile = "/dev/null";
|
||||
bool m_hasGitHeader = false;
|
||||
};
|
||||
|
||||
AZStd::optional<AZStd::string_view> UnifiedDiffParser::GetTargetFile(const AZStd::string_view& targetFile)
|
||||
{
|
||||
size_t startIndex = 0;
|
||||
|
||||
if (targetFile.starts_with(m_renameFromPrefix))
|
||||
{
|
||||
startIndex = m_renameFromPrefix.length();
|
||||
}
|
||||
else if (targetFile.starts_with(m_renameToPrefix))
|
||||
{
|
||||
startIndex = m_renameToPrefix.length();
|
||||
}
|
||||
else if (targetFile.find(m_nullFile) != AZStd::string::npos)
|
||||
{
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex = m_hasGitHeader ? m_gitTargetPrefix.size() + m_dstFilePrefix.size()
|
||||
: m_perforceTargetPrefix.size() + m_dstFilePrefix.size();
|
||||
}
|
||||
|
||||
const auto endIndex = targetFile.find('\t');
|
||||
|
||||
if (endIndex != AZStd::string::npos)
|
||||
{
|
||||
return targetFile.substr(startIndex, endIndex - startIndex);
|
||||
}
|
||||
|
||||
return targetFile.substr(startIndex);
|
||||
}
|
||||
|
||||
ChangeList UnifiedDiffParser::GenerateChangelist(
|
||||
const AZStd::vector<AZStd::optional<AZStd::string_view>>& src, const AZStd::vector<AZStd::optional<AZStd::string_view>>& dst)
|
||||
{
|
||||
AZ_TestImpact_Eval(src.size() == dst.size(), ArtifactException, "Change list source and destination file count mismatch");
|
||||
ChangeList changelist;
|
||||
|
||||
for (size_t i = 0; i < src.size(); i++)
|
||||
{
|
||||
if (!src[i].has_value())
|
||||
{
|
||||
changelist.m_createdFiles.emplace_back(dst[i].value());
|
||||
}
|
||||
else if (!dst[i].has_value())
|
||||
{
|
||||
changelist.m_deletedFiles.emplace_back(src[i].value());
|
||||
}
|
||||
else if (src[i] != dst[i])
|
||||
{
|
||||
changelist.m_deletedFiles.emplace_back(src[i].value());
|
||||
changelist.m_createdFiles.emplace_back(dst[i].value());
|
||||
}
|
||||
else
|
||||
{
|
||||
changelist.m_updatedFiles.emplace_back(src[i].value());
|
||||
}
|
||||
}
|
||||
|
||||
return changelist;
|
||||
}
|
||||
|
||||
ChangeList UnifiedDiffParser::Parse(const AZStd::string& unifiedDiff)
|
||||
{
|
||||
const AZStd::string GitHeader = "diff --git";
|
||||
const auto lines = Utils::split<AZStd::string_view>(unifiedDiff, "\n");
|
||||
|
||||
AZStd::vector<AZStd::optional<AZStd::string_view>> src;
|
||||
AZStd::vector<AZStd::optional<AZStd::string_view>> dst;
|
||||
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
if (line.starts_with(GitHeader))
|
||||
{
|
||||
m_hasGitHeader = true;
|
||||
}
|
||||
else if (line.starts_with(m_srcFilePrefix))
|
||||
{
|
||||
src.emplace_back(GetTargetFile(line));
|
||||
}
|
||||
else if (line.starts_with(m_dstFilePrefix))
|
||||
{
|
||||
dst.emplace_back(GetTargetFile(line));
|
||||
}
|
||||
else if (line.starts_with(m_renameFromPrefix))
|
||||
{
|
||||
src.emplace_back(GetTargetFile(line));
|
||||
}
|
||||
else if (line.starts_with(m_renameToPrefix))
|
||||
{
|
||||
dst.emplace_back(GetTargetFile(line));
|
||||
}
|
||||
}
|
||||
|
||||
return GenerateChangelist(src, dst);
|
||||
}
|
||||
|
||||
ChangeList ChangeListFactory(const AZStd::string& unifiedDiff)
|
||||
{
|
||||
AZ_TestImpact_Eval(!unifiedDiff.empty(), ArtifactException, "Unified diff is empty");
|
||||
UnifiedDiffParser diff;
|
||||
ChangeList changeList = diff.Parse(unifiedDiff);
|
||||
AZ_TestImpact_Eval(
|
||||
!changeList.m_createdFiles.empty() ||
|
||||
!changeList.m_updatedFiles.empty() ||
|
||||
!changeList.m_deletedFiles.empty(),
|
||||
ArtifactException, "The unified diff contained no changes");
|
||||
return changeList;
|
||||
}
|
||||
} // namespace UnifiedDiff
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactChangeList.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace UnifiedDiff
|
||||
{
|
||||
//! Constructs a change list artifact from the specified unified diff data.
|
||||
//! @param unifiedDiffData The raw change list data in unified diff format.
|
||||
//! @return The constructed change list artifact.
|
||||
ChangeList ChangeListFactory(const AZStd::string& unifiedDiffData);
|
||||
} // namespace UnifiedDiff
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactModuleCoverageFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent XML node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"packages",
|
||||
"name",
|
||||
"filename",
|
||||
"coverage",
|
||||
"classes",
|
||||
"lines",
|
||||
"line",
|
||||
"number",
|
||||
"hits",
|
||||
"sources",
|
||||
"source"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PackagesKey,
|
||||
NameKey,
|
||||
FileNameKey,
|
||||
CoverageKey,
|
||||
ClassesKey,
|
||||
LinesKey,
|
||||
LineKey,
|
||||
NumberKey,
|
||||
HitsKey,
|
||||
SourcesKey,
|
||||
SourceKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace Cobertura
|
||||
{
|
||||
// Note: OpenCppCoverage appears to have a very liberal interpretation of the Cobertura coverage file format so consider
|
||||
// this implementation to be provisional and coupled to the Windows platform and OpenCppCoverage tool
|
||||
AZStd::vector<ModuleCoverage> ModuleCoveragesFactory(const AZStd::string& coverageData)
|
||||
{
|
||||
AZ_TestImpact_Eval(!coverageData.empty(), ArtifactException, "Cannot parse coverage, string is empty");
|
||||
AZStd::vector<ModuleCoverage> modules;
|
||||
AZStd::vector<char> rawData(coverageData.begin(), coverageData.end());
|
||||
|
||||
try
|
||||
{
|
||||
AZ::rapidxml::xml_document<> doc;
|
||||
// Parse the XML doc with default flags
|
||||
doc.parse<0>(rawData.data());
|
||||
|
||||
// Coverage
|
||||
const auto coverage_node = doc.first_node(Keys[CoverageKey]);
|
||||
AZ_TestImpact_Eval(coverage_node, ArtifactException, "Could not parse coverage node");
|
||||
|
||||
// Sources
|
||||
const auto sources_node = coverage_node->first_node(Keys[SourcesKey]);
|
||||
if (!sources_node)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Source
|
||||
const auto source_node = sources_node->first_node(Keys[SourceKey]);
|
||||
if (!source_node)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Root drive (this seems to be an unconventional use of the sources section by OpenCppCoverage)
|
||||
const AZStd::string pathRoot = AZStd::string(source_node->value(), source_node->value() + source_node->value_size()) + "\\";
|
||||
|
||||
const auto packages_node = coverage_node->first_node(Keys[PackagesKey]);
|
||||
if (packages_node)
|
||||
{
|
||||
// Modules
|
||||
for (auto package_node = packages_node->first_node(); package_node; package_node = package_node->next_sibling())
|
||||
{
|
||||
// Module
|
||||
ModuleCoverage moduleCoverage;
|
||||
moduleCoverage.m_path = AZ::IO::Path(package_node->first_attribute(Keys[NameKey])->value());
|
||||
|
||||
const auto classes_node = package_node->first_node(Keys[ClassesKey]);
|
||||
if (classes_node)
|
||||
{
|
||||
// Sources
|
||||
for (auto class_node = classes_node->first_node(); class_node; class_node = class_node->next_sibling())
|
||||
{
|
||||
// Source
|
||||
SourceCoverage sourceCoverage;
|
||||
sourceCoverage.m_path = AZ::IO::Path(pathRoot + class_node->first_attribute(Keys[FileNameKey])->value());
|
||||
|
||||
const auto lines_node = class_node->first_node(Keys[LinesKey]);
|
||||
if (lines_node)
|
||||
{
|
||||
AZStd::vector<LineCoverage> lineCoverage;
|
||||
|
||||
// Lines
|
||||
for (auto line_node = lines_node->first_node(); line_node; line_node = line_node->next_sibling())
|
||||
{
|
||||
// Line
|
||||
const size_t number =
|
||||
AZStd::stol(AZStd::string(line_node->first_attribute(Keys[NumberKey])->value()));
|
||||
const size_t hits = AZStd::stol(AZStd::string(line_node->first_attribute(Keys[HitsKey])->value()));
|
||||
lineCoverage.emplace_back(LineCoverage{number, hits});
|
||||
}
|
||||
|
||||
if (!lineCoverage.empty())
|
||||
{
|
||||
sourceCoverage.m_coverage.emplace(AZStd::move(lineCoverage));
|
||||
}
|
||||
}
|
||||
|
||||
moduleCoverage.m_sources.emplace_back(AZStd::move(sourceCoverage));
|
||||
}
|
||||
}
|
||||
|
||||
modules.emplace_back(AZStd::move(moduleCoverage));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
AZ_Error("ModuleCoveragesFactory", false, e.what());
|
||||
throw ArtifactException(e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw ArtifactException("An unknown error occurred parsing the XML data");
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
} // namespace Cobertura
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactCoverage.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace Cobertura
|
||||
{
|
||||
//! Constructs a list of module coverage artifacts from the specified coverage data.
|
||||
//! @param coverageData The raw coverage data in XML format.
|
||||
//! @return The constructed list of module coverage artifacts.
|
||||
AZStd::vector<ModuleCoverage> ModuleCoveragesFactory(const AZStd::string& coverageData);
|
||||
} // namespace Cobertura
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestEnumerationSuiteFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent XML node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"testsuites",
|
||||
"testsuite",
|
||||
"name",
|
||||
"testcase"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TestSuitesKey,
|
||||
TestSuiteKey,
|
||||
NameKey,
|
||||
TestCaseKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace GTest
|
||||
{
|
||||
AZStd::vector<TestEnumerationSuite> TestEnumerationSuitesFactory(const AZStd::string& testEnumerationData)
|
||||
{
|
||||
AZ_TestImpact_Eval(!testEnumerationData.empty(), ArtifactException, "Cannot parse enumeration, string is empty");
|
||||
AZStd::vector<TestEnumerationSuite> testSuites;
|
||||
AZStd::vector<char> rawData(testEnumerationData.begin(), testEnumerationData.end());
|
||||
|
||||
try
|
||||
{
|
||||
AZ::rapidxml::xml_document<> doc;
|
||||
// Parse the XML doc with default flags
|
||||
doc.parse<0>(rawData.data());
|
||||
|
||||
const auto testsuites_node = doc.first_node(Keys[TestSuitesKey]);
|
||||
AZ_TestImpact_Eval(testsuites_node, ArtifactException, "Could not parse enumeration, XML is invalid");
|
||||
for (auto testsuite_node = testsuites_node->first_node(Keys[TestSuiteKey]); testsuite_node;
|
||||
testsuite_node = testsuite_node->next_sibling())
|
||||
{
|
||||
const auto isEnabled = [](const AZStd::string& name)
|
||||
{
|
||||
return !name.starts_with("DISABLED_") && name.find("/DISABLED_") == AZStd::string::npos;
|
||||
};
|
||||
|
||||
TestEnumerationSuite testSuite;
|
||||
testSuite.m_name = testsuite_node->first_attribute(Keys[NameKey])->value();
|
||||
testSuite.m_enabled = isEnabled(testSuite.m_name);
|
||||
|
||||
for (auto testcase_node = testsuite_node->first_node(Keys[TestCaseKey]); testcase_node;
|
||||
testcase_node = testcase_node->next_sibling())
|
||||
{
|
||||
TestEnumerationCase testCase;
|
||||
testCase.m_name = testcase_node->first_attribute(Keys[NameKey])->value();
|
||||
testCase.m_enabled = isEnabled(testCase.m_name);
|
||||
testSuite.m_tests.emplace_back(AZStd::move(testCase));
|
||||
}
|
||||
|
||||
testSuites.emplace_back(AZStd::move(testSuite));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
AZ_Error("TestEnumerationSuitesFactory", false, e.what());
|
||||
throw ArtifactException(e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw ArtifactException("An unknown error occured parsing the XML data");
|
||||
}
|
||||
|
||||
return testSuites;
|
||||
}
|
||||
} // namespace GTest
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestEnumerationSuite.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace GTest
|
||||
{
|
||||
//! Constructs a list of test enumeration suite artifacts from the specified test enumeraion data.
|
||||
//! @param testEnumerationData The raw test enumeration data in XML format.
|
||||
//! @return The constructed list of test enumeration suite artifacts.
|
||||
AZStd::vector<TestEnumerationSuite> TestEnumerationSuitesFactory(const AZStd::string& testEnumerationData);
|
||||
} // namespace GTest
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestRunSuiteFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent XML node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"testsuites",
|
||||
"testsuite",
|
||||
"name",
|
||||
"testcase",
|
||||
"status",
|
||||
"run",
|
||||
"notrun",
|
||||
"time"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TestSuitesKey,
|
||||
TestSuiteKey,
|
||||
NameKey,
|
||||
TestCaseKey,
|
||||
StatusKey,
|
||||
RunKey,
|
||||
NotRunKey,
|
||||
DurationKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace GTest
|
||||
{
|
||||
AZStd::vector<TestRunSuite> TestRunSuitesFactory(const AZStd::string& testEnumerationData)
|
||||
{
|
||||
AZ_TestImpact_Eval(!testEnumerationData.empty(), ArtifactException, "Cannot parse test run, string is empty");
|
||||
AZStd::vector<TestRunSuite> testSuites;
|
||||
AZStd::vector<char> rawData(testEnumerationData.begin(), testEnumerationData.end());
|
||||
|
||||
try
|
||||
{
|
||||
AZ::rapidxml::xml_document<> doc;
|
||||
// Parse the XML doc with default flags
|
||||
doc.parse<0>(rawData.data());
|
||||
|
||||
const auto testsuites_node = doc.first_node(Keys[TestSuitesKey]);
|
||||
AZ_TestImpact_Eval(testsuites_node, ArtifactException, "Could not parse enumeration, XML is invalid");
|
||||
for (auto testsuite_node = testsuites_node->first_node(Keys[TestSuiteKey]); testsuite_node;
|
||||
testsuite_node = testsuite_node->next_sibling())
|
||||
{
|
||||
const auto isEnabled = [](const AZStd::string& name)
|
||||
{
|
||||
return !name.starts_with("DISABLED_") && name.find("/DISABLED_") == AZStd::string::npos;
|
||||
};
|
||||
|
||||
const auto getDuration = [](const AZ::rapidxml::xml_node<>* node)
|
||||
{
|
||||
const AZStd::string duration = node->first_attribute(Keys[DurationKey])->value();
|
||||
return AZStd::chrono::milliseconds(AZStd::stof(duration) * 1000.f);
|
||||
};
|
||||
|
||||
TestRunSuite testSuite;
|
||||
testSuite.m_name = testsuite_node->first_attribute(Keys[NameKey])->value();
|
||||
testSuite.m_enabled = isEnabled(testSuite.m_name);
|
||||
testSuite.m_duration = getDuration(testsuite_node);
|
||||
|
||||
for (auto testcase_node = testsuite_node->first_node(Keys[TestCaseKey]); testcase_node;
|
||||
testcase_node = testcase_node->next_sibling())
|
||||
{
|
||||
const auto getStatus = [](const AZ::rapidxml::xml_node<>* node)
|
||||
{
|
||||
const AZStd::string status = node->first_attribute(Keys[StatusKey])->value();
|
||||
if (status == Keys[RunKey])
|
||||
{
|
||||
return TestRunStatus::Run;
|
||||
}
|
||||
else if (status == Keys[NotRunKey])
|
||||
{
|
||||
return TestRunStatus::NotRun;
|
||||
}
|
||||
|
||||
throw ArtifactException(AZStd::string::format("Unexpected run status: %s", status.c_str()));
|
||||
};
|
||||
|
||||
const auto getResult = [](const AZ::rapidxml::xml_node<>* node)
|
||||
{
|
||||
for (auto child_node = node->first_node("failure"); child_node; child_node = child_node->next_sibling())
|
||||
{
|
||||
return TestRunResult::Failed;
|
||||
}
|
||||
|
||||
return TestRunResult::Passed;
|
||||
};
|
||||
|
||||
TestRunCase testCase;
|
||||
testCase.m_name = testcase_node->first_attribute(Keys[NameKey])->value();
|
||||
testCase.m_enabled = isEnabled(testCase.m_name);
|
||||
testCase.m_duration = getDuration(testcase_node);
|
||||
testCase.m_status = getStatus(testcase_node);
|
||||
|
||||
if (testCase.m_status == TestRunStatus::Run)
|
||||
{
|
||||
testCase.m_result = getResult(testcase_node);
|
||||
}
|
||||
|
||||
testSuite.m_tests.emplace_back(AZStd::move(testCase));
|
||||
}
|
||||
|
||||
testSuites.emplace_back(AZStd::move(testSuite));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
AZ_Error("TestRunSuitesFactory", false, e.what());
|
||||
throw ArtifactException(e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw ArtifactException("An unknown error occurred parsing the XML data");
|
||||
}
|
||||
|
||||
return testSuites;
|
||||
}
|
||||
} // namespace GTest
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestRunSuite.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace GTest
|
||||
{
|
||||
//! Constructs a list of test run suite artifacts from the specified test run data.
|
||||
//! @param testRunData The raw test run data in XML format.
|
||||
//! @return The constructed list of test run suite artifacts.
|
||||
AZStd::vector<TestRunSuite> TestRunSuitesFactory(const AZStd::string& testRunData);
|
||||
} // namespace GTest
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactTestTargetMetaArtifact.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Constructs a list of test target meta-data artifacts from the specified master test list data.
|
||||
//! @param masterTestListData The raw master test list data in JSON format.
|
||||
//! @return The constructed list of test target meta-data artifacts.
|
||||
TestTargetMetas TestTargetMetaMapFactory(const AZStd::string& masterTestListData);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestTargetMetaMapFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent JSON node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"google",
|
||||
"test",
|
||||
"tests",
|
||||
"suite",
|
||||
"launch_method",
|
||||
"test_runner",
|
||||
"stand_alone",
|
||||
"name"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GoogleKey,
|
||||
TestKey,
|
||||
TestsKey,
|
||||
SuiteKey,
|
||||
LaunchMethodKey,
|
||||
TestRunnerKey,
|
||||
StandAloneKey,
|
||||
NameKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TestTargetMetaMap TestTargetMetaMapFactory(const AZStd::string& masterTestListData)
|
||||
{
|
||||
TestTargetMetaMap testMetas;
|
||||
rapidjson::Document masterTestList;
|
||||
|
||||
if (masterTestList.Parse(masterTestListData.c_str()).HasParseError())
|
||||
{
|
||||
throw TestImpact::ArtifactException("Could not parse test meta-data file");
|
||||
}
|
||||
|
||||
const auto tests = masterTestList[Keys[GoogleKey]][Keys[TestKey]][Keys[TestsKey]].GetArray();
|
||||
for (const auto& test : tests)
|
||||
{
|
||||
TestTargetMeta testMeta;
|
||||
testMeta.m_suite = test[Keys[SuiteKey]].GetString();
|
||||
|
||||
if (const auto buildTypeString = test[Keys[LaunchMethodKey]].GetString(); strcmp(buildTypeString, Keys[TestRunnerKey]) == 0)
|
||||
{
|
||||
testMeta.m_launchMethod = LaunchMethod::TestRunner;
|
||||
}
|
||||
else if (strcmp(buildTypeString, Keys[StandAloneKey]) == 0)
|
||||
{
|
||||
testMeta.m_launchMethod = LaunchMethod::StandAlone;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(ArtifactException("Unexpected test build type"));
|
||||
}
|
||||
|
||||
AZStd::string name = test[Keys[NameKey]].GetString();
|
||||
AZ_TestImpact_Eval(!name.empty(), ArtifactException, "Test name field cannot be empty");
|
||||
testMetas.emplace(AZStd::move(name), AZStd::move(testMeta));
|
||||
}
|
||||
|
||||
// If there's no tests in the repo then something is seriously wrong
|
||||
AZ_TestImpact_Eval(!testMetas.empty(), ArtifactException, "No tests were found in the repository");
|
||||
|
||||
return testMetas;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactTestTargetMeta.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Constructs a list of test target meta-data artifacts from the specified master test list data.
|
||||
//! @param masterTestListData The raw master test list data in JSON format.
|
||||
//! @return The constructed list of test target meta-data artifacts.
|
||||
TestTargetMetaMap TestTargetMetaMapFactory(const AZStd::string& masterTestListData);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Static/TestImpactBuildTargetDescriptor.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
BuildTargetDescriptor::BuildTargetDescriptor(BuildMetaData&& buildMetaData, TargetSources&& sources)
|
||||
: m_buildMetaData(AZStd::move(buildMetaData))
|
||||
, m_sources(AZStd::move(sources))
|
||||
{
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Pairing between a given autogen input source and the generated output source(s).
|
||||
struct AutogenPairs
|
||||
{
|
||||
AZStd::string m_input;
|
||||
AZStd::vector<AZStd::string> m_outputs;
|
||||
};
|
||||
|
||||
using AutogenSources = AZStd::vector<AutogenPairs>;
|
||||
|
||||
//! Representation of a given built target's source list.
|
||||
struct TargetSources
|
||||
{
|
||||
AZStd::vector<AZStd::string> m_staticSources; //!< Source files used to build this target (if any).
|
||||
AutogenSources m_autogenSources; //!< Autogen source files (if any).
|
||||
};
|
||||
|
||||
//! Representation of a given build target's basic build infotmation.
|
||||
struct BuildMetaData
|
||||
{
|
||||
AZStd::string m_name; //!< Build target name.
|
||||
AZStd::string m_outputName; //!< Output name (sans extension) of build target binary.
|
||||
AZ::IO::Path m_path; //!< Path to build target location in source tree (relative to repository root).
|
||||
};
|
||||
|
||||
//! Artifact produced by the build system for each build target. Contains source and output information about said targets.
|
||||
struct BuildTargetDescriptor
|
||||
{
|
||||
BuildTargetDescriptor() = default;
|
||||
BuildTargetDescriptor(BuildMetaData&& buildMetaData, TargetSources&& sources);
|
||||
|
||||
BuildMetaData m_buildMetaData;
|
||||
TargetSources m_sources;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Static/TestImpactProductionTargetDescriptor.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
ProductionTargetDescriptor::ProductionTargetDescriptor(BuildTargetDescriptor&& buildTargetDescriptor)
|
||||
: BuildTargetDescriptor(AZStd::move(buildTargetDescriptor))
|
||||
{
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactBuildTargetDescriptor.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Artifact produced by the target artifact compiler that represents a production build target in the repository.
|
||||
struct ProductionTargetDescriptor
|
||||
: public BuildTargetDescriptor
|
||||
{
|
||||
ProductionTargetDescriptor(BuildTargetDescriptor&& buildTarget);
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Static/TestImpactTargetDescriptorCompiler.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
AZStd::tuple<AZStd::vector<ProductionTargetDescriptor>, AZStd::vector<TestTargetDescriptor>> CompileTargetDescriptors(
|
||||
AZStd::vector<BuildTargetDescriptor>&& buildTargets, TestTargetMetaMap&& testTargetMetaMap)
|
||||
{
|
||||
AZ_TestImpact_Eval(!buildTargets.empty(), ArtifactException, "Build target descriptor list cannot be null");
|
||||
AZ_TestImpact_Eval(!testTargetMetaMap.empty(), ArtifactException, "Test target meta map cannot be null");
|
||||
|
||||
AZStd::tuple<AZStd::vector<ProductionTargetDescriptor>, AZStd::vector<TestTargetDescriptor>> outputTargets;
|
||||
auto& [productionTargets, testTargets] = outputTargets;
|
||||
|
||||
for (auto&& buildTarget : buildTargets)
|
||||
{
|
||||
// If this build target has an associated test artifact then it is a test target, otherwise it is a production target
|
||||
if (auto&& testTargetMeta = testTargetMetaMap.find(buildTarget.m_buildMetaData.m_name);
|
||||
testTargetMeta != testTargetMetaMap.end())
|
||||
{
|
||||
testTargets.emplace_back(TestTargetDescriptor(AZStd::move(buildTarget), AZStd::move(testTargetMeta->second)));
|
||||
}
|
||||
else
|
||||
{
|
||||
productionTargets.emplace_back(ProductionTargetDescriptor(AZStd::move(buildTarget)));
|
||||
}
|
||||
}
|
||||
|
||||
return outputTargets;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactProductionTargetDescriptor.h>
|
||||
#include <Artifact/Static/TestImpactTestTargetDescriptor.h>
|
||||
#include <Artifact/Static/TestImpactTestTargetMeta.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Compiles the production target artifacts and test target artifactss from the supplied build target artifacts and test target meta
|
||||
//! map artifact.
|
||||
//! @param buildTargets The list of build target artifacts to be sorted into production and test artifact types.
|
||||
//! @param testTargetMetaMap The map of test target meta artifacts containing the additional meta-data about each test target.
|
||||
//! @return A tuple containing the production artifacts and test artifacts.
|
||||
AZStd::tuple<AZStd::vector<ProductionTargetDescriptor>, AZStd::vector<TestTargetDescriptor>> CompileTargetDescriptors(
|
||||
AZStd::vector<BuildTargetDescriptor>&& buildTargets, TestTargetMetaMap&& testTargetMetaMap);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Static/TestImpactTestTargetDescriptor.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestTargetDescriptor::TestTargetDescriptor(BuildTargetDescriptor&& buildTarget, TestTargetMeta&& testTargetMeta)
|
||||
: BuildTargetDescriptor(AZStd::move(buildTarget))
|
||||
, m_testMetaData(AZStd::move(testTargetMeta))
|
||||
{
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactBuildTargetDescriptor.h>
|
||||
#include <Artifact/Static/TestImpactTestTargetMeta.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Artifact produced by the target artifact compiler that represents a test build target in the repository.
|
||||
struct TestTargetDescriptor
|
||||
: public BuildTargetDescriptor
|
||||
{
|
||||
TestTargetDescriptor(BuildTargetDescriptor&& buildTarget, TestTargetMeta&& testTargetMeta);
|
||||
|
||||
TestTargetMeta m_testMetaData;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Method used to launch the test target.
|
||||
enum class LaunchMethod : bool
|
||||
{
|
||||
TestRunner, //!< Target is launched through a separate test runner binary.
|
||||
StandAlone //!< Target is launched directly by itself.
|
||||
};
|
||||
|
||||
//! Artifact produced by the build system for each test target containing the additional meta-data about the test.
|
||||
struct TestTargetMeta
|
||||
{
|
||||
AZStd::string m_suite;
|
||||
LaunchMethod m_launchMethod = LaunchMethod::TestRunner;
|
||||
};
|
||||
|
||||
//! Map between test target name and test target meta-data.
|
||||
using TestTargetMetaMap = AZStd::unordered_map<AZStd::string, TestTargetMeta>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for artifacts and artifact parsing operations.
|
||||
class ArtifactException
|
||||
: public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
@ -0,0 +1,12 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(LY_COMPILE_OPTIONS PUBLIC -fexceptions)
|
||||
@ -0,0 +1,12 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(LY_COMPILE_OPTIONS PUBLIC /EHsc)
|
||||
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! OS function to cleanup handle
|
||||
using CleanupFunc = BOOL (*)(HANDLE);
|
||||
|
||||
//! RAII wrapper around OS handles.
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
class Handle
|
||||
{
|
||||
public:
|
||||
Handle() = default;
|
||||
explicit Handle(HANDLE handle);
|
||||
~Handle();
|
||||
|
||||
operator HANDLE&();
|
||||
PHANDLE operator&();
|
||||
HANDLE& operator=(HANDLE handle);
|
||||
void Close();
|
||||
|
||||
private:
|
||||
HANDLE m_handle = INVALID_HANDLE_VALUE;
|
||||
};
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
Handle<CleanupFuncT>::Handle(HANDLE handle)
|
||||
: m_handle(handle)
|
||||
{
|
||||
}
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
Handle<CleanupFuncT>::~Handle()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
Handle<CleanupFuncT>::operator HANDLE&()
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
PHANDLE Handle<CleanupFuncT>::operator&()
|
||||
{
|
||||
return &m_handle;
|
||||
}
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
HANDLE& Handle<CleanupFuncT>::operator=(HANDLE handle)
|
||||
{
|
||||
// Setting the handle to INVALID_HANDLE_VALUE will close the handle
|
||||
if (handle == INVALID_HANDLE_VALUE && m_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<CleanupFunc CleanupFuncT>
|
||||
void Handle<CleanupFuncT>::Close()
|
||||
{
|
||||
if (m_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CleanupFuncT(m_handle);
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
using ObjectHandle = Handle<CloseHandle>;
|
||||
using WaitHandle = Handle<UnregisterWait>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactWin32_Pipe.h"
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
Pipe::Pipe(SECURITY_ATTRIBUTES& sa, HANDLE& stdChannel)
|
||||
{
|
||||
if (!CreatePipe(&m_parent, &m_child, &sa, 0))
|
||||
{
|
||||
throw ProcessException("Couldn't create pipe");
|
||||
}
|
||||
|
||||
SetHandleInformation(m_parent, HANDLE_FLAG_INHERIT, 0);
|
||||
stdChannel = m_child;
|
||||
}
|
||||
|
||||
void Pipe::ReleaseChild()
|
||||
{
|
||||
m_child.Close();
|
||||
}
|
||||
|
||||
void Pipe::EmptyPipe()
|
||||
{
|
||||
DWORD bytesAvailable = 0;
|
||||
while (PeekNamedPipe(m_parent, NULL, 0, NULL, &bytesAvailable, NULL) && bytesAvailable > 0)
|
||||
{
|
||||
// Grow the buffer by the number of bytes available in the pipe and append the new data
|
||||
DWORD bytesRead;
|
||||
const size_t currentSize = m_buffer.size();
|
||||
m_buffer.resize(m_buffer.size() + bytesAvailable);
|
||||
if (!ReadFile(m_parent, m_buffer.data() + currentSize, bytesAvailable, &bytesRead, NULL) || bytesRead == 0)
|
||||
{
|
||||
throw ProcessException("Couldn't read child output from pipe");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string Pipe::GetContentsAndClearInternalBuffer()
|
||||
{
|
||||
EmptyPipe();
|
||||
AZStd::string contents;
|
||||
|
||||
if (m_buffer.size() > 0)
|
||||
{
|
||||
contents = AZStd::string(m_buffer.begin(), m_buffer.end());
|
||||
m_buffer.clear();
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TestImpactWin32_Handle.h"
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! RAII wrapper around OS pipes.
|
||||
//! Used to connect the standard output and standard error of the child process to a sink accessible to the
|
||||
//! parent process to allow the parent process to read the output(s) of the child process.
|
||||
class Pipe
|
||||
{
|
||||
public:
|
||||
Pipe(SECURITY_ATTRIBUTES& sa, HANDLE& stdChannel);
|
||||
Pipe(Pipe&& other) = delete;
|
||||
Pipe(Pipe& other) = delete;
|
||||
Pipe& operator=(Pipe& other) = delete;
|
||||
Pipe& operator=(Pipe&& other) = delete;
|
||||
|
||||
//! Releases the child end of the pipe (not needed once parent has their end).
|
||||
void ReleaseChild();
|
||||
|
||||
//! Empties the contents of the pipe into the internal buffer.
|
||||
void EmptyPipe();
|
||||
|
||||
//! Empties the contents of the pipe into a string, clearing the internal buffer.
|
||||
AZStd::string GetContentsAndClearInternalBuffer();
|
||||
|
||||
private:
|
||||
// Parent and child process ends of pipe
|
||||
ObjectHandle m_parent;
|
||||
ObjectHandle m_child;
|
||||
|
||||
// Buffer for emptying pipe upon child processes exit
|
||||
AZStd::vector<char> m_buffer;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactWin32_Process.h"
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
// Note: this is called from an OS thread
|
||||
VOID ProcessWin32::ProcessExitCallback(PVOID processPtr, [[maybe_unused]] BOOLEAN EventSignalled)
|
||||
{
|
||||
// Lock the process destructor from being entered from the client thread
|
||||
AZStd::lock_guard lifeLock(m_lifeCycleMutex);
|
||||
|
||||
ProcessId id = reinterpret_cast<ProcessId>(processPtr);
|
||||
auto process = m_masterProcessList[id];
|
||||
|
||||
// Check that the process hasn't already been destructed from the client thread
|
||||
if (process && process->m_isRunning)
|
||||
{
|
||||
// Lock state access and/or mutation from the client thread
|
||||
AZStd::lock_guard stateLock(process->m_stateMutex);
|
||||
process->RetrieveOSReturnCodeAndCleanUpProcess();
|
||||
}
|
||||
}
|
||||
|
||||
ProcessWin32::ProcessWin32(const ProcessInfo& processInfo)
|
||||
: Process(processInfo)
|
||||
{
|
||||
AZStd::string args(m_processInfo.GetProcessPath().String());
|
||||
|
||||
if (m_processInfo.GetStartupArgs().length())
|
||||
{
|
||||
args = AZStd::string::format("%s %s", args.c_str(), m_processInfo.GetStartupArgs().c_str());
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = nullptr;
|
||||
sa.bInheritHandle = IsPiping();
|
||||
|
||||
STARTUPINFO si;
|
||||
ZeroMemory(&si, sizeof(STARTUPINFO));
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
CreatePipes(sa, si);
|
||||
|
||||
if (!CreateProcess(
|
||||
NULL,
|
||||
&args[0],
|
||||
NULL,
|
||||
NULL,
|
||||
IsPiping(),
|
||||
CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW,
|
||||
NULL, NULL,
|
||||
&si, &pi))
|
||||
{
|
||||
throw ProcessException("Couldn't create process");
|
||||
}
|
||||
|
||||
ReleaseChildPipes();
|
||||
|
||||
m_process = pi.hProcess;
|
||||
m_thread = pi.hThread;
|
||||
m_isRunning = true;
|
||||
|
||||
{
|
||||
// Lock reading of the master process list from the OS thread
|
||||
AZStd::lock_guard lock(m_lifeCycleMutex);
|
||||
|
||||
// Register this process with a unique id in the master process list
|
||||
m_uniqueId = m_uniqueIdCounter++;
|
||||
m_masterProcessList[m_uniqueId] = this;
|
||||
}
|
||||
|
||||
// Register the process exit signal callback
|
||||
if (!RegisterWaitForSingleObject(
|
||||
&m_waitCallback,
|
||||
pi.hProcess,
|
||||
ProcessExitCallback,
|
||||
reinterpret_cast<PVOID>(m_uniqueId),
|
||||
INFINITE,
|
||||
WT_EXECUTEONLYONCE))
|
||||
{
|
||||
throw ProcessException("Couldn't register wait object for process exit event");
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessWin32::IsPiping() const
|
||||
{
|
||||
return m_processInfo.ParentHasStdOutput() || m_processInfo.ParentHasStdError();
|
||||
}
|
||||
|
||||
void ProcessWin32::CreatePipes(SECURITY_ATTRIBUTES& sa, STARTUPINFO& si)
|
||||
{
|
||||
if (IsPiping())
|
||||
{
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
if (m_processInfo.ParentHasStdOutput())
|
||||
{
|
||||
m_stdOutPipe.emplace(sa, si.hStdOutput);
|
||||
}
|
||||
|
||||
if (m_processInfo.ParentHasStdError())
|
||||
{
|
||||
m_stdErrPipe.emplace(sa, si.hStdError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessWin32::ReleaseChildPipes()
|
||||
{
|
||||
if (m_stdOutPipe)
|
||||
{
|
||||
m_stdOutPipe->ReleaseChild();
|
||||
}
|
||||
|
||||
if (m_stdErrPipe)
|
||||
{
|
||||
m_stdErrPipe->ReleaseChild();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessWin32::EmptyPipes()
|
||||
{
|
||||
if (m_stdOutPipe)
|
||||
{
|
||||
m_stdOutPipe->EmptyPipe();
|
||||
}
|
||||
|
||||
if (m_stdErrPipe)
|
||||
{
|
||||
m_stdErrPipe->EmptyPipe();
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::string> ProcessWin32::ConsumeStdOut()
|
||||
{
|
||||
if (m_stdOutPipe)
|
||||
{
|
||||
AZStd::string contents = m_stdOutPipe->GetContentsAndClearInternalBuffer();
|
||||
if (!contents.empty())
|
||||
{
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::string> ProcessWin32::ConsumeStdErr()
|
||||
{
|
||||
if (m_stdErrPipe)
|
||||
{
|
||||
AZStd::string contents = m_stdErrPipe->GetContentsAndClearInternalBuffer();
|
||||
if (!contents.empty())
|
||||
{
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
void ProcessWin32::Terminate(ReturnCode returnCode)
|
||||
{
|
||||
// Lock process cleanup from the OS thread
|
||||
AZStd::lock_guard lock(m_stateMutex);
|
||||
|
||||
if (m_isRunning)
|
||||
{
|
||||
// Cancel the callback so we can wait for the signal ourselves
|
||||
// Note: we keep the state mutex locked as closing the callback is not guaranteed to be instantaneous
|
||||
m_waitCallback.Close();
|
||||
|
||||
// Terminate the process and set the error code to the terminate code
|
||||
TerminateProcess(m_process, returnCode);
|
||||
SetReturnCodeAndCleanUpProcesses(returnCode);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessWin32::IsRunning() const
|
||||
{
|
||||
return m_isRunning;
|
||||
}
|
||||
|
||||
void ProcessWin32::BlockUntilExit()
|
||||
{
|
||||
// Lock process cleanup from the OS thread
|
||||
AZStd::lock_guard lock(m_stateMutex);
|
||||
|
||||
if (m_isRunning)
|
||||
{
|
||||
// Cancel the callback so we can wait for the signal ourselves
|
||||
// Note: we keep the state mutex locked as closing the callback is not guaranteed to be instantaneous
|
||||
m_waitCallback.Close();
|
||||
|
||||
if (IsPiping())
|
||||
{
|
||||
// This process will be blocked from exiting if pipe not emptied so will deadlock if we wait
|
||||
// indefintely whilst there is still output in the pipes so instead keep waiting and checking
|
||||
// if the pipes need emptying until the process exits
|
||||
while (WAIT_OBJECT_0 != WaitForSingleObject(m_process, 1))
|
||||
{
|
||||
EmptyPipes();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No possibility of pipe deadlocking, safe to wait indefinitely for process exit
|
||||
WaitForSingleObject(m_process, INFINITE);
|
||||
}
|
||||
|
||||
// Now that the this process has definately exited we are safe to clean up
|
||||
RetrieveOSReturnCodeAndCleanUpProcess();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessWin32::RetrieveOSReturnCodeAndCleanUpProcess()
|
||||
{
|
||||
DWORD returnCode;
|
||||
GetExitCodeProcess(m_process, &returnCode);
|
||||
SetReturnCodeAndCleanUpProcesses(returnCode);
|
||||
}
|
||||
|
||||
void ProcessWin32::SetReturnCodeAndCleanUpProcesses(ReturnCode returnCode)
|
||||
{
|
||||
m_returnCode = returnCode;
|
||||
m_process.Close();
|
||||
m_thread.Close();
|
||||
m_waitCallback.Close();
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
||||
ProcessWin32::~ProcessWin32()
|
||||
{
|
||||
// Lock the process exit signal callback from being entered OS thread
|
||||
AZStd::lock_guard lock(m_lifeCycleMutex);
|
||||
|
||||
// Remove this process from the master list so the process exit signal doesn't attempt to cleanup
|
||||
// this process if it is deleted client side
|
||||
m_masterProcessList[m_uniqueId] = nullptr;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TestImpactWin32_Handle.h"
|
||||
#include "TestImpactWin32_Pipe.h"
|
||||
|
||||
#include <Process/TestImpactProcess.h>
|
||||
|
||||
#include <AzCore/PlatformIncl.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Platform-specific implementation of Process.
|
||||
class ProcessWin32
|
||||
: public Process
|
||||
{
|
||||
public:
|
||||
explicit ProcessWin32(const ProcessInfo& processInfo);
|
||||
ProcessWin32(ProcessWin32&& other) = delete;
|
||||
ProcessWin32(ProcessWin32& other) = delete;
|
||||
ProcessWin32& operator=(ProcessWin32& other) = delete;
|
||||
ProcessWin32& operator=(ProcessWin32&& other) = delete;
|
||||
~ProcessWin32();
|
||||
|
||||
// Process overrides...
|
||||
void Terminate(ReturnCode returnCode) override;
|
||||
void BlockUntilExit() override;
|
||||
bool IsRunning() const override;
|
||||
AZStd::optional<AZStd::string> ConsumeStdOut() override;
|
||||
AZStd::optional<AZStd::string> ConsumeStdErr() override;
|
||||
|
||||
private:
|
||||
//! Callback for process exit signal.
|
||||
static VOID ProcessExitCallback(PVOID processPtr, BOOLEAN EventSignalled);
|
||||
|
||||
//! Retrieves the return code and cleans up the OS handles.
|
||||
void RetrieveOSReturnCodeAndCleanUpProcess();
|
||||
|
||||
//! Sets the return code and cleans up the OS handles
|
||||
void SetReturnCodeAndCleanUpProcesses(ReturnCode returnCode);
|
||||
|
||||
//! Returns true if either stdout or stderr is beign redirected.
|
||||
bool IsPiping() const;
|
||||
|
||||
//! Creates the parent and child pipes for stdout and/or stderr.
|
||||
void CreatePipes(SECURITY_ATTRIBUTES& sa, STARTUPINFO& si);
|
||||
|
||||
//! Empties all pipes so the process can exit without deadlocking.
|
||||
void EmptyPipes();
|
||||
|
||||
//! Releases the child end of the stdout and/or stderr pipes/
|
||||
void ReleaseChildPipes();
|
||||
|
||||
// Flag to determine whether or not the process is in flight
|
||||
AZStd::atomic_bool m_isRunning = false;
|
||||
|
||||
// Unique id assigned to this process (not the same as the id assigned by the client in the ProcessInfo class)
|
||||
// as used in the master process list
|
||||
size_t m_uniqueId = 0;
|
||||
|
||||
// Handles to OS process
|
||||
ObjectHandle m_process;
|
||||
ObjectHandle m_thread;
|
||||
|
||||
// Handle to process exit signal callback
|
||||
WaitHandle m_waitCallback;
|
||||
|
||||
// Process to parent standard output piping
|
||||
AZStd::optional<Pipe> m_stdOutPipe;
|
||||
AZStd::optional<Pipe> m_stdErrPipe;
|
||||
|
||||
// Mutex protecting process state access/mutation from the OS thread and client thread
|
||||
mutable AZStd::mutex m_stateMutex;
|
||||
|
||||
// Mutex keeping the process life cycles in sync between the OS thread and client thread
|
||||
inline static AZStd::mutex m_lifeCycleMutex;
|
||||
|
||||
// Unique counter to give each launched process a unique id
|
||||
inline static size_t m_uniqueIdCounter = 1;
|
||||
|
||||
// Master process list used to ensure consistency of process lifecycles between OS thread and client thread
|
||||
inline static std::unordered_map<ProcessId, ProcessWin32*> m_masterProcessList;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactWin32_Process.h"
|
||||
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessLauncher.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
AZStd::unique_ptr<Process> LaunchProcess(const ProcessInfo& processInfo)
|
||||
{
|
||||
return AZStd::make_unique<ProcessWin32>(processInfo);
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/JobRunner/TestImpactProcessJobInfo.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Result of a job that was run.
|
||||
enum class JobResult
|
||||
{
|
||||
NotExecuted, //!< The job was not executed (e.g. the job runner terminated before the job could be executed).
|
||||
FailedToExecute, //!< The job failed to execute (e.g. due to the arguments used to execute the job being invalid).
|
||||
Terminated, //!< The job was terminated by the job runner (e.g. job or runner timeout exceeded while job was in-flight).
|
||||
ExecutedWithFailure, //!< The job was executed but exited in an erroneous state (the underlying process returned non-zero).
|
||||
ExecutedWithSuccess //!< The job was executed and exited in a successful state (the underlying processes returned zero).
|
||||
};
|
||||
|
||||
//! The meta-data for a given job.
|
||||
struct JobMeta
|
||||
{
|
||||
JobResult m_result = JobResult::NotExecuted;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point>
|
||||
m_startTime; //!< The time, relative to the job runner start, that this job started.
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_duration; //!< The duration that this job took to complete.
|
||||
AZStd::optional<ReturnCode> m_returnCode; //!< The return code of the underlying processes of this job.
|
||||
};
|
||||
|
||||
//! Representation of a unit of work to be performed by a process.
|
||||
//! @tparam JobInfoT The JobInfo structure containing the information required to run this job.
|
||||
//! @tparam JobPayloadT The resulting output of the processed artifact produced by this job.
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
class Job
|
||||
{
|
||||
public:
|
||||
using Info = JobInfoT;
|
||||
using Payload = JobPayloadT;
|
||||
|
||||
//! Constructor with r-values for the specific use case of the job runner.
|
||||
Job(Info jobInfo, JobMeta&& jobMeta, AZStd::optional<Payload>&& payload);
|
||||
|
||||
//! Returns the job info associated with this job.
|
||||
const Info& GetJobInfo() const;
|
||||
|
||||
//! Returns the result of this job.
|
||||
JobResult GetResult() const;
|
||||
|
||||
//! Returns the start time, relative to the job runner start, that this job started.
|
||||
AZStd::chrono::high_resolution_clock::time_point GetStartTime() const;
|
||||
|
||||
//! Returns the end time, relative to the job runner start, that this job ended.
|
||||
AZStd::chrono::high_resolution_clock::time_point GetEndTime() const;
|
||||
|
||||
//! Returns the duration that this job took to complete.
|
||||
AZStd::chrono::milliseconds GetDuration() const;
|
||||
|
||||
//! Returns the return code of the underlying processes of this job.
|
||||
AZStd::optional<ReturnCode> GetReturnCode() const;
|
||||
|
||||
//! Returns the payload produced by this job.
|
||||
const AZStd::optional<Payload>& GetPayload() const;
|
||||
|
||||
private:
|
||||
Info m_jobInfo;
|
||||
JobMeta m_meta;
|
||||
AZStd::optional<Payload> m_payload;
|
||||
};
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
Job<JobInfoT, JobPayloadT>::Job(Info jobInfo, JobMeta&& jobMeta, AZStd::optional<Payload>&& payload)
|
||||
: m_jobInfo(jobInfo)
|
||||
, m_meta(AZStd::move(jobMeta))
|
||||
, m_payload(AZStd::move(payload))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
const JobInfoT& Job<JobInfoT, JobPayloadT>::GetJobInfo() const
|
||||
{
|
||||
return m_jobInfo;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
JobResult Job<JobInfoT, JobPayloadT>::GetResult() const
|
||||
{
|
||||
return m_meta.m_result;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::optional<ReturnCode> Job<JobInfoT, JobPayloadT>::GetReturnCode() const
|
||||
{
|
||||
return m_meta.m_returnCode;
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::high_resolution_clock::time_point Job<JobInfoT, JobPayloadT>::GetStartTime() const
|
||||
{
|
||||
return m_meta.m_startTime.value_or(AZStd::chrono::high_resolution_clock::time_point());
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::high_resolution_clock::time_point Job<JobInfoT, JobPayloadT>::GetEndTime() const
|
||||
{
|
||||
if (m_meta.m_startTime.has_value() && m_meta.m_duration.has_value())
|
||||
{
|
||||
return m_meta.m_startTime.value() + m_meta.m_duration.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZStd::chrono::high_resolution_clock::time_point();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
AZStd::chrono::milliseconds Job<JobInfoT, JobPayloadT>::GetDuration() const
|
||||
{
|
||||
return m_meta.m_duration.value_or(AZStd::chrono::milliseconds{0});
|
||||
}
|
||||
|
||||
template<typename JobInfoT, typename JobPayloadT>
|
||||
const AZStd::optional<JobPayloadT>& Job<JobInfoT, JobPayloadT>::GetPayload() const
|
||||
{
|
||||
return m_payload;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Per-job information to configure and run jobs and process the resulting artifacts.
|
||||
//! @tparam AdditionalInfo Additional information to be provided to each job to be consumed by client.
|
||||
template<typename AdditionalInfo>
|
||||
class JobInfo
|
||||
: public AdditionalInfo
|
||||
{
|
||||
public:
|
||||
using IdType = size_t;
|
||||
|
||||
//! Client-provided identifier to distinguish between different jobs.
|
||||
//! @note Ids of different job types are not interchangeable.
|
||||
struct Id
|
||||
{
|
||||
IdType m_value;
|
||||
};
|
||||
|
||||
//! Constructs the job information with any additional information required by the job.
|
||||
//! @param jobId The client-provided unique identifier for the job.
|
||||
//! @param args The arguments used to launch the process running the job.
|
||||
//! @param additionalInfo The arguments to be provided to the additional information data structure.
|
||||
template<typename... AdditionalInfoArgs>
|
||||
JobInfo(Id jobId, const AZStd::string& args, AdditionalInfoArgs&&... additionalInfo);
|
||||
|
||||
//! Returns the id of this job.
|
||||
Id GetId() const;
|
||||
|
||||
//! Returns the command arguments used to execute this job.
|
||||
const AZStd::string& GetArgs() const;
|
||||
|
||||
private:
|
||||
Id m_id;
|
||||
AZStd::string m_args;
|
||||
};
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
template<typename... AdditionalInfoArgs>
|
||||
JobInfo<AdditionalInfo>::JobInfo(Id jobId, const AZStd::string& args, AdditionalInfoArgs&&... additionalInfo)
|
||||
: AdditionalInfo{std::forward<AdditionalInfoArgs>(additionalInfo)...}
|
||||
, m_id(jobId)
|
||||
, m_args(args)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
typename JobInfo<AdditionalInfo>::Id JobInfo<AdditionalInfo>::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
template<typename AdditionalInfo>
|
||||
const AZStd::string& JobInfo<AdditionalInfo>::GetArgs() const
|
||||
{
|
||||
return m_args;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/Scheduler/TestImpactProcessScheduler.h>
|
||||
#include <TestImpactFramework/TestImpactCallback.h>
|
||||
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Callback for job completion/failure.
|
||||
//! @param jobInfo The job information associated with this job.
|
||||
//! @param meta The meta-data about the job run.
|
||||
//! @param std The standard output and standard error of the process running the job.
|
||||
template<typename Job>
|
||||
using JobCallback = AZStd::function<CallbackResult(const typename Job::Info& jobInfo, const JobMeta& meta, StdContent&& std)>;
|
||||
|
||||
//! The payloads produced by the job-specific payload producer in the form of a map associating each job id with the job's payload.
|
||||
template<typename Job>
|
||||
using PayloadMap = AZStd::unordered_map<typename Job::Info::IdType, AZStd::optional<typename Job::Payload>>;
|
||||
|
||||
//! The map used by the client to associate the job information and meta-data with the job ids.
|
||||
template<typename Job>
|
||||
using JobDataMap = AZStd::unordered_map<typename Job::Info::IdType, AZStd::pair<JobMeta, const typename Job::Info*>>;
|
||||
|
||||
//! The callback for producing the payloads for the jobs after all jobs have finished executing.
|
||||
//! @param jobInfos The information for each job run.
|
||||
//! @param jobDataMap The job data (in the form of job info and meta-data) for each job run.
|
||||
template<typename Job>
|
||||
using PayloadMapProducer = AZStd::function<PayloadMap<Job>(const JobDataMap<Job>& jobDataMap)>;
|
||||
|
||||
//! Generic job runner that launches a process for each job, records metrics about each job run and hands the payload artifacts
|
||||
//! produced by each job to the client before compositing the metrics and payload artifacts for each job into a single interface
|
||||
//! to be consumed by the client.
|
||||
template<typename JobT>
|
||||
class JobRunner
|
||||
{
|
||||
public:
|
||||
//! Constructs the job runner with the specified parameters to constrain job runs.
|
||||
//! @param stdOutRouting The standard output routing to be specified for all jobs.
|
||||
//! @param stdErrRouting The standard error routing to be specified for all jobs.
|
||||
//! @param maxConcurrentProcesses he maximum number of concurrent jobs in-flight.
|
||||
//! @param processTimeout The maximum duration a job may be in-flight before being forcefully terminated (nullopt if no timeout).
|
||||
//! @param scheduleTimeout The maximum duration the scheduler may run before forcefully terminating all in-flight jobs (nullopt if
|
||||
//! no timeout).
|
||||
JobRunner(
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout);
|
||||
|
||||
//! Executes the specified jobs and returns the products of their labor.
|
||||
//! @note: the job and payload callbacks are specified here rather than in the constructor to allow clients to use capturing lambdas
|
||||
//! should they desire to.
|
||||
//! @param jobs The arguments (and other pertinent information) required for each job to be run.
|
||||
//! @param jobCallback The client callback to be called when each job changes state.
|
||||
//! @param payloadMapProducer The client callback to be called when all jobs have finished to transform the work produced by each
|
||||
//! job into the desired output.
|
||||
AZStd::vector<typename JobT> Execute(
|
||||
const AZStd::vector<typename JobT::Info>& jobs, JobCallback<typename JobT> jobCallback,
|
||||
PayloadMapProducer<JobT> payloadMapProducer);
|
||||
|
||||
private:
|
||||
size_t m_maxConcurrentProcesses = 0; //!< Maximum number of concurrent jobs being executed at a given time.
|
||||
StdOutputRouting m_stdOutRouting; //!< Standard output routing from each job process to job runner.
|
||||
StdErrorRouting m_stdErrRouting; //!< Standard error routing from each job process to job runner
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_jobTimeout; //!< Maximum time a job can run for before being forcefully terminated.
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_runnerTimeout; //!< Maximum time the job runner can run before forcefully terminating all in-flight jobs and shutting down.
|
||||
};
|
||||
|
||||
template<typename JobT>
|
||||
JobRunner<JobT>::JobRunner(
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> jobTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout)
|
||||
: m_maxConcurrentProcesses(maxConcurrentProcesses)
|
||||
, m_stdOutRouting(stdOutRouting)
|
||||
, m_stdErrRouting(stdErrRouting)
|
||||
, m_jobTimeout(jobTimeout)
|
||||
, m_runnerTimeout(runnerTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename JobT>
|
||||
AZStd::vector<JobT> JobRunner<JobT>::Execute(
|
||||
const AZStd::vector<typename JobT::Info>& jobInfos,
|
||||
JobCallback<JobT> jobCallback,
|
||||
PayloadMapProducer<JobT> payloadMapProducer)
|
||||
{
|
||||
AZStd::vector<ProcessInfo> processes;
|
||||
AZStd::unordered_map<JobT::Info::IdType, AZStd::pair<JobMeta, const typename JobT::Info*>> metas;
|
||||
AZStd::vector<JobT> jobs;
|
||||
jobs.reserve(jobInfos.size());
|
||||
processes.reserve(jobInfos.size());
|
||||
|
||||
// Transform the job infos into the underlying process infos required for each job
|
||||
for (size_t jobIndex = 0; jobIndex < jobInfos.size(); jobIndex++)
|
||||
{
|
||||
const auto* jobInfo = &jobInfos[jobIndex];
|
||||
const auto jobId = jobInfo->GetId().m_value;
|
||||
metas.emplace(jobId, AZStd::pair<JobMeta, const typename JobT::Info*>{JobMeta{}, jobInfo});
|
||||
processes.emplace_back(jobId, m_stdOutRouting, m_stdErrRouting, jobInfo->GetArgs());
|
||||
}
|
||||
|
||||
// Wrapper around low-level process launch callback to gather job meta-data and present a simplified callback interface to the client
|
||||
const auto processLaunchCallback = [&jobCallback, &jobInfos, &metas](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)
|
||||
{
|
||||
auto& [meta, jobInfo] = metas.at(pid);
|
||||
if (launchResult == LaunchResult::Failure)
|
||||
{
|
||||
meta.m_result = JobResult::FailedToExecute;
|
||||
return jobCallback(*jobInfo, meta, {});
|
||||
}
|
||||
else
|
||||
{
|
||||
meta.m_startTime = createTime;
|
||||
return CallbackResult::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper around low-level process exit callback to gather job meta-data and present a simplified callback interface to the client
|
||||
const auto processExitCallback = [&jobCallback, &jobInfos, &metas](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::ExitCondition exitCondition,
|
||||
TestImpact::ReturnCode returnCode,
|
||||
TestImpact::StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)
|
||||
{
|
||||
auto& [meta, jobInfo] = metas.at(pid);
|
||||
meta.m_returnCode = returnCode;
|
||||
meta.m_duration = AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(exitTime - *meta.m_startTime);
|
||||
if (exitCondition == ExitCondition::Gracefull && returnCode == 0)
|
||||
{
|
||||
meta.m_result = JobResult::ExecutedWithSuccess;
|
||||
}
|
||||
else if (exitCondition == ExitCondition::Terminated || exitCondition == ExitCondition::Timeout)
|
||||
{
|
||||
meta.m_result = JobResult::Terminated;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta.m_result = JobResult::ExecutedWithFailure;
|
||||
}
|
||||
|
||||
return jobCallback(*jobInfo, meta, AZStd::move(std));
|
||||
};
|
||||
|
||||
// Schedule all jobs for execution
|
||||
ProcessScheduler scheduler(
|
||||
processes,
|
||||
processLaunchCallback,
|
||||
processExitCallback,
|
||||
m_maxConcurrentProcesses,
|
||||
m_jobTimeout,
|
||||
m_runnerTimeout
|
||||
);
|
||||
|
||||
// Hand off the jobs to the client for payload generation
|
||||
auto payloadMap = payloadMapProducer(metas);
|
||||
|
||||
// Unpack the payload map produced by the client into a vector of jobs containing the job data and payload for each job
|
||||
for (const auto& jobInfo : jobInfos)
|
||||
{
|
||||
const auto jobId = jobInfo.GetId().m_value;
|
||||
jobs.emplace_back(JobT(jobInfo, AZStd::move(metas.at(jobId).first), AZStd::move(payloadMap[jobId])));
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/Scheduler/TestImpactProcessScheduler.h>
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
#include <Process/TestImpactProcessLauncher.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
struct ProcessScheduler::ProcessInFlight
|
||||
{
|
||||
AZStd::unique_ptr<Process> m_process;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point> m_startTime;
|
||||
AZStd::string m_stdOutput;
|
||||
AZStd::string m_stdError;
|
||||
};
|
||||
|
||||
ProcessScheduler::ProcessScheduler(
|
||||
const AZStd::vector<ProcessInfo>& processes,
|
||||
const ProcessLaunchCallback& processLaunchCallback,
|
||||
const ProcessExitCallback& processExitCallback,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout)
|
||||
: m_processCreateCallback(processLaunchCallback)
|
||||
, m_processExitCallback(processExitCallback)
|
||||
, m_processTimeout(processTimeout)
|
||||
, m_scheduleTimeout(scheduleTimeout)
|
||||
, m_startTime(AZStd::chrono::high_resolution_clock::now())
|
||||
{
|
||||
AZ_TestImpact_Eval(maxConcurrentProcesses != 0, ProcessException, "Max Number of concurrent processes in flight cannot be 0");
|
||||
AZ_TestImpact_Eval(!processes.empty(), ProcessException, "Number of processes to launch cannot be 0");
|
||||
AZ_TestImpact_Eval(
|
||||
!m_processTimeout.has_value() || m_processTimeout->count() > 0, ProcessException,
|
||||
"Process timeout must be empty or non-zero value");
|
||||
AZ_TestImpact_Eval(
|
||||
!m_scheduleTimeout.has_value() || m_scheduleTimeout->count() > 0, ProcessException,
|
||||
"Scheduler timeout must be empty or non-zero value");
|
||||
|
||||
const size_t numConcurrentProcesses = AZStd::min(processes.size(), maxConcurrentProcesses);
|
||||
m_processPool.resize(numConcurrentProcesses);
|
||||
|
||||
for (const auto& process : processes)
|
||||
{
|
||||
m_processQueue.emplace(process);
|
||||
}
|
||||
|
||||
for (auto& process : m_processPool)
|
||||
{
|
||||
if (PopAndLaunch(process) == CallbackResult::Abort)
|
||||
{
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MonitorProcesses();
|
||||
}
|
||||
|
||||
ProcessScheduler::~ProcessScheduler()
|
||||
{
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
}
|
||||
|
||||
void ProcessScheduler::MonitorProcesses()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Check to see whether or not the scheduling has exceeded its specified runtime
|
||||
if (m_scheduleTimeout.has_value())
|
||||
{
|
||||
const auto shedulerRunTime = AZStd::chrono::milliseconds(AZStd::chrono::high_resolution_clock::now() - m_startTime);
|
||||
|
||||
if (shedulerRunTime > m_scheduleTimeout)
|
||||
{
|
||||
// Runtime exceeded, terminate all proccesses and schedule no further
|
||||
TerminateAllProcesses(ExitCondition::Timeout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Flag to determine whether or not there are currently any processes in-flight
|
||||
bool processesInFlight = false;
|
||||
|
||||
// Loop round the process pool and visit round robin queued up processes for launch
|
||||
for (auto& processInFlight : m_processPool)
|
||||
{
|
||||
if (processInFlight.m_process)
|
||||
{
|
||||
// Process is alive (note: not necessarilly currently running)
|
||||
AccumulateProcessStdContent(processInFlight);
|
||||
const ProcessId processId = processInFlight.m_process->GetProcessInfo().GetId();
|
||||
|
||||
if (!processInFlight.m_process->IsRunning())
|
||||
{
|
||||
// Process has exited of its own accord
|
||||
const ReturnCode returnCode = processInFlight.m_process->GetReturnCode().value();
|
||||
processInFlight.m_process.reset();
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
|
||||
// Inform the client that the processes has exited
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processId,
|
||||
ExitCondition::Gracefull,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else if (!m_processQueue.empty())
|
||||
{
|
||||
// This slot in the pool is free so launch one of the processes waiting in the queue
|
||||
if (PopAndLaunch(processInFlight) == CallbackResult::Abort)
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We know from the above PopAndLaunch there is at least one process in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process is still in-flight
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
const auto runTime = AZStd::chrono::milliseconds(exitTime - processInFlight.m_startTime.value());
|
||||
|
||||
// Check to see whether or not the processes has exceeded its specified flight time
|
||||
if (m_processTimeout.has_value() && runTime > m_processTimeout)
|
||||
{
|
||||
processInFlight.m_process->Terminate(ProcessTimeoutErrorCode);
|
||||
const ReturnCode returnCode = processInFlight.m_process->GetReturnCode().value();
|
||||
processInFlight.m_process.reset();
|
||||
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processId,
|
||||
ExitCondition::Timeout,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Flight time exceeded, terminate this process
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We know that at least this process is in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Queue is empty, no more processes to launch
|
||||
if (!m_processQueue.empty())
|
||||
{
|
||||
if (PopAndLaunch(processInFlight) == CallbackResult::Abort)
|
||||
{
|
||||
// Client chose to abort the scheduler
|
||||
TerminateAllProcesses(ExitCondition::Terminated);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We know from the above PopAndLaunch there is at least one process in-flight this iteration
|
||||
processesInFlight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!processesInFlight)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallbackResult ProcessScheduler::PopAndLaunch(ProcessInFlight& processInFlight)
|
||||
{
|
||||
auto processInfo = m_processQueue.front();
|
||||
m_processQueue.pop();
|
||||
const auto createTime = AZStd::chrono::high_resolution_clock::now();
|
||||
LaunchResult createResult = LaunchResult::Success;
|
||||
|
||||
try
|
||||
{
|
||||
processInFlight.m_process = LaunchProcess(AZStd::move(processInfo));
|
||||
processInFlight.m_startTime = createTime;
|
||||
}
|
||||
catch (ProcessException& e)
|
||||
{
|
||||
AZ_Warning("ProcessScheduler", false, e.what());
|
||||
createResult = LaunchResult::Failure;
|
||||
}
|
||||
|
||||
return m_processCreateCallback(processInfo.GetId(), createResult, createTime);
|
||||
}
|
||||
|
||||
void ProcessScheduler::AccumulateProcessStdContent(ProcessInFlight& processInFlight)
|
||||
{
|
||||
// Accumulate the stdout/stderr so we don't deadlock with the process waiting for the pipe to empty before finishing
|
||||
processInFlight.m_stdOutput += processInFlight.m_process->ConsumeStdOut().value_or("");
|
||||
processInFlight.m_stdError += processInFlight.m_process->ConsumeStdErr().value_or("");
|
||||
}
|
||||
|
||||
StdContent ProcessScheduler::ConsumeProcessStdContent(ProcessInFlight& processInFlight)
|
||||
{
|
||||
return
|
||||
{
|
||||
!processInFlight.m_stdOutput.empty()
|
||||
? AZStd::optional<AZStd::string>{AZStd::move(processInFlight.m_stdOutput)}
|
||||
: AZStd::nullopt,
|
||||
!processInFlight.m_stdError.empty()
|
||||
? AZStd::optional<AZStd::string>{AZStd::move(processInFlight.m_stdError)}
|
||||
: AZStd::nullopt
|
||||
};
|
||||
}
|
||||
|
||||
void ProcessScheduler::TerminateAllProcesses(ExitCondition exitStatus)
|
||||
{
|
||||
bool isCallingBackToClient = true;
|
||||
const ReturnCode returnCode = static_cast<ReturnCode>(exitStatus);
|
||||
|
||||
for (auto& processInFlight : m_processPool)
|
||||
{
|
||||
if (processInFlight.m_process)
|
||||
{
|
||||
processInFlight.m_process->Terminate(ProcessTerminateErrorCode);
|
||||
AccumulateProcessStdContent(processInFlight);
|
||||
const ProcessId processId = processInFlight.m_process->GetProcessInfo().GetId();
|
||||
|
||||
if (isCallingBackToClient)
|
||||
{
|
||||
const auto exitTime = AZStd::chrono::high_resolution_clock::now();
|
||||
if (CallbackResult::Abort == m_processExitCallback(
|
||||
processInFlight.m_process->GetProcessInfo().GetId(),
|
||||
exitStatus,
|
||||
returnCode,
|
||||
ConsumeProcessStdContent(processInFlight),
|
||||
exitTime))
|
||||
{
|
||||
// Client chose to abort the scheduler, do not make any further callbacks
|
||||
isCallingBackToClient = false;
|
||||
}
|
||||
}
|
||||
|
||||
processInFlight.m_process.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <TestImpactFramework/TestImpactCallback.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Result of the attempt to launch a process.
|
||||
enum class LaunchResult : bool
|
||||
{
|
||||
Failure,
|
||||
Success
|
||||
};
|
||||
|
||||
//! The condition under which the processes exited.
|
||||
//! @note For convinience, the terminate and timeout condition values are set to the corresponding return value sent to the
|
||||
//! process.
|
||||
enum class ExitCondition : ReturnCode
|
||||
{
|
||||
Gracefull, //!< Process has exited of its own accord.
|
||||
Terminated = ProcessTerminateErrorCode, //!< The process was terminated by the client/scheduler.
|
||||
Timeout = ProcessTimeoutErrorCode //!< The process was terminated by the scheduler due to exceeding runtime limit.
|
||||
};
|
||||
|
||||
//! Callback for process launch attempt.
|
||||
//! @param processId The id of the process that attempted to launch.
|
||||
//! @param launchResult The result of the process launch attempt.
|
||||
//! @param createTime The timestamp of the process launch attempt.
|
||||
using ProcessLaunchCallback =
|
||||
AZStd::function<CallbackResult(
|
||||
ProcessId processId,
|
||||
LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)>;
|
||||
|
||||
//! Callback for process exit of successfully launched process.
|
||||
//! @param processId The id of the process that attempted to launch.
|
||||
//! @param exitStatus The circumstances upon which the processes exited.
|
||||
//! @param returnCode The return code of the exited process.
|
||||
//! @param std The standard output and standard error of the process.
|
||||
//! @param createTime The timestamp of the process exit.
|
||||
using ProcessExitCallback =
|
||||
AZStd::function<CallbackResult(
|
||||
ProcessId processId,
|
||||
ExitCondition exitStatus,
|
||||
ReturnCode returnCode,
|
||||
StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)>;
|
||||
|
||||
//! Schedules a batch of processes for launch using a round robin approach to distribute the in-flight processes over
|
||||
//! the specified number of concurrent process slots.
|
||||
class ProcessScheduler
|
||||
{
|
||||
public:
|
||||
//! Constructs the scheduler with the specified batch of processes.
|
||||
//! @param processes The batch of processes to schedule.
|
||||
//! @param processLaunchCallback The process launch callback function.
|
||||
//! @param processExitCallback The process exit callback function.
|
||||
//! @param maxConcurrentProcesses The maximum number of concurrent processes in-flight.
|
||||
//! @param processTimeout The maximum duration a process may be in-flight for before being forcefully terminated.
|
||||
//! @param scheduleTimeout The maximum duration the scheduler may run before forcefully terminating all in-flight processes.
|
||||
//! processes and abandoning any queued processes.
|
||||
ProcessScheduler(
|
||||
const AZStd::vector<ProcessInfo>& processes,
|
||||
const ProcessLaunchCallback& processLaunchCallback,
|
||||
const ProcessExitCallback& processExitCallback,
|
||||
size_t maxConcurrentProcesses,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> processTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> scheduleTimeout);
|
||||
|
||||
~ProcessScheduler();
|
||||
|
||||
private:
|
||||
struct ProcessInFlight;
|
||||
|
||||
void MonitorProcesses();
|
||||
CallbackResult PopAndLaunch(ProcessInFlight& processInFlight);
|
||||
void TerminateAllProcesses(ExitCondition exitStatus);
|
||||
StdContent ConsumeProcessStdContent(ProcessInFlight& processInFlight);
|
||||
void AccumulateProcessStdContent(ProcessInFlight& processInFlight);
|
||||
|
||||
const ProcessLaunchCallback m_processCreateCallback;
|
||||
const ProcessExitCallback m_processExitCallback;
|
||||
const AZStd::optional<AZStd::chrono::milliseconds> m_processTimeout;
|
||||
const AZStd::optional<AZStd::chrono::milliseconds> m_scheduleTimeout;
|
||||
const AZStd::chrono::high_resolution_clock::time_point m_startTime;
|
||||
AZStd::vector<ProcessInFlight> m_processPool;
|
||||
AZStd::queue<ProcessInfo> m_processQueue;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
Process::Process(const ProcessInfo& processInfo)
|
||||
: m_processInfo(processInfo)
|
||||
{
|
||||
}
|
||||
|
||||
const ProcessInfo& Process::GetProcessInfo() const
|
||||
{
|
||||
return m_processInfo;
|
||||
}
|
||||
|
||||
AZStd::optional<ReturnCode> Process::GetReturnCode() const
|
||||
{
|
||||
return m_returnCode;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Abstraction of platform-specific process.
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
explicit Process(const ProcessInfo& processInfo);
|
||||
virtual ~Process() = default;
|
||||
|
||||
//! Terminates the process with the specified return code.
|
||||
virtual void Terminate(ReturnCode returnCode) = 0;
|
||||
|
||||
//! Block the calling thread until the process exits.
|
||||
virtual void BlockUntilExit() = 0;
|
||||
|
||||
//! Returns whether or not the process is still running.
|
||||
virtual bool IsRunning() const = 0;
|
||||
|
||||
//! Returns the process info associated with this process.
|
||||
const ProcessInfo& GetProcessInfo() const;
|
||||
|
||||
//! Returns the return code of the exited process.
|
||||
//! Will be empty if the process is still running or was not successfully launched.
|
||||
AZStd::optional<ReturnCode> GetReturnCode() const;
|
||||
|
||||
//! Flushes the internal buffer and returns the process's buffered standard output.
|
||||
//! Subsequent calls will keep returning data so long as the process is producing output.
|
||||
//! Will return nullopt if no output routing or no output produced.
|
||||
virtual AZStd::optional<AZStd::string> ConsumeStdOut() = 0;
|
||||
|
||||
//! Flushes the internal buffer and returns the process's buffered standard error.
|
||||
//! Subsequent calls will keep returning data so long as the process is producing errors.
|
||||
//! Will return nullopt if no error routing or no errors produced.
|
||||
virtual AZStd::optional<AZStd::string> ConsumeStdErr() = 0;
|
||||
|
||||
protected:
|
||||
//! The information used to launch the process.
|
||||
ProcessInfo m_processInfo;
|
||||
|
||||
//! The return code of a successfully launched process (otherwise is empty)
|
||||
AZStd::optional<ReturnCode> m_returnCode;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for processes and process-related operations.
|
||||
class ProcessException
|
||||
: public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
#include <Process/TestImpactProcessInfo.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
ProcessInfo::ProcessInfo(ProcessId id, const AZ::IO::Path& processPath, const AZStd::string& startupArgs)
|
||||
: m_id(id)
|
||||
, m_parentHasStdOutput(false)
|
||||
, m_parentHasStdErr(false)
|
||||
, m_processPath(processPath)
|
||||
, m_startupArgs(startupArgs)
|
||||
{
|
||||
AZ_TestImpact_Eval(processPath.String().length() > 0, ProcessException, "Process path cannot be empty");
|
||||
}
|
||||
|
||||
ProcessInfo::ProcessInfo(
|
||||
ProcessId id,
|
||||
StdOutputRouting stdOut,
|
||||
StdErrorRouting stdErr,
|
||||
const AZ::IO::Path& processPath,
|
||||
const AZStd::string& startupArgs)
|
||||
: m_id(id)
|
||||
, m_processPath(processPath)
|
||||
, m_startupArgs(startupArgs)
|
||||
, m_parentHasStdOutput(stdOut == StdOutputRouting::ToParent ? true : false)
|
||||
, m_parentHasStdErr(stdErr == StdErrorRouting::ToParent ? true : false)
|
||||
{
|
||||
AZ_TestImpact_Eval(processPath.String().length() > 0, ProcessException, "Process path cannot be empty");
|
||||
}
|
||||
|
||||
ProcessId ProcessInfo::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
const AZ::IO::Path& ProcessInfo::GetProcessPath() const
|
||||
{
|
||||
return m_processPath;
|
||||
}
|
||||
|
||||
const AZStd::string& ProcessInfo::GetStartupArgs() const
|
||||
{
|
||||
return m_startupArgs;
|
||||
}
|
||||
|
||||
bool ProcessInfo::ParentHasStdOutput() const
|
||||
{
|
||||
return m_parentHasStdOutput;
|
||||
}
|
||||
|
||||
bool ProcessInfo::ParentHasStdError() const
|
||||
{
|
||||
return m_parentHasStdErr;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Identifier to distinguish between processes.
|
||||
using ProcessId = size_t;
|
||||
|
||||
//! Return code of successfully launched process.
|
||||
using ReturnCode = int;
|
||||
|
||||
//! Error code for processes that are forcefully terminated whilst in-flight by the client.
|
||||
inline constexpr const ReturnCode ProcessTerminateErrorCode = 0xF10BAD;
|
||||
|
||||
//! Error code for processes that are forcefully terminated whilst in-flight by the scheduler due to timing out.
|
||||
inline constexpr const ReturnCode ProcessTimeoutErrorCode = 0xBADF10;
|
||||
|
||||
//! Specifier for how the process's standard out willt be routed
|
||||
enum class StdOutputRouting
|
||||
{
|
||||
ToParent,
|
||||
None
|
||||
};
|
||||
|
||||
enum class StdErrorRouting
|
||||
{
|
||||
ToParent,
|
||||
None
|
||||
};
|
||||
|
||||
//! Container for process standard output and standard error.
|
||||
struct StdContent
|
||||
{
|
||||
AZStd::optional<AZStd::string> m_out;
|
||||
AZStd::optional<AZStd::string> m_err;
|
||||
};
|
||||
|
||||
//! Information about a process the arguments used to launch it.
|
||||
class ProcessInfo
|
||||
{
|
||||
public:
|
||||
//! Provides the information required to launch a process.
|
||||
//! @param processId Client-supplied id to diffrentiate between processes.
|
||||
//! @param stdOut Routing of process standard output.
|
||||
//! @param stdErr Routing of process standard error.
|
||||
//! @param processPath Path to executable binary to launch.
|
||||
//! @param startupArgs Arguments to launch the process with.
|
||||
ProcessInfo(
|
||||
ProcessId processId,
|
||||
StdOutputRouting stdOut,
|
||||
StdErrorRouting stdErr,
|
||||
const AZ::IO::Path& processPath,
|
||||
const AZStd::string& startupArgs = "");
|
||||
ProcessInfo(ProcessId processId, const AZ::IO::Path& processPath, const AZStd::string& startupArgs = "");
|
||||
|
||||
//! Returns the identifier of this process.
|
||||
ProcessId GetId() const;
|
||||
|
||||
//! Returns whether or not stdoutput is routed to the parent process.
|
||||
bool ParentHasStdOutput() const;
|
||||
|
||||
//! Returns whether or not stderror is routed to the parent process.
|
||||
bool ParentHasStdError() const;
|
||||
|
||||
// Returns the path to the process binary.
|
||||
const AZ::IO::Path& GetProcessPath() const;
|
||||
|
||||
//! Returns the command line arguments used to launch the process.
|
||||
const AZStd::string& GetStartupArgs() const;
|
||||
|
||||
private:
|
||||
const ProcessId m_id;
|
||||
const bool m_parentHasStdOutput;
|
||||
const bool m_parentHasStdErr;
|
||||
const AZ::IO::Path m_processPath;
|
||||
const AZStd::string m_startupArgs;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Process/TestImpactProcessException.h>
|
||||
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
class Process;
|
||||
class ProcessInfo;
|
||||
|
||||
//! Attempts to launch a process with the provided command line arguments.
|
||||
//! @param processInfo The path and command line arguments to launch the process with.
|
||||
AZStd::unique_ptr<Process> LaunchProcess(const ProcessInfo& processInfo);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactBuildTarget.h"
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
BuildTarget::BuildTarget(BuildTargetDescriptor&& descriptor, TargetType type)
|
||||
: m_buildMetaData(AZStd::move(descriptor.m_buildMetaData))
|
||||
, m_sources(AZStd::move(descriptor.m_sources))
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
const AZStd::string& BuildTarget::GetName() const
|
||||
{
|
||||
return m_buildMetaData.m_name;
|
||||
}
|
||||
|
||||
const AZStd::string& BuildTarget::GetOutputName() const
|
||||
{
|
||||
return m_buildMetaData.m_outputName;
|
||||
}
|
||||
|
||||
const AZ::IO::Path& BuildTarget::GetPath() const
|
||||
{
|
||||
return m_buildMetaData.m_path;
|
||||
}
|
||||
|
||||
const TargetSources& BuildTarget::GetSources() const
|
||||
{
|
||||
return m_sources;
|
||||
}
|
||||
|
||||
TargetType BuildTarget::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactBuildTargetDescriptor.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Type id for querying specialized derived target types from base pointer/reference.
|
||||
enum class TargetType : bool
|
||||
{
|
||||
Production, //!< Production build target.
|
||||
Test //!< Test build target.
|
||||
};
|
||||
|
||||
//! Representation of a generic build target in the repository.
|
||||
class BuildTarget
|
||||
{
|
||||
public:
|
||||
BuildTarget(BuildTargetDescriptor&& descriptor, TargetType type);
|
||||
virtual ~BuildTarget() = default;
|
||||
|
||||
//! Returns the build target name.
|
||||
const AZStd::string& GetName() const;
|
||||
|
||||
//! Returns the build target's compiled binary name.
|
||||
const AZStd::string& GetOutputName() const;
|
||||
|
||||
//! Returns the path in the source tree to the build target location.
|
||||
const AZ::IO::Path& GetPath() const;
|
||||
|
||||
//! Returns the build target's sources.
|
||||
const TargetSources& GetSources() const;
|
||||
|
||||
//! Returns the build target type.
|
||||
TargetType GetType() const;
|
||||
|
||||
private:
|
||||
BuildMetaData m_buildMetaData;
|
||||
TargetSources m_sources;
|
||||
TargetType m_type;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Target/TestImpactTargetException.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Container for unique set of sorted build target types.
|
||||
//! @tparam Target The specialized build target type.
|
||||
template<typename Target>
|
||||
class BuildTargetList
|
||||
{
|
||||
public:
|
||||
using TargetType = Target;
|
||||
|
||||
BuildTargetList(AZStd::vector<typename Target::Descriptor>&& descriptors);
|
||||
|
||||
//! Returns the targets in the collection.
|
||||
const AZStd::vector<Target>& GetTargets() const;
|
||||
|
||||
//! Returns the target with the specified name.
|
||||
const Target* GetTarget(const AZStd::string& name) const;
|
||||
|
||||
//! Returns the target with the specified name or throws if target not found.
|
||||
const Target* GetTargetOrThrow(const AZStd::string& name) const;
|
||||
|
||||
// Returns the number of targets in the list.
|
||||
size_t GetNumTargets() const;
|
||||
|
||||
private:
|
||||
AZStd::vector<Target> m_targets;
|
||||
};
|
||||
|
||||
template<typename Target>
|
||||
BuildTargetList<Target>::BuildTargetList(AZStd::vector<typename Target::Descriptor>&& descriptors)
|
||||
{
|
||||
AZ_TestImpact_Eval(!descriptors.empty(), TargetException, "Target list is empty");
|
||||
|
||||
AZStd::sort(
|
||||
descriptors.begin(), descriptors.end(), [](const typename Target::Descriptor& lhs, const typename Target::Descriptor& rhs)
|
||||
{
|
||||
return lhs.m_buildMetaData.m_name < rhs.m_buildMetaData.m_name;
|
||||
});
|
||||
|
||||
const auto duplicateElement = AZStd::adjacent_find(
|
||||
descriptors.begin(), descriptors.end(), [](const typename Target::Descriptor& lhs, const typename Target::Descriptor& rhs)
|
||||
{
|
||||
return lhs.m_buildMetaData.m_name == rhs.m_buildMetaData.m_name;
|
||||
});
|
||||
|
||||
AZ_TestImpact_Eval(duplicateElement == descriptors.end(), TargetException, "Target list contains duplicate targets");
|
||||
|
||||
m_targets.reserve(descriptors.size());
|
||||
for (auto&& descriptor : descriptors)
|
||||
{
|
||||
m_targets.emplace_back(Target(AZStd::move(descriptor)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
const AZStd::vector<Target>& BuildTargetList<Target>::GetTargets() const
|
||||
{
|
||||
return m_targets;
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
size_t BuildTargetList<Target>::GetNumTargets() const
|
||||
{
|
||||
return m_targets.size();
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
const Target* BuildTargetList<Target>::GetTarget(const AZStd::string& name) const
|
||||
{
|
||||
struct TargetComparator
|
||||
{
|
||||
bool operator()(const Target& target, const AZStd::string& name) const
|
||||
{
|
||||
return target.GetName() < name;
|
||||
}
|
||||
|
||||
bool operator()(const AZStd::string& name, const Target& target) const
|
||||
{
|
||||
return name < target.GetName();
|
||||
}
|
||||
};
|
||||
|
||||
const auto targetRange = std::equal_range(m_targets.begin(), m_targets.end(), name, TargetComparator{});
|
||||
|
||||
if (targetRange.first != targetRange.second)
|
||||
{
|
||||
return targetRange.first;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Target>
|
||||
const Target* BuildTargetList<Target>::GetTargetOrThrow(const AZStd::string& name) const
|
||||
{
|
||||
const Target* target = GetTarget(name);
|
||||
AZ_TestImpact_Eval(target, TargetException, AZStd::string::format("Couldn't find target %s", name.c_str()).c_str());
|
||||
return target;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactProductionTarget.h"
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
ProductionTarget::ProductionTarget(Descriptor&& descriptor)
|
||||
: BuildTarget(AZStd::move(descriptor), TargetType::Production)
|
||||
{
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactProductionTargetDescriptor.h>
|
||||
#include <Target/TestImpactBuildTarget.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Build target specialization for production targets (build targets containing production code and no test code).
|
||||
class ProductionTarget
|
||||
: public BuildTarget
|
||||
{
|
||||
public:
|
||||
using Descriptor = ProductionTargetDescriptor;
|
||||
ProductionTarget(Descriptor&& descriptor);
|
||||
};
|
||||
|
||||
template<typename Target>
|
||||
inline constexpr bool IsProductionTarget = AZStd::is_same_v<ProductionTarget, AZStd::remove_const_t<AZStd::remove_pointer_t<AZStd::decay_t<Target>>>>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Target/TestImpactBuildTargetList.h>
|
||||
#include <Target/TestImpactProductionTarget.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Container for set of sorted production targets containing no duplicates.
|
||||
using ProductionTargetList = BuildTargetList<ProductionTarget>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for target and target-related operations.
|
||||
class TargetException : public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactTestTarget.h"
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestTarget::TestTarget(Descriptor&& descriptor)
|
||||
: BuildTarget(AZStd::move(descriptor), TargetType::Test)
|
||||
, m_testMetaData(AZStd::move(descriptor.m_testMetaData))
|
||||
{
|
||||
}
|
||||
|
||||
const AZStd::string& TestTarget::GetSuite() const
|
||||
{
|
||||
return m_testMetaData.m_suite;
|
||||
}
|
||||
|
||||
LaunchMethod TestTarget::GetLaunchMethod() const
|
||||
{
|
||||
return m_testMetaData.m_launchMethod;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Static/TestImpactTestTargetDescriptor.h>
|
||||
#include <Target/TestImpactBuildTarget.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Build target specialization for test targets (build targets containing test code and no production code).
|
||||
class TestTarget
|
||||
: public BuildTarget
|
||||
{
|
||||
public:
|
||||
using Descriptor = TestTargetDescriptor;
|
||||
|
||||
TestTarget(Descriptor&& descriptor);
|
||||
|
||||
//! Returns the test target suite.
|
||||
const AZStd::string& GetSuite() const;
|
||||
|
||||
//! Returns the test target launch method.
|
||||
LaunchMethod GetLaunchMethod() const;
|
||||
|
||||
private:
|
||||
const TestTargetMeta m_testMetaData;
|
||||
};
|
||||
|
||||
template<typename Target>
|
||||
inline constexpr bool IsTestTarget = AZStd::is_same_v<TestTarget, AZStd::remove_const_t<AZStd::remove_pointer_t<AZStd::decay_t<Target>>>>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Target/TestImpactBuildTargetList.h>
|
||||
#include <Target/TestImpactTestTarget.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Container for set of sorted test targets containing no duplicates.
|
||||
using TestTargetList = BuildTargetList<TestTarget>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestEnumerationSuite.h>
|
||||
#include <Test/TestImpactTestSuiteContainer.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Representation of a given test target's enumerated tests.
|
||||
using TestEnumeration = TestSuiteContainer<TestEnumerationSuite>;
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for test enumerations and test enumeration related operations.
|
||||
class TestEnumerationException
|
||||
: public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Test/Enumeration/TestImpactTestEnumerationException.h>
|
||||
#include <Test/Enumeration/TestImpactTestEnumerationSerializer.h>
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/JSON/prettywriter.h>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/JSON/stringbuffer.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent JSON node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"suites",
|
||||
"name",
|
||||
"enabled",
|
||||
"tests"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SuitesKey,
|
||||
NameKey,
|
||||
EnabledKey,
|
||||
TestsKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
AZStd::string SerializeTestEnumeration(const TestEnumeration& testEnum)
|
||||
{
|
||||
rapidjson::StringBuffer stringBuffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(stringBuffer);
|
||||
|
||||
writer.StartObject();
|
||||
writer.Key(Keys[SuitesKey]);
|
||||
writer.StartArray();
|
||||
for (const auto& suite : testEnum.GetTestSuites())
|
||||
{
|
||||
writer.StartObject();
|
||||
writer.Key(Keys[NameKey]);
|
||||
writer.String(suite.m_name.c_str());
|
||||
writer.Key(Keys[EnabledKey]);
|
||||
writer.Bool(suite.m_enabled);
|
||||
writer.Key(Keys[TestsKey]);
|
||||
writer.StartArray();
|
||||
for (const auto& test : suite.m_tests)
|
||||
{
|
||||
writer.StartObject();
|
||||
writer.Key(Keys[NameKey]);
|
||||
writer.String(test.m_name.c_str());
|
||||
writer.Key(Keys[EnabledKey]);
|
||||
writer.Bool(test.m_enabled);
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
writer.EndObject();
|
||||
|
||||
return stringBuffer.GetString();
|
||||
}
|
||||
|
||||
TestEnumeration DeserializeTestEnumeration(const AZStd::string& testEnumString)
|
||||
{
|
||||
AZStd::vector<TestEnumerationSuite> testSuites;
|
||||
rapidjson::Document doc;
|
||||
|
||||
if (doc.Parse<0>(testEnumString.c_str()).HasParseError())
|
||||
{
|
||||
throw TestEnumerationException("Could not parse enumeration data");
|
||||
}
|
||||
|
||||
for (const auto& suite : doc[Keys[SuitesKey]].GetArray())
|
||||
{
|
||||
testSuites.emplace_back(TestEnumerationSuite{suite[Keys[NameKey]].GetString(), suite[Keys[EnabledKey]].GetBool(), {}});
|
||||
for (const auto& test : suite[Keys[TestsKey]].GetArray())
|
||||
{
|
||||
testSuites.back().m_tests.emplace_back(
|
||||
TestEnumerationCase{test[Keys[NameKey]].GetString(), test[Keys[EnabledKey]].GetBool()});
|
||||
}
|
||||
}
|
||||
|
||||
return TestEnumeration(std::move(testSuites));
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Test/Enumeration/TestImpactTestEnumeration.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Serializes the specified test enumeration to JSON format.
|
||||
AZStd::string SerializeTestEnumeration(const TestEnumeration& testEnumeration);
|
||||
|
||||
//! Deserializes a test enumeration from the specified test enumeration data in JSON format.
|
||||
TestEnumeration DeserializeTestEnumeration(const AZStd::string& testEnumerationString);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestEnumerationSuiteFactory.h>
|
||||
#include <Test/Enumeration/TestImpactTestEnumerationException.h>
|
||||
#include <Test/Enumeration/TestImpactTestEnumerationSerializer.h>
|
||||
#include <Test/Enumeration/TestImpactTestEnumerator.h>
|
||||
#include <Test/Job/TestImpactTestJobCommon.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void WriteCacheFile(
|
||||
const TestEnumeration& enumeration, const AZ::IO::Path& path, Bitwise::CacheExceptionPolicy cacheExceptionPolicy)
|
||||
{
|
||||
const AZStd::string cacheJSON = SerializeTestEnumeration(enumeration);
|
||||
const AZStd::vector<char> cacheBytes(cacheJSON.begin(), cacheJSON.end());
|
||||
AZ::IO::SystemFile cacheFile;
|
||||
|
||||
if (!cacheFile.Open(
|
||||
path.c_str(),
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY))
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(cacheExceptionPolicy, Bitwise::CacheExceptionPolicy::OnCacheWriteFailure), TestEnumerationException,
|
||||
"Couldn't open cache file for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cacheFile.Write(cacheBytes.data(), cacheBytes.size()) == 0)
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(cacheExceptionPolicy, Bitwise::CacheExceptionPolicy::OnCacheWriteFailure), TestEnumerationException,
|
||||
"Couldn't write cache file data");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::optional<TestEnumeration> ReadCacheFile(const AZ::IO::Path& path, Bitwise::CacheExceptionPolicy cacheExceptionPolicy)
|
||||
{
|
||||
AZ::IO::SystemFile cacheFile;
|
||||
AZStd::string cacheJSON;
|
||||
if (!cacheFile.Open(path.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY))
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(cacheExceptionPolicy, Bitwise::CacheExceptionPolicy::OnCacheNotExist), TestEnumerationException,
|
||||
"Couldn't locate cache file");
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
const AZ::IO::SystemFile::SizeType length = cacheFile.Length();
|
||||
if (length == 0)
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(cacheExceptionPolicy, Bitwise::CacheExceptionPolicy::OnCacheReadFailure), TestEnumerationException,
|
||||
"Cache file is empty");
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
cacheFile.Seek(0, AZ::IO::SystemFile::SF_SEEK_BEGIN);
|
||||
cacheJSON.resize(length);
|
||||
if (cacheFile.Read(length, cacheJSON.data()) != length)
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(cacheExceptionPolicy, Bitwise::CacheExceptionPolicy::OnCacheReadFailure), TestEnumerationException,
|
||||
"Couldn't read cache file");
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
return DeserializeTestEnumeration(cacheJSON);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TestEnumeration ParseTestEnumerationFile(const AZ::IO::Path& enumerationFile)
|
||||
{
|
||||
return TestEnumeration(GTest::TestEnumerationSuitesFactory(ReadFileContents<TestEnumerationException>(enumerationFile)));
|
||||
}
|
||||
|
||||
TestEnumerationJobData::TestEnumerationJobData(const AZ::IO::Path& enumerationArtifact, AZStd::optional<Cache>&& cache)
|
||||
: m_enumerationArtifact(enumerationArtifact)
|
||||
, m_cache(AZStd::move(cache))
|
||||
{
|
||||
}
|
||||
|
||||
const AZ::IO::Path& TestEnumerationJobData::GetEnumerationArtifactPath() const
|
||||
{
|
||||
return m_enumerationArtifact;
|
||||
}
|
||||
|
||||
const AZStd::optional<TestEnumerationJobData::Cache>& TestEnumerationJobData::GetCache() const
|
||||
{
|
||||
return m_cache;
|
||||
}
|
||||
|
||||
TestEnumerator::TestEnumerator(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
size_t maxConcurrentEnumerations,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> enumerationTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> enumeratorTimeout)
|
||||
: JobRunner(clientCallback, AZStd::nullopt, StdOutputRouting::None, StdErrorRouting::None, maxConcurrentEnumerations, enumerationTimeout, enumeratorTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::vector<TestEnumerator::Job> TestEnumerator::Enumerate(
|
||||
const AZStd::vector<JobInfo>& jobInfos,
|
||||
CacheExceptionPolicy cacheExceptionPolicy,
|
||||
JobExceptionPolicy jobExceptionPolicy)
|
||||
{
|
||||
AZStd::vector<Job> cachedJobs;
|
||||
AZStd::vector<JobInfo> jobQueue;
|
||||
|
||||
for (const auto& jobInfo : jobInfos)
|
||||
{
|
||||
// If this job has a cache read policy attempt to read the cache
|
||||
if (jobInfo.GetCache().has_value() && jobInfo.GetCache()->m_policy == JobData::CachePolicy::Read)
|
||||
{
|
||||
JobMeta meta;
|
||||
auto enumeration = ReadCacheFile(jobInfo.GetCache()->m_file, cacheExceptionPolicy);
|
||||
|
||||
// Even though cached jobs don't get executed we still give the client the opportunity to handle the job state
|
||||
// change in order to make the caching process transparent to the client
|
||||
if (enumeration.has_value())
|
||||
{
|
||||
if (m_clientJobCallback.has_value())
|
||||
{
|
||||
(*m_clientJobCallback)(jobInfo, meta);
|
||||
}
|
||||
|
||||
// Cache read successfully, this job will not be placed in the job queue
|
||||
cachedJobs.emplace_back(Job(jobInfo, AZStd::move(meta), AZStd::move(enumeration)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The cache read failed and exception policy for cache read failures is not to throw so instead place this job in the
|
||||
// job queue
|
||||
jobQueue.emplace_back(jobInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This job has no cache read policy so place in job queue
|
||||
jobQueue.emplace_back(jobInfo);
|
||||
}
|
||||
}
|
||||
|
||||
const auto payloadGenerator = [this, cacheExceptionPolicy](const JobDataMap& jobDataMap)
|
||||
{
|
||||
PayloadMap<Job> enumerations;
|
||||
for (const auto& [jobId, jobData] : jobDataMap)
|
||||
{
|
||||
const auto& [meta, jobInfo] = jobData;
|
||||
if (meta.m_result == JobResult::ExecutedWithSuccess)
|
||||
{
|
||||
const auto& enumeration = enumerations[jobId] = ParseTestEnumerationFile(jobInfo->GetEnumerationArtifactPath());
|
||||
|
||||
// Write out the enumeration to a cache file if we have a cache write policy for this job
|
||||
if (jobInfo->GetCache().has_value() && jobInfo->GetCache()->m_policy == JobData::CachePolicy::Write)
|
||||
{
|
||||
WriteCacheFile(enumeration.value(), jobInfo->GetCache()->m_file, cacheExceptionPolicy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return enumerations;
|
||||
};
|
||||
|
||||
// Generate the enumeration results for the jobs that weren't cached
|
||||
auto jobs = ExecuteJobs(jobQueue, payloadGenerator, jobExceptionPolicy);
|
||||
|
||||
// We need to add the cached jobs to the completed job list even though they technically weren't executed
|
||||
for (auto&& job : cachedJobs)
|
||||
{
|
||||
jobs.emplace_back(AZStd::move(job));
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
#include <Test/Enumeration/TestImpactTestEnumeration.h>
|
||||
#include <Test/Job/TestImpactTestJobRunner.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Per-job data for test enumerations.
|
||||
class TestEnumerationJobData
|
||||
{
|
||||
public:
|
||||
//! Policy for how a test enumeration will be written/read from the a previous cache instead of enumerated from the test target.
|
||||
enum class CachePolicy
|
||||
{
|
||||
Read, //!< Do read from a cache file but do not overwrite any existing cache file.
|
||||
Write //!< Do not read from a cache file but instead overwrite any existing cache file.
|
||||
};
|
||||
|
||||
//! Cache configuration for a given test enumeration command.
|
||||
struct Cache
|
||||
{
|
||||
CachePolicy m_policy;
|
||||
AZ::IO::Path m_file;
|
||||
};
|
||||
|
||||
TestEnumerationJobData(const AZ::IO::Path& enumerationArtifact, AZStd::optional<Cache>&& cache);
|
||||
|
||||
//! Returns the path to the enumeration artifact produced by the test target.
|
||||
const AZ::IO::Path& GetEnumerationArtifactPath() const;
|
||||
|
||||
//! Returns the cache details for this job.
|
||||
const AZStd::optional<Cache>& GetCache() const;
|
||||
|
||||
private:
|
||||
AZ::IO::Path m_enumerationArtifact; //!< Path to enumeration artifact to be processed.
|
||||
AZStd::optional<Cache> m_cache = AZStd::nullopt; //!< No caching takes place if cache is empty.
|
||||
};
|
||||
|
||||
namespace Bitwise
|
||||
{
|
||||
//! Exception policy for test enumeration cache reads/writes.
|
||||
enum class CacheExceptionPolicy
|
||||
{
|
||||
Never = 0, //! Never throw.
|
||||
OnCacheNotExist = 1, //! Throw when a cache read policy was in place but a cache file for this job doesn't exist.
|
||||
OnCacheReadFailure = 1 << 1, //! Throw when a cache read policy is in place but the cache file could not be read.
|
||||
OnCacheWriteFailure = 1 << 2 //! Throw when a cache write policy is in place but the cache file could not be written.
|
||||
};
|
||||
} // namespace Bitwise
|
||||
|
||||
//! Enumerate a batch of test targets to determine the test suites and fixtures they contain, caching the results where applicable.
|
||||
class TestEnumerator
|
||||
: public TestJobRunner<TestEnumerationJobData, TestEnumeration>
|
||||
{
|
||||
using JobRunner = TestJobRunner<TestEnumerationJobData, TestEnumeration>;
|
||||
|
||||
public:
|
||||
using CacheExceptionPolicy = Bitwise::CacheExceptionPolicy;
|
||||
|
||||
//! Constructs a test enumerator with the specified parameters common to all enumeration job runs of this enumerator.
|
||||
//! @param clientCallback The optional client callback to be called whenever an enumeration job changes state.
|
||||
//! @param maxConcurrentEnumerations The maximum number of enumerations to be in flight at any given time.
|
||||
//! @param enumerationTimeout The maximum duration an enumeration may be in-flight for before being forcefully terminated.
|
||||
//! @param enumeratorTimeout The maximum duration the enumerator may run before forcefully terminating all in-flight enumerations.
|
||||
TestEnumerator(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
size_t maxConcurrentEnumerations,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> enumerationTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> enumeratorTimeout);
|
||||
|
||||
//! Executes the specified test enumeration jobs according to the specified cache and job exception policies.
|
||||
//! @param jobInfos The enumeration jobs to execute.
|
||||
//! @param cacheExceptionPolicy The cache exception policy to be used for this run.
|
||||
//! @param jobExceptionPolicy The enumeration job exception policy to be used for this run.
|
||||
//! @return the test enumeration jobs with their associated test enumeration payloads.
|
||||
AZStd::vector<Job> Enumerate(
|
||||
const AZStd::vector<JobInfo>& jobInfos, CacheExceptionPolicy cacheExceptionPolicy, JobExceptionPolicy jobExceptionPolicy);
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
template<typename ExceptionType>
|
||||
AZStd::string ReadFileContents(const AZ::IO::Path& file)
|
||||
{
|
||||
static_assert(AZStd::is_base_of<Exception, ExceptionType>::value, "Exception must be a TestImpact exception or derived type");
|
||||
|
||||
const auto fileSize = AZ::IO::SystemFile::Length(file.c_str());
|
||||
AZ_TestImpact_Eval(fileSize > 0, ExceptionType, AZStd::string::format("File %s does not exist", file.c_str()));
|
||||
|
||||
AZStd::vector<char> buffer(fileSize + 1);
|
||||
buffer[fileSize] = '\0';
|
||||
AZ_TestImpact_Eval(AZ::IO::SystemFile::Read(file.c_str(), buffer.data()), ExceptionType, "Could not read file contents");
|
||||
|
||||
return AZStd::string(buffer.begin(), buffer.end());
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for test job related operations.
|
||||
class TestJobException
|
||||
: public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactBitwise.h>
|
||||
|
||||
#include <Process/JobRunner/TestImpactProcessJob.h>
|
||||
#include <Process/JobRunner/TestImpactProcessJobRunner.h>
|
||||
#include <Test/Job/TestImpactTestJobException.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace Bitwise
|
||||
{
|
||||
//! Exception policy for test jobs (and derived jobs).
|
||||
enum class TestJobExceptionPolicy
|
||||
{
|
||||
Never = 0, //!< Never throw.
|
||||
OnFailedToExecute = 1, //!< Throw when a job fails to execute.
|
||||
OnExecutedWithFailure = 1 << 1 //!< Throw when a job returns with an error code.
|
||||
};
|
||||
} // namespace Bitwise
|
||||
|
||||
//! Base class for test related job runners.
|
||||
//! @tparam AdditionalInfo The data structure containing the information additional to the command arguments necessary to execute and
|
||||
//! complete a job.
|
||||
//! @tparam Payload The output produced by a job.
|
||||
template<typename AdditionalInfo, typename Payload>
|
||||
class TestJobRunner
|
||||
{
|
||||
public:
|
||||
using JobData = AdditionalInfo;
|
||||
using JobInfo = JobInfo<AdditionalInfo>;
|
||||
using JobPayload = Payload;
|
||||
using Job = Job<JobInfo, Payload>;
|
||||
using ClientJobCallback = AZStd::function<void(const JobInfo& jobInfo, const JobMeta& meta)>;
|
||||
using DerivedJobCallback = JobCallback<Job>;
|
||||
using JobExceptionPolicy = Bitwise::TestJobExceptionPolicy;
|
||||
using JobDataMap = JobDataMap<Job>;
|
||||
|
||||
//! Constructs the job runner with the specified parameters common to all job runs of this runner.
|
||||
//! @param clientCallback The optional callback function provided by the client to be called upon job state change.
|
||||
//! @param clientCallback The optional callback function provided by the derived job runner to be called upon job state change.
|
||||
//! @param stdOutRouting The standard output routing from the underlying job processes to the derived runner.
|
||||
//! @param stdErrorRouting The standard error routing from the underlying job processes to the derived runner.
|
||||
//! @param maxConcurrentJobs The maximum number of jobs to be in flight at any given time.
|
||||
//! @param jobTimeout The maximum duration a job may be in-flight for before being forcefully terminated (nullopt if no timeout).
|
||||
//! @param runnerTimeout The maximum duration the runner may run before forcefully terminating all in-flight jobs (nullopt if no
|
||||
//! timeout).
|
||||
TestJobRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
AZStd::optional<DerivedJobCallback> derivedJobCallback,
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentJobs,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> jobTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout);
|
||||
|
||||
protected:
|
||||
//! Runs the specified jobs and returns the completed payloads produced by each job.
|
||||
//! @param jobInfos The batch of jobs to execute.
|
||||
//! @param payloadMapProducer The client callback for producing the payload map based on the completed job data.
|
||||
//! @param jobExceptionPolicy The job execution policy for this job run.
|
||||
AZStd::vector<Job> ExecuteJobs(
|
||||
const AZStd::vector<JobInfo>& jobInfos,
|
||||
PayloadMapProducer<Job> payloadMapProducer,
|
||||
JobExceptionPolicy jobExceptionPolicy);
|
||||
|
||||
const AZStd::optional<ClientJobCallback> m_clientJobCallback;
|
||||
|
||||
private:
|
||||
JobRunner<Job> m_jobRunner;
|
||||
const AZStd::optional<DerivedJobCallback> m_derivedJobCallback;
|
||||
};
|
||||
|
||||
template<typename Data, typename Payload>
|
||||
TestJobRunner<Data, Payload>::TestJobRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
AZStd::optional<DerivedJobCallback> derivedJobCallback,
|
||||
StdOutputRouting stdOutRouting,
|
||||
StdErrorRouting stdErrRouting,
|
||||
size_t maxConcurrentJobs,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> jobTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout)
|
||||
: m_jobRunner(stdOutRouting, stdErrRouting, maxConcurrentJobs, jobTimeout, runnerTimeout)
|
||||
, m_clientJobCallback(clientCallback)
|
||||
, m_derivedJobCallback(derivedJobCallback)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Data, typename Payload>
|
||||
AZStd::vector<typename TestJobRunner<Data, Payload>::Job> TestJobRunner<Data, Payload>::ExecuteJobs(
|
||||
const AZStd::vector<JobInfo>& jobInfos,
|
||||
PayloadMapProducer<Job> payloadMapProducer,
|
||||
JobExceptionPolicy jobExceptionPolicy)
|
||||
{
|
||||
// Callback to handle job exception policies and client/derived callbacks
|
||||
const auto jobCallback = [this, &jobExceptionPolicy](const JobInfo& jobInfo, const JobMeta& meta, StdContent&& std)
|
||||
{
|
||||
if (meta.m_result == JobResult::FailedToExecute && IsFlagSet(jobExceptionPolicy, JobExceptionPolicy::OnFailedToExecute))
|
||||
{
|
||||
throw TestJobException("Job failed to execute");
|
||||
}
|
||||
else if (meta.m_result == JobResult::ExecutedWithFailure && IsFlagSet(jobExceptionPolicy, JobExceptionPolicy::OnExecutedWithFailure))
|
||||
{
|
||||
throw TestJobException("Job executed with failure");
|
||||
}
|
||||
|
||||
if (m_derivedJobCallback.has_value())
|
||||
{
|
||||
if (const auto result = (*m_derivedJobCallback)(jobInfo, meta, AZStd::move(std)); result != CallbackResult::Continue)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_clientJobCallback.has_value())
|
||||
{
|
||||
(*m_clientJobCallback)(jobInfo, meta);
|
||||
}
|
||||
|
||||
return CallbackResult::Continue;
|
||||
};
|
||||
|
||||
return m_jobRunner.Execute(jobInfos, jobCallback, payloadMapProducer);
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactModuleCoverageFactory.h>
|
||||
#include <Artifact/Factory/TestImpactTestRunSuiteFactory.h>
|
||||
#include <Test/Job/TestImpactTestJobCommon.h>
|
||||
#include <Test/Run/TestImpactInstrumentedTestRunner.h>
|
||||
#include <Test/Run/TestImpactTestRunException.h>
|
||||
#include <Test/Run/TestImpactTestRunSerializer.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
InstrumentedTestRunJobData::InstrumentedTestRunJobData(const AZ::IO::Path& resultsArtifact, const AZ::IO::Path& coverageArtifact)
|
||||
: TestRunJobData(resultsArtifact)
|
||||
, m_coverageArtifact(coverageArtifact)
|
||||
{
|
||||
}
|
||||
|
||||
const AZ::IO::Path& InstrumentedTestRunJobData::GetCoverageArtifactPath() const
|
||||
{
|
||||
return m_coverageArtifact;
|
||||
}
|
||||
|
||||
InstrumentedTestRunner::JobPayload ParseTestRunAndCoverageFiles(
|
||||
const AZ::IO::Path& runFile,
|
||||
const AZ::IO::Path& coverageFile,
|
||||
AZStd::chrono::milliseconds duration,
|
||||
InstrumentedTestRunner::CoverageExceptionPolicy coverageExceptionPolicy)
|
||||
{
|
||||
TestRun run(GTest::TestRunSuitesFactory(ReadFileContents<TestRunException>(runFile)), duration);
|
||||
AZStd::vector<ModuleCoverage> moduleCoverages = Cobertura::ModuleCoveragesFactory(ReadFileContents<TestRunException>(coverageFile));
|
||||
if (moduleCoverages.empty())
|
||||
{
|
||||
AZ_TestImpact_Eval(
|
||||
!IsFlagSet(coverageExceptionPolicy, Bitwise::CoverageExceptionPolicy::OnEmptyCoverage), TestRunException,
|
||||
"No coverage data generated");
|
||||
}
|
||||
|
||||
TestCoverage coverage(AZStd::move(moduleCoverages));
|
||||
return {AZStd::move(run), AZStd::move(coverage)};
|
||||
}
|
||||
|
||||
InstrumentedTestRunner::InstrumentedTestRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
size_t maxConcurrentRuns,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout)
|
||||
: JobRunner(clientCallback, AZStd::nullopt, StdOutputRouting::None, StdErrorRouting::None, maxConcurrentRuns, runTimeout, runnerTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::vector<InstrumentedTestRunner::Job> InstrumentedTestRunner::RunInstrumentedTests(
|
||||
const AZStd::vector<JobInfo>& jobInfos,
|
||||
CoverageExceptionPolicy coverageExceptionPolicy,
|
||||
JobExceptionPolicy jobExceptionPolicy)
|
||||
{
|
||||
const auto payloadGenerator = [this, coverageExceptionPolicy](const JobDataMap& jobDataMap)
|
||||
{
|
||||
PayloadMap<Job> runs;
|
||||
for (const auto& [jobId, jobData] : jobDataMap)
|
||||
{
|
||||
const auto& [meta, jobInfo] = jobData;
|
||||
if (meta.m_result == JobResult::ExecutedWithSuccess || meta.m_result == JobResult::ExecutedWithFailure)
|
||||
{
|
||||
runs[jobId] = ParseTestRunAndCoverageFiles(
|
||||
jobInfo->GetRunArtifactPath(),
|
||||
jobInfo->GetCoverageArtifactPath(),
|
||||
meta.m_duration.value(),
|
||||
coverageExceptionPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
return runs;
|
||||
};
|
||||
|
||||
return ExecuteJobs(jobInfos, payloadGenerator, jobExceptionPolicy);
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Test/Job/TestImpactTestJobRunner.h>
|
||||
#include <Test/Run/TestImpactTestCoverage.h>
|
||||
#include <Test/Run/TestImpactTestRun.h>
|
||||
#include <Test/Run/TestImpactTestRunJobData.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Per-job data for instrumented test runs.
|
||||
class InstrumentedTestRunJobData : public TestRunJobData
|
||||
{
|
||||
public:
|
||||
InstrumentedTestRunJobData(const AZ::IO::Path& resultsArtifact, const AZ::IO::Path& coverageArtifact);
|
||||
|
||||
//! Returns the path to the coverage artifact produced by the test target.
|
||||
const AZ::IO::Path& GetCoverageArtifactPath() const;
|
||||
|
||||
private:
|
||||
AZ::IO::Path m_coverageArtifact; //!< Path to coverage data.
|
||||
};
|
||||
|
||||
namespace Bitwise
|
||||
{
|
||||
//! Exception policy for test coverage artifacts.
|
||||
enum class CoverageExceptionPolicy
|
||||
{
|
||||
Never = 0, //! Never throw.
|
||||
OnEmptyCoverage = 1 //! Throw when no coverage data was produced.
|
||||
};
|
||||
} // namespace Bitwise
|
||||
|
||||
//! Runs a batch of test targets to determine the test coverage and passes/failures.
|
||||
class InstrumentedTestRunner : public TestJobRunner<InstrumentedTestRunJobData, AZStd::pair<TestRun, TestCoverage>>
|
||||
{
|
||||
using JobRunner = TestJobRunner<InstrumentedTestRunJobData, AZStd::pair<TestRun, TestCoverage>>;
|
||||
|
||||
public:
|
||||
using CoverageExceptionPolicy = Bitwise::CoverageExceptionPolicy;
|
||||
|
||||
//! Constructs an instrumented test runner with the specified parameters common to all job runs of this runner.
|
||||
//! @param clientCallback The optional client callback to be called whenever a run job changes state.
|
||||
//! @param maxConcurrentRuns The maximum number of runs to be in flight at any given time.
|
||||
//! @param runTimeout The maximum duration a run may be in-flight for before being forcefully terminated.
|
||||
//! @param runnerTimeout The maximum duration the runner may run before forcefully terminating all in-flight runs.
|
||||
InstrumentedTestRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback, size_t maxConcurrentRuns,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runTimeout, AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout);
|
||||
|
||||
//! Executes the specified instrumented test run jobs according to the specified job exception policies.
|
||||
//! @param jobInfos The test run jobs to execute.
|
||||
//! @param CoverageExceptionPolicy The coverage exception policy to be used for this run.
|
||||
//! @param jobExceptionPolicy The test run job exception policy to be used for this run (use
|
||||
//! TestJobExceptionPolicy::OnFailedToExecute to throw on test failures).
|
||||
//! @return the instrumented test run jobs with their associated test run and test coverage payloads.
|
||||
AZStd::vector<Job> RunInstrumentedTests(
|
||||
const AZStd::vector<JobInfo>& jobInfos, CoverageExceptionPolicy coverageExceptionPolicy, JobExceptionPolicy jobExceptionPolicy);
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Test/Run/TestImpactTestCoverage.h>
|
||||
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestCoverage::TestCoverage(AZStd::vector<ModuleCoverage>&& moduleCoverages)
|
||||
: m_modules(AZStd::move(moduleCoverages))
|
||||
{
|
||||
for (const auto& moduleCovered : m_modules)
|
||||
{
|
||||
for (const auto& sourceCovered : moduleCovered.m_sources)
|
||||
{
|
||||
m_sourcesCovered.emplace_back(sourceCovered.m_path);
|
||||
if (sourceCovered.m_coverage.has_value())
|
||||
{
|
||||
m_coverageLevel = CoverageLevel::Line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::sort(m_sourcesCovered.begin(), m_sourcesCovered.end());
|
||||
m_sourcesCovered.erase(AZStd::unique(m_sourcesCovered.begin(), m_sourcesCovered.end()), m_sourcesCovered.end());
|
||||
|
||||
if (!m_coverageLevel.has_value() && !m_sourcesCovered.empty())
|
||||
{
|
||||
m_coverageLevel = CoverageLevel::Source;
|
||||
}
|
||||
}
|
||||
|
||||
size_t TestCoverage::GetNumSourcesCovered() const
|
||||
{
|
||||
return m_sourcesCovered.size();
|
||||
}
|
||||
|
||||
size_t TestCoverage::GetNumModulesCovered() const
|
||||
{
|
||||
return m_modules.size();
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::IO::Path>& TestCoverage::GetSourcesCovered() const
|
||||
{
|
||||
return m_sourcesCovered;
|
||||
}
|
||||
|
||||
const AZStd::vector<ModuleCoverage>& TestCoverage::GetModuleCoverages() const
|
||||
{
|
||||
return m_modules;
|
||||
}
|
||||
|
||||
AZStd::optional<CoverageLevel> TestCoverage::GetCoverageLevel() const
|
||||
{
|
||||
return m_coverageLevel;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactCoverage.h>
|
||||
|
||||
#include <AzCore/std/containers/set.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Scope of coverage data.
|
||||
enum class CoverageLevel : bool
|
||||
{
|
||||
Source, //!< Line-level coverage data.
|
||||
Line //!< Source-level coverage data.
|
||||
};
|
||||
|
||||
//! Representation of a given test target's test coverage results.
|
||||
class TestCoverage
|
||||
{
|
||||
public:
|
||||
TestCoverage(AZStd::vector<ModuleCoverage>&& moduleCoverages);
|
||||
|
||||
//! Returns the number of unique sources covered.
|
||||
size_t GetNumSourcesCovered() const;
|
||||
|
||||
//! Returns the number of modules (dynamic libraries, child processes, etc.) covered.
|
||||
size_t GetNumModulesCovered() const;
|
||||
|
||||
//! Returns the sorted set of unique sources covered (empty if no coverage).
|
||||
const AZStd::vector<AZ::IO::Path>& GetSourcesCovered() const;
|
||||
|
||||
//! Returns the modules covered (empty if no coverage).
|
||||
const AZStd::vector<ModuleCoverage>& GetModuleCoverages() const;
|
||||
|
||||
//! Returns the coverage level (empty if no coverage).
|
||||
AZStd::optional<CoverageLevel> GetCoverageLevel() const;
|
||||
|
||||
private:
|
||||
AZStd::vector<ModuleCoverage> m_modules;
|
||||
AZStd::vector<AZ::IO::Path> m_sourcesCovered;
|
||||
AZStd::optional<CoverageLevel> m_coverageLevel;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TestImpactTestRun.h"
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestRun::TestRun(AZStd::vector<TestRunSuite>&& testSuites, AZStd::chrono::milliseconds duration)
|
||||
: TestSuiteContainer(AZStd::move(testSuites))
|
||||
, m_duration(duration)
|
||||
{
|
||||
for (const auto& suite : m_testSuites)
|
||||
{
|
||||
for (const auto& test : suite.m_tests)
|
||||
{
|
||||
if (test.m_status == TestRunStatus::Run)
|
||||
{
|
||||
m_numRuns++;
|
||||
|
||||
if (test.m_result.value() == TestRunResult::Passed)
|
||||
{
|
||||
m_numPasses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_numFailures++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_numNotRuns++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t TestRun::GetNumRuns() const
|
||||
{
|
||||
return m_numRuns;
|
||||
}
|
||||
|
||||
size_t TestRun::GetNumNotRuns() const
|
||||
{
|
||||
return m_numNotRuns;
|
||||
}
|
||||
|
||||
size_t TestRun::GetNumPasses() const
|
||||
{
|
||||
return m_numPasses;
|
||||
}
|
||||
|
||||
size_t TestRun::GetNumFailures() const
|
||||
{
|
||||
return m_numFailures;
|
||||
}
|
||||
|
||||
AZStd::chrono::milliseconds TestRun::GetDuration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Artifact/Dynamic/TestImpactTestRunSuite.h>
|
||||
#include <Test/TestImpactTestSuiteContainer.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Representation of a given test target's test run results.
|
||||
class TestRun
|
||||
: public TestSuiteContainer<TestRunSuite>
|
||||
{
|
||||
using TestSuiteContainer = TestSuiteContainer<TestRunSuite>;
|
||||
|
||||
public:
|
||||
TestRun(AZStd::vector<TestRunSuite>&& testSuites, AZStd::chrono::milliseconds duration);
|
||||
|
||||
//! Returns the total number of tests that were run.
|
||||
size_t GetNumRuns() const;
|
||||
|
||||
//! Returns the total number of tests that were not run.
|
||||
size_t GetNumNotRuns() const;
|
||||
|
||||
//! Returns the total number of tests that were run and passed.
|
||||
size_t GetNumPasses() const;
|
||||
|
||||
//! Returns the total number of tests that were run and failed.
|
||||
size_t GetNumFailures() const;
|
||||
|
||||
//! Returns the duration of the job that was executed to yield this run data.
|
||||
AZStd::chrono::milliseconds GetDuration() const;
|
||||
|
||||
private:
|
||||
size_t m_numRuns = 0;
|
||||
size_t m_numNotRuns = 0;
|
||||
size_t m_numPasses = 0;
|
||||
size_t m_numFailures = 0;
|
||||
AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds{0};
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Exception for test runs and test run related operations.
|
||||
class TestRunException : public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Test/Run/TestImpactTestRunJobData.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestRunJobData::TestRunJobData(const AZ::IO::Path& resultsArtifact)
|
||||
: m_runArtifact(resultsArtifact)
|
||||
{
|
||||
}
|
||||
|
||||
const AZ::IO::Path& TestRunJobData::GetRunArtifactPath() const
|
||||
{
|
||||
return m_runArtifact;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Test/Job/TestImpactTestJobRunner.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Per-job data for test runs.
|
||||
class TestRunJobData
|
||||
{
|
||||
public:
|
||||
TestRunJobData(const AZ::IO::Path& resultsArtifact);
|
||||
|
||||
//! Returns the path to the test run artifact produced by the test target.
|
||||
const AZ::IO::Path& GetRunArtifactPath() const;
|
||||
|
||||
private:
|
||||
AZ::IO::Path m_runArtifact; //!< Path to results data.
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Test/Run/TestImpactTestRunException.h>
|
||||
#include <Test/Run/TestImpactTestRunSerializer.h>
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/JSON/prettywriter.h>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/JSON/stringbuffer.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Keys for pertinent JSON node and attribute names
|
||||
constexpr const char* Keys[] =
|
||||
{
|
||||
"suites",
|
||||
"name",
|
||||
"enabled",
|
||||
"tests",
|
||||
"duration",
|
||||
"status",
|
||||
"result"
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SuitesKey,
|
||||
NameKey,
|
||||
EnabledKey,
|
||||
TestsKey,
|
||||
DurationKey,
|
||||
StatusKey,
|
||||
ResultKey
|
||||
};
|
||||
} // namespace
|
||||
|
||||
AZStd::string SerializeTestRun(const TestRun& testRun)
|
||||
{
|
||||
rapidjson::StringBuffer stringBuffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(stringBuffer);
|
||||
|
||||
// Run
|
||||
writer.StartObject();
|
||||
|
||||
// Run duration
|
||||
writer.Key(Keys[DurationKey]);
|
||||
writer.Uint(testRun.GetDuration().count());
|
||||
|
||||
// Suites
|
||||
writer.Key(Keys[SuitesKey]);
|
||||
writer.StartArray();
|
||||
|
||||
for (const auto& suite : testRun.GetTestSuites())
|
||||
{
|
||||
// Suite
|
||||
writer.StartObject();
|
||||
|
||||
// Suite name
|
||||
writer.Key(Keys[NameKey]);
|
||||
writer.String(suite.m_name.c_str());
|
||||
|
||||
// Suite duration
|
||||
writer.Key(Keys[DurationKey]);
|
||||
writer.Uint(suite.m_duration.count());
|
||||
|
||||
// Suite enabled
|
||||
writer.Key(Keys[EnabledKey]);
|
||||
writer.Bool(suite.m_enabled);
|
||||
|
||||
// Suite tests
|
||||
writer.Key(Keys[TestsKey]);
|
||||
writer.StartArray();
|
||||
for (const auto& test : suite.m_tests)
|
||||
{
|
||||
// Test
|
||||
writer.StartObject();
|
||||
|
||||
// Test name
|
||||
writer.Key(Keys[NameKey]);
|
||||
writer.String(test.m_name.c_str());
|
||||
|
||||
// Test enabled
|
||||
writer.Key(Keys[EnabledKey]);
|
||||
writer.Bool(test.m_enabled);
|
||||
|
||||
// Test duration
|
||||
writer.Key(Keys[DurationKey]);
|
||||
writer.Uint(test.m_duration.count());
|
||||
|
||||
// Test status
|
||||
writer.Key(Keys[StatusKey]);
|
||||
writer.Bool(static_cast<bool>(test.m_status));
|
||||
|
||||
// Test result
|
||||
if (test.m_status == TestRunStatus::Run)
|
||||
{
|
||||
writer.Key(Keys[ResultKey]);
|
||||
writer.Bool(static_cast<size_t>(test.m_result.value()));
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Key(Keys[ResultKey]);
|
||||
writer.Null();
|
||||
}
|
||||
|
||||
// End test
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
// End tests
|
||||
writer.EndArray();
|
||||
|
||||
// End suite
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
// End suites
|
||||
writer.EndArray();
|
||||
|
||||
// End run
|
||||
writer.EndObject();
|
||||
|
||||
return stringBuffer.GetString();
|
||||
}
|
||||
|
||||
TestRun DeserializeTestRun(const AZStd::string& testEnumString)
|
||||
{
|
||||
AZStd::vector<TestRunSuite> testSuites;
|
||||
rapidjson::Document doc;
|
||||
|
||||
if (doc.Parse<0>(testEnumString.c_str()).HasParseError())
|
||||
{
|
||||
throw TestRunException("Could not parse enumeration data");
|
||||
}
|
||||
|
||||
// Run duration
|
||||
const AZStd::chrono::milliseconds runDuration = AZStd::chrono::milliseconds{doc[Keys[DurationKey]].GetUint()};
|
||||
|
||||
// Suites
|
||||
for (const auto& suite : doc[Keys[SuitesKey]].GetArray())
|
||||
{
|
||||
// Suite name
|
||||
const AZStd::string name = suite[Keys[NameKey]].GetString();
|
||||
|
||||
// Suite duration
|
||||
const AZStd::chrono::milliseconds suiteDuration = AZStd::chrono::milliseconds{suite[Keys[DurationKey]].GetUint()};
|
||||
|
||||
// Suite enabled
|
||||
const bool enabled = suite[Keys[EnabledKey]].GetBool();
|
||||
|
||||
testSuites.emplace_back(TestRunSuite{
|
||||
suite[Keys[NameKey]].GetString(),
|
||||
suite[Keys[EnabledKey]].GetBool(),
|
||||
{},
|
||||
AZStd::chrono::milliseconds{suite[Keys[DurationKey]].GetUint()}});
|
||||
|
||||
// Suite tests
|
||||
for (const auto& test : suite[Keys[TestsKey]].GetArray())
|
||||
{
|
||||
AZStd::optional<TestRunResult> result;
|
||||
TestRunStatus status = static_cast<TestRunStatus>(test[Keys[StatusKey]].GetBool());
|
||||
if (status == TestRunStatus::Run)
|
||||
{
|
||||
result = static_cast<TestRunResult>(test[Keys[ResultKey]].GetBool());
|
||||
}
|
||||
const AZStd::chrono::milliseconds testDuration = AZStd::chrono::milliseconds{test[Keys[DurationKey]].GetUint()};
|
||||
testSuites.back().m_tests.emplace_back(
|
||||
TestRunCase{test[Keys[NameKey]].GetString(), test[Keys[EnabledKey]].GetBool(), result, testDuration, status});
|
||||
}
|
||||
}
|
||||
|
||||
return TestRun(std::move(testSuites), runDuration);
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Test/Run/TestImpactTestRun.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Serializes the specified test run to JSON format.
|
||||
AZStd::string SerializeTestRun(const TestRun& testRun);
|
||||
|
||||
//! Deserializes a test run from the specified test run data in JSON format.
|
||||
TestRun DeserializeTestRun(const AZStd::string& testRunString);
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestRunSuiteFactory.h>
|
||||
#include <Test/Job/TestImpactTestJobCommon.h>
|
||||
#include <Test/Run/TestImpactTestRunException.h>
|
||||
#include <Test/Run/TestImpactTestRunSerializer.h>
|
||||
#include <Test/Run/TestImpactTestRunner.h>
|
||||
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
TestRun ParseTestRunFile(const AZ::IO::Path& runFile, AZStd::chrono::milliseconds duration)
|
||||
{
|
||||
return TestRun(GTest::TestRunSuitesFactory(ReadFileContents<TestRunException>(runFile)), duration);
|
||||
}
|
||||
|
||||
TestRunner::TestRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
size_t maxConcurrentRuns,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout)
|
||||
: JobRunner(clientCallback, AZStd::nullopt, StdOutputRouting::None, StdErrorRouting::None, maxConcurrentRuns, runTimeout, runnerTimeout)
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::vector<TestRunner::Job> TestRunner::RunTests(
|
||||
const AZStd::vector<JobInfo>& jobInfos,
|
||||
JobExceptionPolicy jobExceptionPolicy)
|
||||
{
|
||||
const auto payloadGenerator = [this](const JobDataMap& jobDataMap)
|
||||
{
|
||||
PayloadMap<Job> runs;
|
||||
for (const auto& [jobId, jobData] : jobDataMap)
|
||||
{
|
||||
const auto& [meta, jobInfo] = jobData;
|
||||
if (meta.m_result == JobResult::ExecutedWithSuccess || meta.m_result == JobResult::ExecutedWithFailure)
|
||||
{
|
||||
runs[jobId] = ParseTestRunFile(jobInfo->GetRunArtifactPath(), meta.m_duration.value());
|
||||
}
|
||||
}
|
||||
|
||||
return runs;
|
||||
};
|
||||
|
||||
return ExecuteJobs(jobInfos, payloadGenerator, jobExceptionPolicy);
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Test/Job/TestImpactTestJobRunner.h>
|
||||
#include <Test/Run/TestImpactTestRun.h>
|
||||
#include <Test/Run/TestImpactTestRunJobData.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Runs a batch of test targets to determine the test passes/failures.
|
||||
class TestRunner
|
||||
: public TestJobRunner<TestRunJobData, TestRun>
|
||||
{
|
||||
using JobRunner = TestJobRunner<TestRunJobData, TestRun>;
|
||||
|
||||
public:
|
||||
//! Constructs a test runner with the specified parameters common to all job runs of this runner.
|
||||
//! @param clientCallback The optional client callback to be called whenever a run job changes state.
|
||||
//! @param maxConcurrentRuns The maximum number of runs to be in flight at any given time.
|
||||
//! @param runTimeout The maximum duration a run may be in-flight for before being forcefully terminated.
|
||||
//! @param runnerTimeout The maximum duration the runner may run before forcefully terminating all in-flight runs.
|
||||
TestRunner(
|
||||
AZStd::optional<ClientJobCallback> clientCallback,
|
||||
size_t maxConcurrentRuns,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runTimeout,
|
||||
AZStd::optional<AZStd::chrono::milliseconds> runnerTimeout);
|
||||
|
||||
//! Executes the specified test run jobs according to the specified job exception policies.
|
||||
//! @param jobInfos The test run jobs to execute.
|
||||
//! @param jobExceptionPolicy The test run job exception policy to be used for this run (use
|
||||
//! TestJobExceptionPolicy::OnFailedToExecute to throw on test failures).
|
||||
//! @return the test run jobs with their associated test run payloads.
|
||||
AZStd::vector<Job> RunTests(const AZStd::vector<JobInfo>& jobInfos, JobExceptionPolicy jobExceptionPolicy);
|
||||
};
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
//! Encapsulation of test suites into a class with meta-data about each the suites.
|
||||
//! @tparam TestSuite The test suite data structure to encapsulate.
|
||||
template<typename TestSuite>
|
||||
class TestSuiteContainer
|
||||
{
|
||||
public:
|
||||
TestSuiteContainer(AZStd::vector<TestSuite>&& testSuites);
|
||||
|
||||
//! Returns the test suites in this container.
|
||||
const AZStd::vector<TestSuite>& GetTestSuites() const;
|
||||
|
||||
//! Returns the number of test suites in this container.
|
||||
size_t GetNumTestSuites() const;
|
||||
|
||||
//! Returns the total number of tests across all test suites.
|
||||
size_t GetNumTests() const;
|
||||
|
||||
//! Returns the total number of enabled tests across all test suites.
|
||||
size_t GetNumEnabledTests() const;
|
||||
|
||||
//! Returns the total number of disabled tests across all test suites.
|
||||
size_t GetNumDisabledTests() const;
|
||||
|
||||
protected:
|
||||
AZStd::vector<TestSuite> m_testSuites;
|
||||
size_t m_numDisabledTests = 0;
|
||||
size_t m_numEnabledTests = 0;
|
||||
};
|
||||
|
||||
template<typename TestSuite>
|
||||
TestSuiteContainer<TestSuite>::TestSuiteContainer(AZStd::vector<TestSuite>&& testSuites)
|
||||
: m_testSuites(std::move(testSuites))
|
||||
{
|
||||
for (const auto& suite : m_testSuites)
|
||||
{
|
||||
if (suite.m_enabled)
|
||||
{
|
||||
const auto enabled = std::count_if(suite.m_tests.begin(), suite.m_tests.end(), [](const auto& test)
|
||||
{
|
||||
return test.m_enabled;
|
||||
});
|
||||
|
||||
m_numEnabledTests += enabled;
|
||||
m_numDisabledTests += suite.m_tests.size() - enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disabled status of suites propagates down to all tests regardless of whether or not each individual test is disabled
|
||||
m_numDisabledTests += suite.m_tests.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TestSuite>
|
||||
const AZStd::vector<TestSuite>& TestSuiteContainer<TestSuite>::GetTestSuites() const
|
||||
{
|
||||
return m_testSuites;
|
||||
}
|
||||
|
||||
template<typename TestSuite>
|
||||
size_t TestSuiteContainer<TestSuite>::GetNumTests() const
|
||||
{
|
||||
return m_numEnabledTests + m_numDisabledTests;
|
||||
}
|
||||
|
||||
template<typename TestSuite>
|
||||
size_t TestSuiteContainer<TestSuite>::GetNumEnabledTests() const
|
||||
{
|
||||
return m_numEnabledTests;
|
||||
}
|
||||
|
||||
template<typename TestSuite>
|
||||
size_t TestSuiteContainer<TestSuite>::GetNumDisabledTests() const
|
||||
{
|
||||
return m_numDisabledTests;
|
||||
}
|
||||
|
||||
template<typename TestSuite>
|
||||
size_t TestSuiteContainer<TestSuite>::GetNumTestSuites() const
|
||||
{
|
||||
return m_testSuites.size();
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactFramework/TestImpactException.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
Exception::Exception(const AZStd::string& msg)
|
||||
: m_msg(msg)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(const char* msg)
|
||||
: m_msg(msg)
|
||||
{
|
||||
}
|
||||
|
||||
const char* Exception::what() const noexcept
|
||||
{
|
||||
return m_msg.c_str();
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactFramework/TestImpactFrameworkPath.h>
|
||||
|
||||
namespace TestImpact
|
||||
{
|
||||
FrameworkPath::FrameworkPath(const AZ::IO::Path& absolutePath)
|
||||
{
|
||||
m_absolutePath = AZ::IO::Path(absolutePath).MakePreferred();
|
||||
m_relativePath = m_absolutePath.LexicallyRelative(m_absolutePath);
|
||||
}
|
||||
|
||||
FrameworkPath::FrameworkPath(const AZ::IO::Path& absolutePath, const FrameworkPath& relativeTo)
|
||||
{
|
||||
m_absolutePath = AZ::IO::Path(absolutePath).MakePreferred();
|
||||
m_relativePath = m_absolutePath.LexicallyRelative(relativeTo.Absolute());
|
||||
}
|
||||
|
||||
const AZ::IO::Path& FrameworkPath::Absolute() const
|
||||
{
|
||||
return m_absolutePath;
|
||||
}
|
||||
|
||||
const AZ::IO::Path& FrameworkPath::Relative() const
|
||||
{
|
||||
return m_relativePath;
|
||||
}
|
||||
} // namespace TestImpact
|
||||
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Factory/TestImpactBuildTargetDescriptorFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class BuildTargetDescriptorFactoryTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
protected:
|
||||
const AZStd::vector<AZStd::string> m_staticExclude = {".cmake"};
|
||||
const AZStd::vector<AZStd::string> m_inputExclude = {".jinja"};
|
||||
const AZStd::string m_autogenMatcher = {"(.*)\\..*"};
|
||||
|
||||
const AZStd::vector<AZStd::string> m_autogenInputs =
|
||||
{
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/Log.ScriptCanvasNode.xml",
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/DrawText.ScriptCanvasNode.xml",
|
||||
"Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNode_Header.jinja",
|
||||
"Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNode_Source.jinja"
|
||||
};
|
||||
|
||||
const AZStd::vector<AZStd::string> m_autogenOutputs =
|
||||
{
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.cpp",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.cpp"
|
||||
};
|
||||
|
||||
const AZStd::vector<AZStd::string> m_staticSources =
|
||||
{
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp",
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h",
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/scriptcanvasdiagnosticlibrary_autogen_files.cmake",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.cpp",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.cpp"
|
||||
};
|
||||
|
||||
const AZStd::vector<AZStd::string> m_expectedStaticSources =
|
||||
{
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp",
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.cpp",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.cpp"
|
||||
};
|
||||
|
||||
const AZStd::string m_name = "ScriptCanvasDiagnosticLibrary.Static";
|
||||
const AZStd::string m_outputName = "ScriptCanvasDiagnosticLibrary";
|
||||
const AZStd::string m_path = "Gems/ScriptCanvasDiagnosticLibrary/Code";
|
||||
|
||||
const TestImpact::AutogenSources m_expectedAutogenSources =
|
||||
{
|
||||
{
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/Log.ScriptCanvasNode.xml",
|
||||
{
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/Log.generated.cpp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Gems/ScriptCanvasDiagnosticLibrary/Code/Source/DrawText.ScriptCanvasNode.xml",
|
||||
{
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.h",
|
||||
"windows_vs2019/Gems/ScriptCanvasDiagnosticLibrary/Code/Azcg/Generated/Source/DrawText.generated.cpp"
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, NoRawData_ExpectArtifactException)
|
||||
{
|
||||
// Given an empty raw descriptor string
|
||||
const AZStd::string rawTargetDescriptor;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, InvalidRawData_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw descriptor string of invalid data
|
||||
const AZStd::string rawTargetDescriptor = "abcde";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, NoAutogenMatcher_ExpectArtifactException)
|
||||
{
|
||||
// Given a valid raw descriptor string
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, m_staticSources, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor with an empty autogen matcher
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, "");
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, EmptyName_ExpectArtifactException)
|
||||
{
|
||||
// Given a invalid raw descriptor string lacking build meta-data name
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString("", m_outputName, m_path, m_staticSources, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, EmptyOutputName_ExpectArtifactException)
|
||||
{
|
||||
// Given a invalid raw descriptor string lacking build meta-data output name
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, "", m_path, m_staticSources, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, EmptyPath_ExpectArtifactException)
|
||||
{
|
||||
// Given a invalid raw descriptor string lacking build meta-data path
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, "", m_staticSources, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, NoStaticSources_ExpectValidDescriptor)
|
||||
{
|
||||
const TestImpact::BuildTargetDescriptor expectedBuiltTarget =
|
||||
GenerateBuildTargetDescriptor(m_name, m_outputName, m_path, {}, m_expectedAutogenSources);
|
||||
|
||||
// Given a valid raw descriptor string with no static sources
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, {}, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, {}, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Expect the constructed build target descriptor to match the specified descriptor
|
||||
EXPECT_TRUE(buildTarget == expectedBuiltTarget);
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, NoAutogenSources_ExpectValidDescriptor)
|
||||
{
|
||||
const TestImpact::BuildTargetDescriptor expectedBuiltTarget =
|
||||
GenerateBuildTargetDescriptor(m_name, m_outputName, m_path, m_expectedStaticSources, {});
|
||||
|
||||
// Given a valid raw descriptor string with no autogen sources
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, m_staticSources, {}, {});
|
||||
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Expect the constructed build target descriptor to match the specified descriptor
|
||||
EXPECT_TRUE(buildTarget == expectedBuiltTarget);
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, NoStaticOrAutogenSources_ExpectValidDescriptor)
|
||||
{
|
||||
const TestImpact::BuildTargetDescriptor expectedBuiltTarget = GenerateBuildTargetDescriptor(m_name, m_outputName, m_path, {}, {});
|
||||
|
||||
// Given a valid raw descriptor string with no static or autogen sources
|
||||
const AZStd::string rawTargetDescriptor = GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, {}, {}, {});
|
||||
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Expect the constructed build target descriptor to match the specified descriptor
|
||||
EXPECT_TRUE(buildTarget == expectedBuiltTarget);
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, AutogenOutputSourcesButNoAutogenInputSources_ExpectArtifactException)
|
||||
{
|
||||
// Given a valid raw descriptor string with autogen output sources but no autogen input sources
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, m_staticSources, {}, m_autogenOutputs);
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, AutogenInputSourcesButNoAutogenOutputSources_ExpectArtifactException)
|
||||
{
|
||||
// Given a valid raw descriptor string with autogen inout sources but no autogen output sources
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, m_staticSources, m_autogenInputs, {});
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BuildTargetDescriptorFactoryTestFixture, StaticAndAutogenSources_ExpectValidDescriptor)
|
||||
{
|
||||
const TestImpact::BuildTargetDescriptor expectedBuiltTarget =
|
||||
GenerateBuildTargetDescriptor(m_name, m_outputName, m_path, m_expectedStaticSources, m_expectedAutogenSources);
|
||||
|
||||
// Given a valid raw descriptor string with static and autogen sources
|
||||
const AZStd::string rawTargetDescriptor =
|
||||
GenerateBuildTargetDescriptorString(m_name, m_outputName, m_path, m_staticSources, m_autogenInputs, m_autogenOutputs);
|
||||
|
||||
// When attempting to construct the build target descriptor
|
||||
const TestImpact::BuildTargetDescriptor buildTarget =
|
||||
TestImpact::BuildTargetDescriptorFactory(rawTargetDescriptor, m_staticExclude, m_inputExclude, m_autogenMatcher);
|
||||
|
||||
// Expect the constructed build target descriptor to match the specified descriptor
|
||||
EXPECT_TRUE(buildTarget == expectedBuiltTarget);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Artifact/Factory/TestImpactChangeListFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST(ChangeListFactoryTest, NoRawData_ExpectArtifactException)
|
||||
{
|
||||
// Given an empty unified diff string
|
||||
const AZStd::string unifiedDiff;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ChangeListFactoryTest, NoChanges_ExpectArtifactException)
|
||||
{
|
||||
// Given a unified diff string with no changes
|
||||
const AZStd::string unifiedDiff = "On this day in 1738 absolutely nothing happened";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ChangeListFactoryTest, CreateOnly_ExpectValidChangeListWithFileCreateOperations)
|
||||
{
|
||||
// Given a unified diff with only one file creation and no file updates or deletions
|
||||
const AZStd::string unifiedDiff =
|
||||
"From f642a2f698452fc18484758b0046132415f09467 Mon Sep 17 00:00:00 2001\n"
|
||||
"From: user <user@website.com>\n"
|
||||
"Date: Sat, 13 Mar 2021 22:58:07 +0000\n"
|
||||
"Subject: Test\n"
|
||||
"\n"
|
||||
"---\n"
|
||||
" New.txt | 1 +\n"
|
||||
" create mode 100644 New.txt\n"
|
||||
"diff --git a/New.txt b/New.txt\n"
|
||||
"new file mode 100644\n"
|
||||
"index 0000000..30d74d2\n"
|
||||
"--- /dev/null\n"
|
||||
"+++ b/New.txt\n"
|
||||
"@@ -0,0 +1 @@\n"
|
||||
"+test\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"-- \n"
|
||||
"2.30.0.windows.2\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Expect the change list to contain the 1 created file
|
||||
EXPECT_EQ(changeList.m_createdFiles.size(), 1);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_createdFiles.begin(), changeList.m_createdFiles.end(), "New.txt") != changeList.m_createdFiles.end());
|
||||
|
||||
// Expect the change list to contain no updated files
|
||||
EXPECT_TRUE(changeList.m_updatedFiles.empty());
|
||||
|
||||
// Expect the change list to contain no deleted files
|
||||
EXPECT_TRUE(changeList.m_deletedFiles.empty());
|
||||
}
|
||||
|
||||
TEST(ChangeListFactoryTest, UpdateOnly_ExpectValidChangeListWithFileUpdateOperations)
|
||||
{
|
||||
// Given a unified diff with only one file update and no file creations or deletions
|
||||
const AZStd::string unifiedDiff =
|
||||
"From f642a2f698452fc18484758b0046132415f09467 Mon Sep 17 00:00:00 2001\n"
|
||||
"From: user <user@website.com>\n"
|
||||
"Date: Sat, 13 Mar 2021 22:58:07 +0000\n"
|
||||
"Subject: Test\n"
|
||||
"\n"
|
||||
"---\n"
|
||||
" A.txt | 2 +-\n"
|
||||
"diff --git a/A.txt b/A.txt\n"
|
||||
"index 7c4a013..e132db2 100644\n"
|
||||
"--- a/A.txt\n"
|
||||
"+++ b/A.txt\n"
|
||||
"@@ -1 +1 @@\n"
|
||||
"-aaa\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"+zzz\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"-- \n"
|
||||
"2.30.0.windows.2\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Expect the change list to contain no created files
|
||||
EXPECT_TRUE(changeList.m_createdFiles.empty());
|
||||
|
||||
// Expect the change list to contain one updated file
|
||||
EXPECT_EQ(changeList.m_updatedFiles.size(), 1);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_updatedFiles.begin(), changeList.m_updatedFiles.end(), "A.txt") != changeList.m_updatedFiles.end());
|
||||
|
||||
// Expect the change list to contain no deleted files
|
||||
EXPECT_TRUE(changeList.m_deletedFiles.empty());
|
||||
}
|
||||
|
||||
TEST(ChangeListFactoryTest, DeleteOnly_ExpectValidChangeListWithFileDeleteOperations)
|
||||
{
|
||||
// Given a unified diff with only one file deletion and no file creations or updates
|
||||
const AZStd::string unifiedDiff =
|
||||
"From f642a2f698452fc18484758b0046132415f09467 Mon Sep 17 00:00:00 2001\n"
|
||||
"From: user <user@website.com>\n"
|
||||
"Date: Sat, 13 Mar 2021 22:58:07 +0000\n"
|
||||
"Subject: Test\n"
|
||||
"\n"
|
||||
"---\n"
|
||||
" B.txt | 1 -\n"
|
||||
" delete mode 100644 B.txt\n"
|
||||
"diff --git a/B.txt b/B.txt\n"
|
||||
"deleted file mode 100644\n"
|
||||
"index 01f02e3..0000000\n"
|
||||
"--- a/B.txt\n"
|
||||
"+++ /dev/null\n"
|
||||
"@@ -1 +0,0 @@\n"
|
||||
"-bbb\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"-- \n"
|
||||
"2.30.0.windows.2\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Expect the change list to contain no created files
|
||||
EXPECT_TRUE(changeList.m_createdFiles.empty());
|
||||
|
||||
// Expect the change list to contain no updated files
|
||||
EXPECT_TRUE(changeList.m_updatedFiles.empty());
|
||||
|
||||
// Expect the change list to contain one deleted file
|
||||
EXPECT_EQ(changeList.m_deletedFiles.size(), 1);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_deletedFiles.begin(), changeList.m_deletedFiles.end(), "B.txt") != changeList.m_deletedFiles.end());
|
||||
}
|
||||
|
||||
TEST(ChangeListFactoryTest, ParseUnifiedDiffWithAllPossibleOperations_ExpectChangeListMatchingOperations)
|
||||
{
|
||||
// Given a unified diff with created files, updated files, deleted files, renamed files and moved files
|
||||
const AZStd::string unifiedDiff =
|
||||
"From f642a2f698452fc18484758b0046132415f09467 Mon Sep 17 00:00:00 2001\n"
|
||||
"From: user <user@website.com>\n"
|
||||
"Date: Sat, 13 Mar 2021 22:58:07 +0000\n"
|
||||
"Subject: Test\n"
|
||||
"\n"
|
||||
"---\n"
|
||||
" A.txt | 2 +-\n"
|
||||
" B.txt | 1 -\n"
|
||||
" D.txt => Foo/D.txt | 0\n"
|
||||
" E.txt => Foo/Y.txt | 0\n"
|
||||
" New.txt | 1 +\n"
|
||||
" C.txt => X.txt | 0\n"
|
||||
" 6 files changed, 2 insertions(+), 2 deletions(-)\n"
|
||||
" delete mode 100644 B.txt\n"
|
||||
" rename D.txt => Foo/D.txt (100%)\n"
|
||||
" rename E.txt => Foo/Y.txt (100%)\n"
|
||||
" create mode 100644 New.txt\n"
|
||||
" rename C.txt => X.txt (100%)\n"
|
||||
"\n"
|
||||
"diff --git a/A.txt b/A.txt\n"
|
||||
"index 7c4a013..e132db2 100644\n"
|
||||
"--- a/A.txt\n"
|
||||
"+++ b/A.txt\n"
|
||||
"@@ -1 +1 @@\n"
|
||||
"-aaa\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"+zzz\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"diff --git a/B.txt b/B.txt\n"
|
||||
"deleted file mode 100644\n"
|
||||
"index 01f02e3..0000000\n"
|
||||
"--- a/B.txt\n"
|
||||
"+++ /dev/null\n"
|
||||
"@@ -1 +0,0 @@\n"
|
||||
"-bbb\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"diff --git a/D.txt b/Foo/D.txt\n"
|
||||
"similarity index 100%\n"
|
||||
"rename from D.txt\n"
|
||||
"rename to Foo/D.txt\n"
|
||||
"diff --git a/E.txt b/Foo/Y.txt\n"
|
||||
"similarity index 100%\n"
|
||||
"rename from E.txt\n"
|
||||
"rename to Foo/Y.txt\n"
|
||||
"diff --git a/New.txt b/New.txt\n"
|
||||
"new file mode 100644\n"
|
||||
"index 0000000..30d74d2\n"
|
||||
"--- /dev/null\n"
|
||||
"+++ b/New.txt\n"
|
||||
"@@ -0,0 +1 @@\n"
|
||||
"+test\n"
|
||||
"\\ No newline at end of file\n"
|
||||
"diff --git a/C.txt b/X.txt\n"
|
||||
"similarity index 100%\n"
|
||||
"rename from C.txt\n"
|
||||
"rename to X.txt\n"
|
||||
"-- \n"
|
||||
"2.30.0.windows.2\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
// When attempting to construct the change list
|
||||
const TestImpact::ChangeList changeList = TestImpact::UnifiedDiff::ChangeListFactory(unifiedDiff);
|
||||
|
||||
// Expect the change list to contain the 4 created files
|
||||
EXPECT_EQ(changeList.m_createdFiles.size(), 4);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_createdFiles.begin(), changeList.m_createdFiles.end(), "Foo/D.txt") !=
|
||||
changeList.m_createdFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_createdFiles.begin(), changeList.m_createdFiles.end(), "Foo/Y.txt") !=
|
||||
changeList.m_createdFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_createdFiles.begin(), changeList.m_createdFiles.end(), "X.txt") != changeList.m_createdFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_createdFiles.begin(), changeList.m_createdFiles.end(), "New.txt") != changeList.m_createdFiles.end());
|
||||
|
||||
// Expect the change list to contain the 1 updated file
|
||||
EXPECT_EQ(changeList.m_updatedFiles.size(), 1);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_updatedFiles.begin(), changeList.m_updatedFiles.end(), "A.txt") != changeList.m_updatedFiles.end());
|
||||
|
||||
// Expect the change list to contain the 4 deleted files
|
||||
EXPECT_EQ(changeList.m_deletedFiles.size(), 4);
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_deletedFiles.begin(), changeList.m_deletedFiles.end(), "B.txt") != changeList.m_deletedFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_deletedFiles.begin(), changeList.m_deletedFiles.end(), "D.txt") != changeList.m_deletedFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_deletedFiles.begin(), changeList.m_deletedFiles.end(), "E.txt") != changeList.m_deletedFiles.end());
|
||||
EXPECT_TRUE(
|
||||
AZStd::find(changeList.m_deletedFiles.begin(), changeList.m_deletedFiles.end(), "C.txt") != changeList.m_deletedFiles.end());
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,522 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Factory/TestImpactModuleCoverageFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseEmptyString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an empty string
|
||||
const AZStd::string rawCoverage;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the empty coverage
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseInvalidString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an invalid string
|
||||
const AZStd::string rawCoverage = "!@?";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the invalid coverage
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseEmptyCoverage_ExpectEmptyModuleCoverages)
|
||||
{
|
||||
// Given an empty coverage string
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617713965\" lines-covered=\"0\" lines-valid=\"0\" version=\"0\">"
|
||||
" <sources/>"
|
||||
" <packages/>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When attempting to parse the empty coverage
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect an empty module coverages
|
||||
EXPECT_TRUE(coverage.empty());
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetLineCoverageA_ReturnsValidLineCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetALineModuleCoverages();
|
||||
|
||||
// Given the raw line coverage output of TestTargetA
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617124634\" lines-covered=\"41\" lines-valid=\"41\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetA.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetA.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines>"
|
||||
" <line number=\"22\" hits=\"1\"/>"
|
||||
" <line number=\"23\" hits=\"1\"/>"
|
||||
" <line number=\"24\" hits=\"1\"/>"
|
||||
" <line number=\"25\" hits=\"1\"/>"
|
||||
" <line number=\"27\" hits=\"1\"/>"
|
||||
" <line number=\"28\" hits=\"1\"/>"
|
||||
" <line number=\"29\" hits=\"1\"/>"
|
||||
" <line number=\"30\" hits=\"1\"/>"
|
||||
" <line number=\"32\" hits=\"1\"/>"
|
||||
" <line number=\"33\" hits=\"1\"/>"
|
||||
" <line number=\"34\" hits=\"1\"/>"
|
||||
" <line number=\"35\" hits=\"1\"/>"
|
||||
" <line number=\"37\" hits=\"1\"/>"
|
||||
" <line number=\"38\" hits=\"1\"/>"
|
||||
" <line number=\"39\" hits=\"1\"/>"
|
||||
" <line number=\"40\" hits=\"1\"/>"
|
||||
" <line number=\"42\" hits=\"1\"/>"
|
||||
" <line number=\"43\" hits=\"1\"/>"
|
||||
" <line number=\"44\" hits=\"1\"/>"
|
||||
" <line number=\"45\" hits=\"1\"/>"
|
||||
" <line number=\"47\" hits=\"1\"/>"
|
||||
" <line number=\"48\" hits=\"1\"/>"
|
||||
" <line number=\"49\" hits=\"1\"/>"
|
||||
" <line number=\"50\" hits=\"1\"/>"
|
||||
" <line number=\"52\" hits=\"1\"/>"
|
||||
" <line number=\"53\" hits=\"1\"/>"
|
||||
" <line number=\"54\" hits=\"1\"/>"
|
||||
" <line number=\"55\" hits=\"1\"/>"
|
||||
" <line number=\"57\" hits=\"1\"/>"
|
||||
" <line number=\"58\" hits=\"1\"/>"
|
||||
" <line number=\"59\" hits=\"1\"/>"
|
||||
" <line number=\"60\" hits=\"1\"/>"
|
||||
" <line number=\"62\" hits=\"1\"/>"
|
||||
" <line number=\"63\" hits=\"1\"/>"
|
||||
" <line number=\"64\" hits=\"1\"/>"
|
||||
" <line number=\"65\" hits=\"1\"/>"
|
||||
" <line number=\"67\" hits=\"1\"/>"
|
||||
" <line number=\"68\" hits=\"1\"/>"
|
||||
" <line number=\"69\" hits=\"1\"/>"
|
||||
" <line number=\"70\" hits=\"1\"/>"
|
||||
" <line number=\"73\" hits=\"1\"/>"
|
||||
" </lines>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw line coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetSourceCoverageA_ReturnsValidSourceCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetASourceModuleCoverages();
|
||||
|
||||
// Given the raw source coverage output of TestTargetA
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617117760\" lines-covered=\"0\" lines-valid=\"0\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetA.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetA.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines/>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw source coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetLineCoverageB_ReturnsValidLineCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetBLineModuleCoverages();
|
||||
|
||||
// Given the raw line coverage output of TestTargetB
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617124605\" lines-covered=\"29\" lines-valid=\"29\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetB.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetB.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetB\\Code\\Tests\\TestImpactTestTargetB.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines>"
|
||||
" <line number=\"29\" hits=\"1\"/>"
|
||||
" <line number=\"30\" hits=\"1\"/>"
|
||||
" <line number=\"31\" hits=\"1\"/>"
|
||||
" <line number=\"32\" hits=\"1\"/>"
|
||||
" <line number=\"34\" hits=\"1\"/>"
|
||||
" <line number=\"35\" hits=\"1\"/>"
|
||||
" <line number=\"36\" hits=\"1\"/>"
|
||||
" <line number=\"37\" hits=\"1\"/>"
|
||||
" <line number=\"39\" hits=\"1\"/>"
|
||||
" <line number=\"40\" hits=\"1\"/>"
|
||||
" <line number=\"41\" hits=\"1\"/>"
|
||||
" <line number=\"42\" hits=\"1\"/>"
|
||||
" <line number=\"44\" hits=\"1\"/>"
|
||||
" <line number=\"45\" hits=\"1\"/>"
|
||||
" <line number=\"46\" hits=\"1\"/>"
|
||||
" <line number=\"47\" hits=\"1\"/>"
|
||||
" <line number=\"49\" hits=\"1\"/>"
|
||||
" <line number=\"50\" hits=\"1\"/>"
|
||||
" <line number=\"51\" hits=\"1\"/>"
|
||||
" <line number=\"52\" hits=\"1\"/>"
|
||||
" <line number=\"54\" hits=\"1\"/>"
|
||||
" <line number=\"55\" hits=\"1\"/>"
|
||||
" <line number=\"56\" hits=\"1\"/>"
|
||||
" <line number=\"57\" hits=\"1\"/>"
|
||||
" <line number=\"59\" hits=\"1\"/>"
|
||||
" <line number=\"66\" hits=\"1\"/>"
|
||||
" <line number=\"68\" hits=\"1\"/>"
|
||||
" <line number=\"75\" hits=\"1\"/>"
|
||||
" <line number=\"78\" hits=\"1\"/>"
|
||||
" </lines>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw line coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetSourceCoverageB_ReturnsValidSourceCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetBSourceModuleCoverages();
|
||||
|
||||
// Given the raw source coverage output of TestTargetB
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617117785\" lines-covered=\"0\" lines-valid=\"0\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetB.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetB.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetB\\Code\\Tests\\TestImpactTestTargetB.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines/>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw source coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetLineCoverageC_ReturnsValidLineCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetCLineModuleCoverages();
|
||||
|
||||
// Given the raw line coverage output of TestTargetC
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617124593\" lines-covered=\"25\" lines-valid=\"25\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetC.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetC.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines>"
|
||||
" <line number=\"32\" hits=\"1\"/>"
|
||||
" <line number=\"33\" hits=\"1\"/>"
|
||||
" <line number=\"34\" hits=\"1\"/>"
|
||||
" <line number=\"35\" hits=\"1\"/>"
|
||||
" <line number=\"37\" hits=\"1\"/>"
|
||||
" <line number=\"38\" hits=\"1\"/>"
|
||||
" <line number=\"39\" hits=\"1\"/>"
|
||||
" <line number=\"40\" hits=\"1\"/>"
|
||||
" <line number=\"42\" hits=\"1\"/>"
|
||||
" <line number=\"43\" hits=\"1\"/>"
|
||||
" <line number=\"44\" hits=\"1\"/>"
|
||||
" <line number=\"45\" hits=\"1\"/>"
|
||||
" <line number=\"47\" hits=\"1\"/>"
|
||||
" <line number=\"48\" hits=\"1\"/>"
|
||||
" <line number=\"49\" hits=\"1\"/>"
|
||||
" <line number=\"50\" hits=\"1\"/>"
|
||||
" <line number=\"52\" hits=\"1\"/>"
|
||||
" <line number=\"53\" hits=\"1\"/>"
|
||||
" <line number=\"54\" hits=\"1\"/>"
|
||||
" <line number=\"55\" hits=\"1\"/>"
|
||||
" <line number=\"57\" hits=\"1\"/>"
|
||||
" <line number=\"58\" hits=\"1\"/>"
|
||||
" <line number=\"59\" hits=\"1\"/>"
|
||||
" <line number=\"60\" hits=\"1\"/>"
|
||||
" <line number=\"63\" hits=\"1\"/>"
|
||||
" </lines>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw line coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetSourceCoverageC_ReturnsValidSourceCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetCSourceModuleCoverages();
|
||||
|
||||
// Given the raw source coverage output of TestTargetC
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617117796\" lines-covered=\"0\" lines-valid=\"0\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetC.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetC.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines/>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw source coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetLineCoverageD_ReturnsValidLineCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetDLineModuleCoverages();
|
||||
|
||||
// Given the raw line coverage output of TestTargetD
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"0.6470588235294118\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617124579\" lines-covered=\"55\" lines-valid=\"85\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetD.Tests.dll\" line-rate=\"0.6470588235294118\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetD.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line-rate=\"0.6470588235294118\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines>"
|
||||
" <line number=\"56\" hits=\"1\"/>"
|
||||
" <line number=\"57\" hits=\"1\"/>"
|
||||
" <line number=\"58\" hits=\"1\"/>"
|
||||
" <line number=\"59\" hits=\"1\"/>"
|
||||
" <line number=\"61\" hits=\"1\"/>"
|
||||
" <line number=\"62\" hits=\"0\"/>"
|
||||
" <line number=\"63\" hits=\"0\"/>"
|
||||
" <line number=\"64\" hits=\"0\"/>"
|
||||
" <line number=\"66\" hits=\"1\"/>"
|
||||
" <line number=\"67\" hits=\"1\"/>"
|
||||
" <line number=\"68\" hits=\"1\"/>"
|
||||
" <line number=\"69\" hits=\"1\"/>"
|
||||
" <line number=\"71\" hits=\"1\"/>"
|
||||
" <line number=\"72\" hits=\"1\"/>"
|
||||
" <line number=\"73\" hits=\"1\"/>"
|
||||
" <line number=\"74\" hits=\"1\"/>"
|
||||
" <line number=\"76\" hits=\"1\"/>"
|
||||
" <line number=\"77\" hits=\"1\"/>"
|
||||
" <line number=\"78\" hits=\"1\"/>"
|
||||
" <line number=\"79\" hits=\"1\"/>"
|
||||
" <line number=\"81\" hits=\"1\"/>"
|
||||
" <line number=\"82\" hits=\"1\"/>"
|
||||
" <line number=\"83\" hits=\"1\"/>"
|
||||
" <line number=\"84\" hits=\"1\"/>"
|
||||
" <line number=\"86\" hits=\"1\"/>"
|
||||
" <line number=\"87\" hits=\"1\"/>"
|
||||
" <line number=\"88\" hits=\"1\"/>"
|
||||
" <line number=\"89\" hits=\"1\"/>"
|
||||
" <line number=\"91\" hits=\"1\"/>"
|
||||
" <line number=\"92\" hits=\"0\"/>"
|
||||
" <line number=\"93\" hits=\"0\"/>"
|
||||
" <line number=\"94\" hits=\"0\"/>"
|
||||
" <line number=\"96\" hits=\"1\"/>"
|
||||
" <line number=\"97\" hits=\"0\"/>"
|
||||
" <line number=\"98\" hits=\"0\"/>"
|
||||
" <line number=\"99\" hits=\"0\"/>"
|
||||
" <line number=\"101\" hits=\"1\"/>"
|
||||
" <line number=\"102\" hits=\"1\"/>"
|
||||
" <line number=\"103\" hits=\"1\"/>"
|
||||
" <line number=\"104\" hits=\"1\"/>"
|
||||
" <line number=\"106\" hits=\"1\"/>"
|
||||
" <line number=\"107\" hits=\"0\"/>"
|
||||
" <line number=\"108\" hits=\"0\"/>"
|
||||
" <line number=\"109\" hits=\"0\"/>"
|
||||
" <line number=\"111\" hits=\"1\"/>"
|
||||
" <line number=\"112\" hits=\"0\"/>"
|
||||
" <line number=\"113\" hits=\"0\"/>"
|
||||
" <line number=\"114\" hits=\"0\"/>"
|
||||
" <line number=\"116\" hits=\"1\"/>"
|
||||
" <line number=\"117\" hits=\"0\"/>"
|
||||
" <line number=\"118\" hits=\"0\"/>"
|
||||
" <line number=\"119\" hits=\"0\"/>"
|
||||
" <line number=\"121\" hits=\"1\"/>"
|
||||
" <line number=\"128\" hits=\"1\"/>"
|
||||
" <line number=\"130\" hits=\"1\"/>"
|
||||
" <line number=\"137\" hits=\"1\"/>"
|
||||
" <line number=\"139\" hits=\"1\"/>"
|
||||
" <line number=\"146\" hits=\"1\"/>"
|
||||
" <line number=\"148\" hits=\"1\"/>"
|
||||
" <line number=\"155\" hits=\"1\"/>"
|
||||
" <line number=\"157\" hits=\"1\"/>"
|
||||
" <line number=\"158\" hits=\"1\"/>"
|
||||
" <line number=\"159\" hits=\"1\"/>"
|
||||
" <line number=\"160\" hits=\"1\"/>"
|
||||
" <line number=\"162\" hits=\"1\"/>"
|
||||
" <line number=\"163\" hits=\"0\"/>"
|
||||
" <line number=\"164\" hits=\"0\"/>"
|
||||
" <line number=\"165\" hits=\"0\"/>"
|
||||
" <line number=\"167\" hits=\"1\"/>"
|
||||
" <line number=\"168\" hits=\"1\"/>"
|
||||
" <line number=\"169\" hits=\"1\"/>"
|
||||
" <line number=\"170\" hits=\"1\"/>"
|
||||
" <line number=\"172\" hits=\"1\"/>"
|
||||
" <line number=\"173\" hits=\"0\"/>"
|
||||
" <line number=\"174\" hits=\"0\"/>"
|
||||
" <line number=\"175\" hits=\"0\"/>"
|
||||
" <line number=\"177\" hits=\"1\"/>"
|
||||
" <line number=\"178\" hits=\"0\"/>"
|
||||
" <line number=\"179\" hits=\"0\"/>"
|
||||
" <line number=\"180\" hits=\"0\"/>"
|
||||
" <line number=\"182\" hits=\"1\"/>"
|
||||
" <line number=\"183\" hits=\"0\"/>"
|
||||
" <line number=\"184\" hits=\"0\"/>"
|
||||
" <line number=\"185\" hits=\"0\"/>"
|
||||
" <line number=\"188\" hits=\"1\"/>"
|
||||
" </lines>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw line coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
|
||||
TEST(CoberturaModuleCoveragesFactory, ParseTestTargetSourceCoverageD_ReturnsValidSourceCoverage)
|
||||
{
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> expectedCoverage = GetTestTargetDSourceModuleCoverages();
|
||||
|
||||
// Given the raw source coverage output of TestTargetD
|
||||
const AZStd::string rawCoverage =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<coverage line-rate=\"1\" branch-rate=\"0\" complexity=\"0\" branches-covered=\"0\" branches-valid=\"0\" timestamp=\"1617117804\" lines-covered=\"0\" lines-valid=\"0\" version=\"0\">"
|
||||
" <sources>"
|
||||
" <source>C:</source>"
|
||||
" </sources>"
|
||||
" <packages>"
|
||||
" <package name=\"C:\\Lumberyard\\windows_vs2019\\bin\\debug\\TestImpact.TestTargetD.Tests.dll\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <classes>"
|
||||
" <class name=\"TestImpactTestTargetD.cpp\" filename=\"Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line-rate=\"1\" branch-rate=\"0\" complexity=\"0\">"
|
||||
" <methods/>"
|
||||
" <lines/>"
|
||||
" </class>"
|
||||
" </classes>"
|
||||
" </package>"
|
||||
" </packages>"
|
||||
"</coverage>"
|
||||
"";
|
||||
|
||||
// When the raw source coverage text is parsed
|
||||
const AZStd::vector<TestImpact::ModuleCoverage> coverage = TestImpact::Cobertura::ModuleCoveragesFactory(rawCoverage);
|
||||
|
||||
// Expect the generated suite data to match that of the raw coverage text
|
||||
EXPECT_TRUE(coverage == expectedCoverage);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Static/TestImpactTargetDescriptorCompiler.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class TargetDescriptorCompilerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
|
||||
m_buildTargetDescriptors.emplace_back(TestImpact::BuildTargetDescriptor{{"TestTargetA", "", ""}, {}});
|
||||
m_buildTargetDescriptors.emplace_back(TestImpact::BuildTargetDescriptor{{"TestTargetB", "", ""}, {}});
|
||||
m_buildTargetDescriptors.emplace_back(TestImpact::BuildTargetDescriptor{{"ProductionTargetA", "", ""}, {}});
|
||||
m_buildTargetDescriptors.emplace_back(TestImpact::BuildTargetDescriptor{{"ProductionTargetB", "", ""}, {}});
|
||||
m_buildTargetDescriptors.emplace_back(TestImpact::BuildTargetDescriptor{{"ProductionTargetC", "", ""}, {}});
|
||||
|
||||
m_testTargetMetaMap.emplace("TestTargetA", TestImpact::TestTargetMeta{"", TestImpact::LaunchMethod::TestRunner});
|
||||
m_testTargetMetaMap.emplace("TestTargetB", TestImpact::TestTargetMeta{"", TestImpact::LaunchMethod::StandAlone});
|
||||
}
|
||||
|
||||
protected:
|
||||
AZStd::vector<TestImpact::BuildTargetDescriptor> m_buildTargetDescriptors;
|
||||
TestImpact::TestTargetMetaMap m_testTargetMetaMap;
|
||||
};
|
||||
|
||||
TestImpact::ProductionTargetDescriptor ConstructProductionTargetDescriptor(const AZStd::string& name)
|
||||
{
|
||||
return TestImpact::ProductionTargetDescriptor{TestImpact::BuildTargetDescriptor{{name, "", ""}, {{}, {}}}};
|
||||
}
|
||||
|
||||
TestImpact::TestTargetDescriptor ConstructTestTargetDescriptor(const AZStd::string& name, TestImpact::LaunchMethod launchMethod)
|
||||
{
|
||||
return TestImpact::TestTargetDescriptor{
|
||||
TestImpact::BuildTargetDescriptor{{name, "", ""}, {{}, {}}}, TestImpact::TestTargetMeta{"", launchMethod}};
|
||||
}
|
||||
|
||||
TEST_F(TargetDescriptorCompilerTestFixture, EmptyBuildTargetDescriptorList_ExpectArtifactException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Given an empty build target descriptor list but valid test target meta map
|
||||
// When attempting to construct the test target
|
||||
const auto& [productionTargetDescriptors, testTargetDescriptors] =
|
||||
TestImpact::CompileTargetDescriptors({}, AZStd::move(m_testTargetMetaMap));
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TargetDescriptorCompilerTestFixture, EmptyTestTargetMetaMap_ExpectArtifactException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Given a valid build target descriptor list but empty test target meta map
|
||||
// When attempting to construct the test target
|
||||
const auto& [productionTargetDescriptors, testTargetDescriptors] =
|
||||
TestImpact::CompileTargetDescriptors(AZStd::move(m_buildTargetDescriptors), {});
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TargetDescriptorCompilerTestFixture, TestTargetWithNoMatchingMeta_ExpectArtifactException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Given a valid build target descriptor list but a test target meta map with an orphan entry
|
||||
m_testTargetMetaMap.emplace("Orphan", TestImpact::TestTargetMeta{"", TestImpact::LaunchMethod::TestRunner});
|
||||
|
||||
// When attempting to construct the test target
|
||||
const auto& [productionTargetDescriptors, testTargetDescriptors] =
|
||||
TestImpact::CompileTargetDescriptors(AZStd::move(m_buildTargetDescriptors), {});
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TargetDescriptorCompilerTestFixture, ValidProductionTargetsAndTestTargetMetas_ExpectValidProductionAndTestTargets)
|
||||
{
|
||||
// Given a valid build target descriptor list and a valid test target meta map
|
||||
// When attempting to construct the test target
|
||||
const auto& [productionTargetDescriptors, testTargetDescriptors] =
|
||||
TestImpact::CompileTargetDescriptors(AZStd::move(m_buildTargetDescriptors), AZStd::move(m_testTargetMetaMap));
|
||||
|
||||
// Expect the production targets to match the expected targets
|
||||
EXPECT_TRUE(productionTargetDescriptors.size() == 3);
|
||||
EXPECT_TRUE(productionTargetDescriptors[0] == ConstructProductionTargetDescriptor("ProductionTargetA"));
|
||||
EXPECT_TRUE(productionTargetDescriptors[1] == ConstructProductionTargetDescriptor("ProductionTargetB"));
|
||||
EXPECT_TRUE(productionTargetDescriptors[2] == ConstructProductionTargetDescriptor("ProductionTargetC"));
|
||||
|
||||
// Expect the test targets to match the expected targets
|
||||
EXPECT_TRUE(testTargetDescriptors.size() == 2);
|
||||
EXPECT_TRUE(testTargetDescriptors[0] == ConstructTestTargetDescriptor("TestTargetA", TestImpact::LaunchMethod::TestRunner));
|
||||
EXPECT_TRUE(testTargetDescriptors[1] == ConstructTestTargetDescriptor("TestTargetB", TestImpact::LaunchMethod::StandAlone));
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,589 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestEnumerationSuiteFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST(GTestEnumerationSuiteFactory, ParseEmptyString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an empty string
|
||||
const AZStd::string rawEnum;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the empty suite
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GTestEnumerationSuiteFactory, ParseInvalidString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an invalid string
|
||||
const AZStd::string rawEnum = "!@?";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the empty suite
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GTestEnumerationSuiteFactory, ParseTestTargetA_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> expectedSuites = GetTestTargetATestEnumerationSuites();
|
||||
|
||||
// Given the raw enum output of TestTargetA
|
||||
const AZStd::string rawEnum =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<testsuites tests=\"10\" name=\"AllTests\">\n"
|
||||
" <testsuite name=\"TestCase\" tests=\"7\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"22\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"27\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"32\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"37\" />\n"
|
||||
" <testcase name=\"Test5_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"42\" />\n"
|
||||
" <testcase name=\"Test6_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"47\" />\n"
|
||||
" <testcase name=\"Test7_WillFail\" file=\"C:\\Tests\\TestImpactTestTargetA.cpp\" line=\"52\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixture\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp\" line=\"57\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp\" line=\"62\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" file=\"C:\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp\" line=\"67\" />\n"
|
||||
" </testsuite>\n"
|
||||
"</testsuites>\n"
|
||||
"\n";
|
||||
|
||||
// When the raw enumeration text is parsed
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Expect the generated suite data to match that of the raw enum text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestEnumerationSuiteFactory, ParseTestTargetB_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> expectedSuites = GetTestTargetBTestEnumerationSuites();
|
||||
|
||||
// Given the raw enum output of TestTargetB
|
||||
const AZStd::string rawEnum =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<testsuites tests=\"112\" name=\"AllTests\">\n"
|
||||
" <testsuite name=\"TestCase\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"29\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"34\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"39\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixture\" tests=\"1\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"44\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"PermutationA/TestFixtureWithParams\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithParams\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" <testcase name=\"Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestImpactTestTargetB.cpp\" line=\"49\" />\n"
|
||||
" </testsuite>\n"
|
||||
"</testsuites>\n"
|
||||
"\n";
|
||||
|
||||
// When the raw enumeration text is parsed
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Expect the generated suite data to match that of the raw enum text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestEnumerationSuiteFactory, ParseTestTargetC_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> expectedSuites = GetTestTargetCTestEnumerationSuites();
|
||||
|
||||
// Given the raw enum output of TestTargetC
|
||||
const AZStd::string rawEnum =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<testsuites tests=\"18\" name=\"AllTests\">\n"
|
||||
" <testsuite name=\"TestFixture\" tests=\"2\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"32\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"37\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes/0\" tests=\"4\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"42\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"47\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"52\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"57\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes/1\" tests=\"4\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"42\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"47\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"52\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"57\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes/2\" tests=\"4\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"42\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"47\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"52\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"57\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes/3\" tests=\"4\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"42\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"47\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"52\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetC\\Code\\Tests\\TestImpactTestTargetC.cpp\" line=\"57\" />\n"
|
||||
" </testsuite>\n"
|
||||
"</testsuites>\n"
|
||||
"\n";
|
||||
|
||||
// When the raw enumeration text is parsed
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Expect the generated suite data to match that of the raw enum text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestEnumerationSuiteFactory, ParseTestTargetD_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> expectedSuites = GetTestTargetDTestEnumerationSuites();
|
||||
|
||||
// Given the raw enum output of TestTargetD
|
||||
const AZStd::string rawEnum =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<testsuites tests=\"249\" name=\"AllTests\">\n"
|
||||
" <testsuite name=\"TestCase\" tests=\"5\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"56\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"61\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"66\" />\n"
|
||||
" <testcase name=\"Test4_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"71\" />\n"
|
||||
" <testcase name=\"Test5_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"76\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixture1\" tests=\"2\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"81\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"86\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixture2\" tests=\"2\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"91\" />\n"
|
||||
" <testcase name=\"Test2_WillPass\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"96\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/0\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"157\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"162\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"167\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/1\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"157\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"162\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"167\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/2\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"157\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"162\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"167\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/3\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"157\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"162\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"167\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/0\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"172\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"177\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"182\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/1\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"172\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"177\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"182\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/2\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"172\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"177\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"182\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/3\" tests=\"3\">\n"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"172\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"177\" />\n"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"182\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"PermutationA/TestFixtureWithParams1\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"TestFixtureWithParams1\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"101\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"PermutationA/DISABLED_TestFixtureWithParams2\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" </testsuite>\n"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithParams2\" tests=\"54\">\n"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" file=\"C:\\Tests\\TestTargetD\\Code\\Tests\\TestImpactTestTargetD.cpp\" line=\"111\" />\n"
|
||||
" </testsuite>\n"
|
||||
"</testsuites>\n"
|
||||
"\n";
|
||||
|
||||
// When the raw enumeration text is parsed
|
||||
const AZStd::vector<TestImpact::TestEnumerationSuite> suites = TestImpact::GTest::TestEnumerationSuitesFactory(rawEnum);
|
||||
|
||||
// Expect the generated suite data to match that of the raw enum text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestRunSuiteFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST(GTestRunSuiteFactory, ParseEmptyString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an empty string
|
||||
const AZStd::string rawRun;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the empty suite
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect a artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GTestRunSuiteFactory, ParseInvalidString_ThrowsArtifactException)
|
||||
{
|
||||
// Given an invalid string
|
||||
const AZStd::string rawRun = "!@?";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to parse the invalid suite
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Do not expect the parsing to succeed
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect a artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GTestRunSuiteFactory, ParseTestTargetA_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestRunSuite> expectedSuites = GetTestTargetATestRunSuites();
|
||||
|
||||
// Given the raw run output of TestTargetA
|
||||
const AZStd::string rawRun =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<testsuites tests=\"10\" failures=\"1\" disabled=\"0\" errors=\"0\" timestamp=\"2021-03-26T19:02:37\" time=\"0.051\" name=\"AllTests\">"
|
||||
" <testsuite name=\"TestCase\" tests=\"7\" failures=\"1\" disabled=\"0\" errors=\"0\" time=\"0.003\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test3_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test4_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test5_WillPass\" status=\"run\" time=\"0.001\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test6_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test7_WillFail\" status=\"run\" time=\"0.001\" classname=\"TestCase\">"
|
||||
" <failure message=\"C:\\Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp:54
Failed\" type=\"\"><![CDATA[C:\\Lumberyard\\Code\\Tools\\TestImpactFramework\\Runtime\\Code\\Tests\\TestTargetA\\Code\\Tests\\TestImpactTestTargetA.cpp:54"
|
||||
"Failed]]></failure>"
|
||||
" </testcase>"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixture\" tests=\"3\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.038\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.004\" classname=\"TestFixture\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"run\" time=\"0\" classname=\"TestFixture\" />"
|
||||
" <testcase name=\"Test3_WillPass\" status=\"run\" time=\"0.001\" classname=\"TestFixture\" />"
|
||||
" </testsuite>"
|
||||
"</testsuites>"
|
||||
"";
|
||||
|
||||
// When the raw run text is parsed
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Expect the generated suite data to match that of the raw run text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestRunSuiteFactory, ParseTestTargetB_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestRunSuite> expectedSuites = GetTestTargetBTestRunSuites();
|
||||
|
||||
// Given the raw run output of TestTargetB
|
||||
const AZStd::string rawRun =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<testsuites tests=\"112\" failures=\"0\" disabled=\"0\" errors=\"0\" timestamp=\"2021-03-27T11:56:14\" time=\"7.155\" name=\"AllTests\">"
|
||||
" <testsuite name=\"TestCase\" tests=\"3\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.202\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.003\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test3_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixture\" tests=\"1\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.062\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.005\" classname=\"TestFixture\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"PermutationA/TestFixtureWithParams\" tests=\"54\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"3.203\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithParams\" tests=\"54\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"3.36\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"run\" time=\"0.002\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" <testcase name=\"Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams\" />"
|
||||
" </testsuite>"
|
||||
"</testsuites>"
|
||||
"";
|
||||
|
||||
// When the raw run text is parsed
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Expect the generated suite data to match that of the raw run text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestRunSuiteFactory, ParseTestTargetC_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestRunSuite> expectedSuites = GetTestTargetCTestRunSuites();
|
||||
|
||||
// Given the raw run output of TestTargetC
|
||||
const AZStd::string rawRun =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<testsuites tests=\"18\" failures=\"0\" disabled=\"0\" errors=\"0\" timestamp=\"2021-03-27T12:35:40\" time=\"1.022\" name=\"AllTests\">"
|
||||
" <testsuite name=\"TestFixture\" tests=\"2\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.125\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.004\" classname=\"TestFixture\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"run\" time=\"0\" classname=\"TestFixture\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes/0\" tests=\"4\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.21\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/0\" />"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"int\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes/0\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes/0\" />"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"int\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes/0\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes/1\" tests=\"4\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.208\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes/1\" />"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"float\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes/1\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/1\" />"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"float\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes/2\" tests=\"4\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.199\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/2\" />"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/2\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/2\" />"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/2\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes/3\" tests=\"4\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.049\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/3\" />"
|
||||
" <testcase name=\"Test2_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/3\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/3\" />"
|
||||
" <testcase name=\"Test4_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes/3\" />"
|
||||
" </testsuite>"
|
||||
"</testsuites>"
|
||||
"";
|
||||
|
||||
// When the raw run text is parsed
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Expect the generated suite data to match that of the raw run text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
|
||||
TEST(GTestRunSuiteFactory, ParseTestTargetD_ReturnsValidSuitesAndTests)
|
||||
{
|
||||
const AZStd::vector<TestImpact::TestRunSuite> expectedSuites = GetTestTargetDTestRunSuites();
|
||||
|
||||
// Given the raw run output of TestTargetD
|
||||
const AZStd::string rawRun =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<testsuites tests=\"249\" failures=\"0\" disabled=\"181\" errors=\"0\" timestamp=\"2021-03-25T15:18:40\" time=\"0.314\" name=\"AllTests\">"
|
||||
" <testsuite name=\"TestCase\" tests=\"5\" failures=\"0\" disabled=\"1\" errors=\"0\" time=\"0.003\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.001\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" status=\"notrun\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test3_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test4_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" <testcase name=\"Test5_WillPass\" status=\"run\" time=\"0\" classname=\"TestCase\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixture1\" tests=\"2\" failures=\"0\" disabled=\"0\" errors=\"0\" time=\"0.004\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"run\" time=\"0.002\" classname=\"TestFixture1\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"run\" time=\"0\" classname=\"TestFixture1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixture2\" tests=\"2\" failures=\"0\" disabled=\"2\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixture2\" />"
|
||||
" <testcase name=\"Test2_WillPass\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixture2\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/0\" tests=\"3\" failures=\"0\" disabled=\"1\" errors=\"0\" time=\"0.001\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/0\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"int\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithTypes1/0\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/0\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/1\" tests=\"3\" failures=\"0\" disabled=\"1\" errors=\"0\" time=\"0.003\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithTypes1/1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"float\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithTypes1/1\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/2\" tests=\"3\" failures=\"0\" disabled=\"1\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"double\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithTypes1/2\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/2\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithTypes1/3\" tests=\"3\" failures=\"0\" disabled=\"1\" errors=\"0\" time=\"0.001\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/3\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"char\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithTypes1/3\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" status=\"run\" time=\"0\" classname=\"TestFixtureWithTypes1/3\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/0\" tests=\"3\" failures=\"0\" disabled=\"3\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"int\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/0\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"int\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/0\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"int\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/0\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/1\" tests=\"3\" failures=\"0\" disabled=\"3\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"float\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"float\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/1\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"float\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/2\" tests=\"3\" failures=\"0\" disabled=\"3\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"double\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"double\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/2\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"double\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/2\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithTypes2/3\" tests=\"3\" failures=\"0\" disabled=\"3\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass\" type_param=\"char\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/3\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass\" type_param=\"char\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/3\" />"
|
||||
" <testcase name=\"Test3_WillPass\" type_param=\"char\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithTypes2/3\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"PermutationA/TestFixtureWithParams1\" tests=\"54\" failures=\"0\" disabled=\"27\" errors=\"0\" time=\"0.173\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"run\" time=\"0.001\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"run\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/TestFixtureWithParams1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"TestFixtureWithParams1\" tests=\"54\" failures=\"0\" disabled=\"27\" errors=\"0\" time=\"0.102\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"run\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"run\" time=\"0.001\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"TestFixtureWithParams1\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"PermutationA/DISABLED_TestFixtureWithParams2\" tests=\"54\" failures=\"0\" disabled=\"54\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(1, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(1, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(1, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(1, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(1, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(1, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(1, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(1, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(1, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(2, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(2, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(2, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(2, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(2, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(2, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(2, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(2, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(2, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(4, '\\x3' (3), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(4, '\\x3' (3), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(4, '\\x3' (3), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(4, '\\x5' (5), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(4, '\\x5' (5), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(4, '\\x5' (5), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(4, '\\a' (7), -0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(4, '\\a' (7), 0)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(4, '\\a' (7), 1)\" status=\"notrun\" time=\"0\" classname=\"PermutationA/DISABLED_TestFixtureWithParams2\" />"
|
||||
" </testsuite>"
|
||||
" <testsuite name=\"DISABLED_TestFixtureWithParams2\" tests=\"54\" failures=\"0\" disabled=\"54\" errors=\"0\" time=\"0\">"
|
||||
" <testcase name=\"Test1_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"Test1_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/0\" value_param=\"(8, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/1\" value_param=\"(8, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/2\" value_param=\"(8, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/3\" value_param=\"(8, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/4\" value_param=\"(8, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/5\" value_param=\"(8, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/6\" value_param=\"(8, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/7\" value_param=\"(8, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/8\" value_param=\"(8, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/9\" value_param=\"(16, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/10\" value_param=\"(16, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/11\" value_param=\"(16, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/12\" value_param=\"(16, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/13\" value_param=\"(16, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/14\" value_param=\"(16, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/15\" value_param=\"(16, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/16\" value_param=\"(16, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/17\" value_param=\"(16, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/18\" value_param=\"(32, '\\t' (9), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/19\" value_param=\"(32, '\\t' (9), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/20\" value_param=\"(32, '\\t' (9), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/21\" value_param=\"(32, '\\r' (13, 0xD), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/22\" value_param=\"(32, '\\r' (13, 0xD), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/23\" value_param=\"(32, '\\r' (13, 0xD), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/24\" value_param=\"(32, '\\x11' (17), -10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/25\" value_param=\"(32, '\\x11' (17), 0.05)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" <testcase name=\"DISABLED_Test2_WillPass/26\" value_param=\"(32, '\\x11' (17), 10)\" status=\"notrun\" time=\"0\" classname=\"DISABLED_TestFixtureWithParams2\" />"
|
||||
" </testsuite>"
|
||||
"</testsuites>"
|
||||
"";
|
||||
|
||||
// When the raw run text is parsed
|
||||
const AZStd::vector<TestImpact::TestRunSuite> suites = TestImpact::GTest::TestRunSuitesFactory(rawRun);
|
||||
|
||||
// Expect the generated suite data to match that of the raw run text
|
||||
EXPECT_TRUE(suites == expectedSuites);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Artifact/Factory/TestImpactTestTargetMetaMapFactory.h>
|
||||
#include <Artifact/TestImpactArtifactException.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST(TestTargetMetaMapFactoryTest, NoRawData_ExpectArtifactException)
|
||||
{
|
||||
// Given an empty meta data string
|
||||
const AZStd::string rawTestTargetMetaData;
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, InvalidRawData_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw meta data string of invalid data
|
||||
const AZStd::string rawTestTargetMetaData = "abcde";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, EmptyTestMetaArray_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw meta data string of valid JSON that contains no tests
|
||||
const AZStd::string rawTestTargetMetaData =
|
||||
"{"
|
||||
" \"google\": {"
|
||||
" \"test\": {"
|
||||
" \"tests\": ["
|
||||
" ]"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, EmptyName_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw meta data string with a test that has no name value
|
||||
const AZStd::string rawTestTargetMetaData =
|
||||
"{"
|
||||
" \"google\": {"
|
||||
" \"test\": {"
|
||||
" \"tests\": ["
|
||||
" { \"name\": \"\", \"namespace\": \"Legacy\", \"suite\": \"main\", \"launch_method\": \"test_runner\" }"
|
||||
" ]"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, EmptyBuildType_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw meta data string with a test that has no build type
|
||||
const AZStd::string rawTestTargetMetaData =
|
||||
"{"
|
||||
" \"google\": {"
|
||||
" \"test\": {"
|
||||
" \"tests\": ["
|
||||
" { \"name\": \"TestName\", \"namespace\": \"Legacy\", \"suite\": \"main\", \"launch_method\": \"\" }"
|
||||
" ]"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, InvalidBuildType_ExpectArtifactException)
|
||||
{
|
||||
// Given a raw meta data string with a test that has an invalid build type
|
||||
const AZStd::string rawTestTargetMetaData =
|
||||
"{"
|
||||
" \"google\": {"
|
||||
" \"test\": {"
|
||||
" \"tests\": ["
|
||||
" { \"name\": \"TestName\", \"namespace\": \"Legacy\", \"suite\": \"main\", \"launch_method\": \"Unknown\" }"
|
||||
" ]"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
try
|
||||
{
|
||||
// When attempting to construct the test target
|
||||
const TestImpact::TestTargetMetaMap testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Do not expect this statement to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ArtifactException& e)
|
||||
{
|
||||
// Expect an artifact exception
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTargetMetaMapFactoryTest, ValidMetaData_ExpectValidTestMetaData)
|
||||
{
|
||||
// Given a raw meta data string valid test meta-data
|
||||
const AZStd::string rawTestTargetMetaData =
|
||||
"{"
|
||||
" \"google\": {"
|
||||
" \"test\": {"
|
||||
" \"tests\": ["
|
||||
" { \"name\": \"TestA\", \"namespace\": \"Legacy\", \"suite\": \"main\", \"launch_method\": \"test_runner\" },"
|
||||
" { \"name\": \"TestB\", \"namespace\": \"\", \"suite\": \"main\", \"launch_method\": \"test_runner\" },"
|
||||
" { \"name\": \"TestC\", \"namespace\": \"\", \"suite\": \"\", \"launch_method\": \"test_runner\" },"
|
||||
" { \"name\": \"TestD\", \"namespace\": \"Legacy\", \"suite\": \"main\", \"launch_method\": \"stand_alone\" }"
|
||||
" ]"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
// When attempting to construct the test target
|
||||
const auto testTargetMetaData = TestImpact::TestTargetMetaMapFactory(rawTestTargetMetaData);
|
||||
|
||||
// Expect the constructed test meta-data to match that of the supplied raw data
|
||||
EXPECT_EQ(testTargetMetaData.size(), 4);
|
||||
EXPECT_TRUE(testTargetMetaData.find("TestA") != testTargetMetaData.end());
|
||||
EXPECT_TRUE((testTargetMetaData.at("TestA") == TestImpact::TestTargetMeta{"main", TestImpact::LaunchMethod::TestRunner}));
|
||||
EXPECT_TRUE(testTargetMetaData.find("TestB") != testTargetMetaData.end());
|
||||
EXPECT_TRUE((testTargetMetaData.at("TestB") == TestImpact::TestTargetMeta{"main", TestImpact::LaunchMethod::TestRunner}));
|
||||
EXPECT_TRUE(testTargetMetaData.find("TestC") != testTargetMetaData.end());
|
||||
EXPECT_TRUE((testTargetMetaData.at("TestC") == TestImpact::TestTargetMeta{"", TestImpact::LaunchMethod::TestRunner}));
|
||||
EXPECT_TRUE(testTargetMetaData.find("TestD") != testTargetMetaData.end());
|
||||
EXPECT_TRUE((testTargetMetaData.at("TestD") == TestImpact::TestTargetMeta{"main", TestImpact::LaunchMethod::StandAlone}));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,718 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Process/Scheduler/TestImpactProcessScheduler.h>
|
||||
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using SchedulerPermutation = AZStd::tuple
|
||||
<
|
||||
size_t, // Number of concurrent processes
|
||||
size_t // Number of processes to launch
|
||||
>;
|
||||
|
||||
class ProcessSchedulerTestFixtureWithParams
|
||||
: public AllocatorsTestFixture
|
||||
, private AZ::Debug::TraceMessageBus::Handler
|
||||
, public ::testing::WithParamInterface<SchedulerPermutation>
|
||||
{
|
||||
private:
|
||||
bool OnOutput(const char*, const char*) override;
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
protected:
|
||||
void ConfigurePermutation();
|
||||
void ExpectSuccessfulLaunch(TestImpact::ProcessId pid);
|
||||
void ExpectGracefulExit(TestImpact::ProcessId pid);
|
||||
void ExpectUnsuccessfulLaunch(TestImpact::ProcessId pid);
|
||||
void ExpectExitCondition(
|
||||
TestImpact::ProcessId pid, AZStd::optional<TestImpact::ExitCondition> expectedExitCondition = AZStd::nullopt);
|
||||
void DoNotExpectExitCondition(TestImpact::ProcessId pid);
|
||||
void ExpectTerminatedProcess(TestImpact::ProcessId pid);
|
||||
void ExpectTimeoutProcess(TestImpact::ProcessId pid);
|
||||
void ExpectUnlaunchedProcess(TestImpact::ProcessId pid);
|
||||
void ExpectLargeStdOutput(TestImpact::ProcessId pid);
|
||||
void ExpectLargeStdError(TestImpact::ProcessId pid);
|
||||
void ExpectSmallStdOutput(TestImpact::ProcessId pid);
|
||||
void ExpectSmallStdError(TestImpact::ProcessId pid);
|
||||
void DoNotExpectStdOutput(TestImpact::ProcessId pid);
|
||||
void DoNotExpectStdError(TestImpact::ProcessId pid);
|
||||
|
||||
struct ProcessResult
|
||||
{
|
||||
AZStd::optional<TestImpact::LaunchResult> m_launchResult;
|
||||
AZStd::optional<TestImpact::ExitCondition> m_exitStatus;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point> m_createTime;
|
||||
AZStd::optional<AZStd::chrono::high_resolution_clock::time_point> m_exitTime;
|
||||
AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds(0);
|
||||
AZStd::optional<TestImpact::ReturnCode> m_returnCode;
|
||||
TestImpact::StdContent m_std;
|
||||
};
|
||||
|
||||
size_t m_numMaxConcurrentProcesses = 0;
|
||||
size_t m_numProcessesToLaunch = 0;
|
||||
|
||||
AZStd::unique_ptr<TestImpact::ProcessScheduler> m_processScheduler;
|
||||
TestImpact::ProcessLaunchCallback m_processLaunchCallback;
|
||||
TestImpact::ProcessExitCallback m_processExitCallback;
|
||||
AZStd::vector<TestImpact::ProcessInfo> m_processInfos;
|
||||
AZStd::vector<ProcessResult> m_processResults;
|
||||
};
|
||||
|
||||
// Permutation values for small process batches
|
||||
const std::vector<size_t> SmallNumMaxConcurrentProcesses = {1, 4, 8};
|
||||
const std::vector<size_t> SmallNumProcessesToLaunch = {1, 8, 32};
|
||||
|
||||
// Permutation values for large process batches
|
||||
const std::vector<size_t> LargeNumMaxConcurrentProcesses = {16, 32, 64};
|
||||
const std::vector<size_t> LargeNumProcessesToLaunch = {128, 256, 512};
|
||||
|
||||
void ProcessSchedulerTestFixtureWithParams::ConfigurePermutation()
|
||||
{
|
||||
const auto& [numMaxConcurrentProcesses, numProcessesToLaunch] = GetParam();
|
||||
m_numMaxConcurrentProcesses = numMaxConcurrentProcesses;
|
||||
m_numProcessesToLaunch = numProcessesToLaunch;
|
||||
}
|
||||
|
||||
// Consume AZ log spam
|
||||
bool ProcessSchedulerTestFixtureWithParams::OnOutput([[maybe_unused]] const char*, [[maybe_unused]] const char*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessSchedulerTestFixtureWithParams::SetUp()
|
||||
{
|
||||
UnitTest::AllocatorsTestFixture::SetUp();
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
ConfigurePermutation();
|
||||
|
||||
m_processLaunchCallback = [this](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)
|
||||
{
|
||||
m_processResults[pid].m_launchResult = launchResult;
|
||||
m_processResults[pid].m_createTime.emplace(createTime);
|
||||
return TestImpact::CallbackResult::Continue;
|
||||
};
|
||||
|
||||
m_processExitCallback = [this](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::ExitCondition exitStatus,
|
||||
TestImpact::ReturnCode returnCode,
|
||||
TestImpact::StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)
|
||||
{
|
||||
m_processResults[pid].m_std = std::move(std);
|
||||
m_processResults[pid].m_returnCode.emplace(returnCode);
|
||||
m_processResults[pid].m_exitStatus = exitStatus;
|
||||
m_processResults[pid].m_exitTime = exitTime;
|
||||
m_processResults[pid].m_duration =
|
||||
AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(exitTime - *m_processResults[pid].m_createTime);
|
||||
return TestImpact::CallbackResult::Continue;
|
||||
};
|
||||
|
||||
m_processResults.resize(m_numProcessesToLaunch);
|
||||
}
|
||||
|
||||
void ProcessSchedulerTestFixtureWithParams::TearDown()
|
||||
{
|
||||
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
|
||||
UnitTest::AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
// Expects the process to have exited under the specified circumstances
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectExitCondition(
|
||||
TestImpact::ProcessId pid, AZStd::optional<TestImpact::ExitCondition> expectedExitCondition)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
// Expect the processes to have exited
|
||||
EXPECT_TRUE(exitStatus.has_value());
|
||||
|
||||
// Expect the return code to be valid
|
||||
EXPECT_TRUE(returnCode.has_value());
|
||||
|
||||
if (expectedExitCondition.has_value())
|
||||
{
|
||||
// Expect the process to have exited under the specified conditions
|
||||
EXPECT_EQ(exitStatus, expectedExitCondition);
|
||||
|
||||
// Expect the return code to be that of the process's is (for gracefull exists) or that of the error code
|
||||
// associated with the abnormal exit condition
|
||||
EXPECT_EQ(returnCode,
|
||||
expectedExitCondition == TestImpact::ExitCondition::Gracefull
|
||||
? pid
|
||||
: static_cast<TestImpact::ReturnCode>(*exitStatus));
|
||||
}
|
||||
|
||||
// Expect the duration to be non zero and the create time and exit time to have values as the processes has been in-flight
|
||||
EXPECT_GT(duration.count(), 0);
|
||||
EXPECT_TRUE(createTime.has_value());
|
||||
EXPECT_TRUE(exitTime.has_value());
|
||||
|
||||
// Expect the exit time to be later than the start time
|
||||
EXPECT_GT(exitTime, createTime);
|
||||
}
|
||||
|
||||
// Expects the process to not have exited for to lack of being in-flight
|
||||
void ProcessSchedulerTestFixtureWithParams::DoNotExpectExitCondition(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
// Expect the processes to not have exited as the process has not been launched successfully
|
||||
EXPECT_FALSE(exitStatus.has_value());
|
||||
|
||||
// Expect the return code to be invalid
|
||||
EXPECT_FALSE(returnCode.has_value());
|
||||
|
||||
// Expect the duration to be zero as the process has not been in-flight
|
||||
EXPECT_EQ(duration.count(), 0);
|
||||
|
||||
// Do not expect the exit time to have a value
|
||||
EXPECT_FALSE(exitTime.has_value());
|
||||
}
|
||||
|
||||
// Expects the process to have been launched successfully, makes no assumptions about how it exited
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectSuccessfulLaunch(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
// Expect a launch to have been attempted by this process (not still in queue)
|
||||
EXPECT_TRUE(launchResult.has_value());
|
||||
|
||||
// Expect the process to have launched successfully
|
||||
EXPECT_EQ(launchResult, TestImpact::LaunchResult::Success);
|
||||
}
|
||||
|
||||
// Expects the process to have failed to launch
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectUnsuccessfulLaunch(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
// Expect a launch to have been attempted by this process (not still in queue)
|
||||
EXPECT_TRUE(launchResult.has_value());
|
||||
|
||||
// Expect the process to have launched unsuccessfully
|
||||
EXPECT_EQ(launchResult, TestImpact::LaunchResult::Failure);
|
||||
|
||||
// Expect the create time to have a value as the process was technically created
|
||||
EXPECT_TRUE(createTime.has_value());
|
||||
|
||||
DoNotExpectExitCondition(pid);
|
||||
}
|
||||
|
||||
// Expects the process to have exited gracefully of its own accord (i.e. not terminated for any reason by the scheduler)
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectGracefulExit(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
ExpectExitCondition(pid, TestImpact::ExitCondition::Gracefull);
|
||||
}
|
||||
|
||||
// Expects the process to have been terminated by the client or scheduler
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectTerminatedProcess(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
ExpectExitCondition(pid, TestImpact::ExitCondition::Terminated);
|
||||
}
|
||||
|
||||
// Expects the process to have been terminated by the scheduler due to the process or scheduler timing out
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectTimeoutProcess(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
ExpectExitCondition(pid, TestImpact::ExitCondition::Timeout);
|
||||
}
|
||||
|
||||
// Expects the process to have not been attempted to launch (was still in the queue)
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectUnlaunchedProcess(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& [launchResult, exitStatus, createTime, exitTime, duration, returnCode, std] = m_processResults[pid];
|
||||
|
||||
// Expect a launch to not have been attempted by this process (still in queue)
|
||||
EXPECT_FALSE(launchResult.has_value());
|
||||
|
||||
// Expect the create time to have a value as the process was technically created
|
||||
EXPECT_FALSE(createTime.has_value());
|
||||
|
||||
DoNotExpectExitCondition(pid);
|
||||
}
|
||||
|
||||
// Expects the std output to have been captured from the process with a large volume of text
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectLargeStdOutput(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdOut = m_processResults[pid].m_std.m_out;
|
||||
|
||||
// Expect standard output to have a value
|
||||
EXPECT_TRUE(stdOut.has_value());
|
||||
|
||||
// Expect the output length to be that of the large text output from the child process
|
||||
EXPECT_EQ(stdOut.value().length(), LargeTextSize);
|
||||
}
|
||||
|
||||
// Expects the std error to have been captured from the process with a large volume of text
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectLargeStdError(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdErr = m_processResults[pid].m_std.m_err;
|
||||
|
||||
// Expect standard error to have a value
|
||||
EXPECT_TRUE(stdErr.has_value());
|
||||
|
||||
// Expect the error length to be that of the large text output from the child process
|
||||
EXPECT_EQ(stdErr.value().length(), LargeTextSize);
|
||||
}
|
||||
|
||||
// Expects the std output to have been captured from the process with a small known text string
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectSmallStdOutput(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdOut = m_processResults[pid].m_std.m_out;
|
||||
|
||||
// Expect standard output to have a value
|
||||
EXPECT_TRUE(stdOut.has_value());
|
||||
|
||||
// Expect the output to match the known stdout of the child
|
||||
EXPECT_EQ(stdOut.value(), KnownTestProcessOutputString(pid));
|
||||
}
|
||||
|
||||
// Expects the std error to have been captured from the process with a small known text string
|
||||
void ProcessSchedulerTestFixtureWithParams::ExpectSmallStdError(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdErr = m_processResults[pid].m_std.m_err;
|
||||
|
||||
// Expect standard error to have a value
|
||||
EXPECT_TRUE(stdErr.has_value());
|
||||
|
||||
// Expect the output to match the known stderr of the child
|
||||
EXPECT_EQ(stdErr.value(), KnownTestProcessErrorString(pid));
|
||||
}
|
||||
|
||||
// Expects no standard output from the child process
|
||||
void ProcessSchedulerTestFixtureWithParams::DoNotExpectStdOutput(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdOut = m_processResults[pid].m_std.m_out;
|
||||
|
||||
// Do not expect standard output to have a value
|
||||
EXPECT_FALSE(stdOut.has_value());
|
||||
}
|
||||
|
||||
// Expects no standard error from the child process
|
||||
void ProcessSchedulerTestFixtureWithParams::DoNotExpectStdError(TestImpact::ProcessId pid)
|
||||
{
|
||||
const auto& stdErr = m_processResults[pid].m_std.m_err;
|
||||
|
||||
// Do not expect standard error to have a value
|
||||
EXPECT_FALSE(stdErr.has_value());
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, ValidProcesses_SuccessfulLaunches)
|
||||
{
|
||||
// Given a set of processes to launch with valid arguments
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
ExpectGracefulExit(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, ValidAndInvalidProcesses_LaunchSuccessesAndFailures)
|
||||
{
|
||||
const size_t invalidProcessGroup = 4;
|
||||
|
||||
// Given a mixture of processes to launch with valid and invalid arguments
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid % invalidProcessGroup == 0)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
InvalidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid % invalidProcessGroup == 0)
|
||||
{
|
||||
ExpectUnsuccessfulLaunch(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectGracefulExit(pid);
|
||||
}
|
||||
|
||||
DoNotExpectStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, ProcessTimeouts_InFlightProcessesTimeout)
|
||||
{
|
||||
const size_t timeoutProcessGroup = 4;
|
||||
|
||||
// Given a mixture of processes to launch with some processes sleeping indefinately
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid % timeoutProcessGroup == 0)
|
||||
{
|
||||
m_processInfos.emplace_back(pid, ValidProcessPath, ConstructTestProcessArgs(pid, LongSleep));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_processInfos.emplace_back(pid, ValidProcessPath, ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes with a process timeout value
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::chrono::milliseconds(100),
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid % timeoutProcessGroup == 0)
|
||||
{
|
||||
ExpectTimeoutProcess(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectExitCondition(pid);
|
||||
}
|
||||
|
||||
DoNotExpectStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
ProcessSchedulerTestFixtureWithParams, ProcessLaunchCallbackAbort_InFlightProcessesTerminatedAndQueuedProcessesUnlaunched)
|
||||
{
|
||||
const size_t processToAbort = 8;
|
||||
|
||||
// Given a set of processes to launch
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
|
||||
// Given a launch callback that will return the abort value for the process to abort
|
||||
const auto abortingLaunchCallback = [this, processToAbort](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::LaunchResult launchResult,
|
||||
AZStd::chrono::high_resolution_clock::time_point createTime)
|
||||
{
|
||||
m_processLaunchCallback(pid, launchResult, createTime);
|
||||
|
||||
if (pid == processToAbort)
|
||||
{
|
||||
return TestImpact::CallbackResult::Abort;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TestImpact::CallbackResult::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
abortingLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid < processToAbort)
|
||||
{
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
}
|
||||
else if (pid == processToAbort)
|
||||
{
|
||||
ExpectTerminatedProcess(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectUnlaunchedProcess(pid);
|
||||
}
|
||||
|
||||
DoNotExpectStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, ProcessExitCallbackAbort_InFlightProcessesTerminated)
|
||||
{
|
||||
const size_t processToAbort = 4;
|
||||
|
||||
// Given a set of processes to launch
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
|
||||
// Given an exit callback that will return the abort value for the process to abort
|
||||
const auto abortingExitCallback = [this, processToAbort](
|
||||
TestImpact::ProcessId pid,
|
||||
TestImpact::ExitCondition exitStatus,
|
||||
TestImpact::ReturnCode returnCode,
|
||||
TestImpact::StdContent&& std,
|
||||
AZStd::chrono::high_resolution_clock::time_point exitTime)
|
||||
{
|
||||
m_processExitCallback(pid, exitStatus, returnCode, std::move(std), exitTime);
|
||||
|
||||
if (pid == processToAbort)
|
||||
{
|
||||
return TestImpact::CallbackResult::Abort;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TestImpact::CallbackResult::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
abortingExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid < processToAbort)
|
||||
{
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
}
|
||||
else if (pid == processToAbort)
|
||||
{
|
||||
ExpectGracefulExit(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_processResults[pid].m_launchResult.has_value())
|
||||
{
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectUnlaunchedProcess(pid);
|
||||
}
|
||||
}
|
||||
|
||||
DoNotExpectStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, SchedulerTimeout_QueuedAndInFlightProcessesTerminated)
|
||||
{
|
||||
const size_t processToTimeout = 0;
|
||||
|
||||
// Given a set of processes to launch where one process will sleep indefinately
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid == processToTimeout)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, LongSleep));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgs(pid, NoSleep));
|
||||
}
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes with a scheduler timeout value
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::chrono::milliseconds(100)
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
if (pid == processToTimeout)
|
||||
{
|
||||
ExpectTimeoutProcess(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_processResults[pid].m_launchResult.has_value())
|
||||
{
|
||||
ExpectSuccessfulLaunch(pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectUnlaunchedProcess(pid);
|
||||
}
|
||||
}
|
||||
|
||||
DoNotExpectStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, RedirectStdOut_StdOutputIsLargeTextString)
|
||||
{
|
||||
// Given a set of processes to launch
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgsLargeText(pid, NoSleep));
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
ExpectGracefulExit(pid);
|
||||
ExpectLargeStdOutput(pid);
|
||||
DoNotExpectStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProcessSchedulerTestFixtureWithParams, RedirectStdError_StdErrorIsLargeTextString)
|
||||
{
|
||||
// Given a set of processes to launch
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
m_processInfos.emplace_back(
|
||||
pid,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
ConstructTestProcessArgsLargeText(pid, NoSleep));
|
||||
}
|
||||
|
||||
// When the process scheduler launches the processes
|
||||
m_processScheduler = AZStd::make_unique<TestImpact::ProcessScheduler>(
|
||||
m_processInfos,
|
||||
m_processLaunchCallback,
|
||||
m_processExitCallback,
|
||||
m_numMaxConcurrentProcesses,
|
||||
AZStd::nullopt,
|
||||
AZStd::nullopt
|
||||
);
|
||||
|
||||
for (size_t pid = 0; pid < m_numProcessesToLaunch; pid++)
|
||||
{
|
||||
ExpectGracefulExit(pid);
|
||||
DoNotExpectStdOutput(pid);
|
||||
ExpectLargeStdError(pid);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SmallConcurrentProcesses,
|
||||
ProcessSchedulerTestFixtureWithParams,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(SmallNumMaxConcurrentProcesses),
|
||||
::testing::ValuesIn(SmallNumProcessesToLaunch)
|
||||
));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
LargeConcurrentProcesses,
|
||||
ProcessSchedulerTestFixtureWithParams,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(LargeNumMaxConcurrentProcesses),
|
||||
::testing::ValuesIn(LargeNumProcessesToLaunch)
|
||||
));
|
||||
} // namespace UnitTest
|
||||
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <TestImpactTestUtils.h>
|
||||
|
||||
#include <Process/TestImpactProcess.h>
|
||||
#include <Process/TestImpactProcessLauncher.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class ProcessTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
UnitTest::AllocatorsTestFixture::SetUp();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (m_process && m_process->IsRunning())
|
||||
{
|
||||
m_process->Terminate(0);
|
||||
}
|
||||
|
||||
UnitTest::AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<TestImpact::Process> m_process;
|
||||
static constexpr const TestImpact::ProcessId m_id = 1;
|
||||
static constexpr const TestImpact::ReturnCode m_terminateErrorCode = 666;
|
||||
};
|
||||
|
||||
TEST_F(ProcessTestFixture, LaunchValidProcess_ProcessReturnsSuccessfully)
|
||||
{
|
||||
// Given a process launched with a valid binary
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process has exited
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect the process to no longer be running
|
||||
EXPECT_FALSE(m_process->IsRunning());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LaunchInvalidProcessInfo_ThrowsProcessException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Given a process launched with an invalid binary
|
||||
TestImpact::ProcessInfo processInfo(m_id, "");
|
||||
|
||||
// Do not expect this code to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ProcessException& e)
|
||||
{
|
||||
// Except a process exception to be thrown
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LaunchInvalidBinary_ThrowsProcessException)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Given a process launched with an ivalid binary
|
||||
TestImpact::ProcessInfo processInfo(m_id, "#!#zz:/z/z/z.exe.z@");
|
||||
|
||||
// When the process is attempted launch
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// Do not expect this code to be reachable
|
||||
FAIL();
|
||||
}
|
||||
catch ([[maybe_unused]] const TestImpact::ProcessException& e)
|
||||
{
|
||||
// Except a process exception to be thrown
|
||||
SUCCEED();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Do not expect any other exceptions
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, GetProcessInfo_ReturnsProcessInfo)
|
||||
{
|
||||
// Given a process launched with a valid binary and args
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath, args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process has exited
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect the retrieved process info to match to process info used to launch the process
|
||||
EXPECT_EQ(m_process->GetProcessInfo().GetId(), m_id);
|
||||
EXPECT_EQ(m_process->GetProcessInfo().GetProcessPath(), ValidProcessPath);
|
||||
EXPECT_EQ(m_process->GetProcessInfo().GetStartupArgs(), args);
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, GetReturnCodeAfterExit_ReturnsArg)
|
||||
{
|
||||
// Given a process launched with a valid binary and args
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath, args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process has exited
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect the process to no longer be running
|
||||
EXPECT_FALSE(m_process->IsRunning());
|
||||
|
||||
// Expect the return value to be the process id
|
||||
EXPECT_EQ(m_process->GetReturnCode(), m_id);
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, GetReturnCodeInFlight_ReturnsNullOpt)
|
||||
{
|
||||
// Given a process launched with a valid binary and args to sleep for 100 seconds
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, LongSleep);
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath, args);
|
||||
|
||||
// When the process is running
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// Expect the return value to be empty
|
||||
EXPECT_EQ(m_process->GetReturnCode(), AZStd::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, TerminateWithErrorCode_ReturnsErrorCode)
|
||||
{
|
||||
// Given a process launched with a valid binary and args to sleep for 100 seconds
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, LongSleep);
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath, args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process is terminated by the client with the specified error code
|
||||
m_process->Terminate(m_terminateErrorCode);
|
||||
|
||||
// Expect the return value to be the error code specified in the Terminate call
|
||||
EXPECT_EQ(m_process->GetReturnCode(), m_terminateErrorCode);
|
||||
|
||||
// Expect the process to no longer be running
|
||||
EXPECT_FALSE(m_process->IsRunning());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, CheckIsRunningWhilstRunning_ProcessIsRunning)
|
||||
{
|
||||
// Given a process launched with a valid binary and args to sleep for 100 seconds
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, LongSleep);
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath, args);
|
||||
|
||||
// When the process is running
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// Expect the process to be running
|
||||
EXPECT_TRUE(m_process->IsRunning());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, CheckIsRunningWhilstNotRunning_ReturnsFalse)
|
||||
{
|
||||
// Given a process launched with a valid binary
|
||||
TestImpact::ProcessInfo processInfo(m_id, ValidProcessPath);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process is terminated by the client
|
||||
m_process->Terminate(0);
|
||||
|
||||
// Expect the process to be running
|
||||
EXPECT_FALSE(m_process->IsRunning());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, RedirectStdOut_OutputIsKnownTestProcessOutputString)
|
||||
{
|
||||
// Given a process launched with a valid binary and standard output redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect stdoutput to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Do not expect stdouterr to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to match the known stdout of the child
|
||||
EXPECT_EQ(m_process->ConsumeStdOut(), KnownTestProcessOutputString(m_id));
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, RedirectStdErr_OutputIsKnownTestProcessOutputString)
|
||||
{
|
||||
// Given a process launched with a valid binary and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Do not expect stdoutput to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Expect stderror to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to match the known stdout of the child
|
||||
EXPECT_EQ(m_process->ConsumeStdErr(), KnownTestProcessErrorString(m_id));
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, RedirectStdOutAndTerminate_OutputIsEmpty)
|
||||
{
|
||||
// Given a process launched with a valid binary and standard output redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process is terminated
|
||||
m_process->Terminate(0);
|
||||
|
||||
// Expect stdoutput to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Do not expect stdouterr to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, RedirectStdErrAndTerminate_OutputIsEmpty)
|
||||
{
|
||||
// Given a process launched with a valid binary and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process is terminated
|
||||
m_process->Terminate(0);
|
||||
|
||||
// Do not expect stdoutput to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Expect stderror to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, RedirectStdOutAndStdErrorRouting_OutputsAreKnownTestProcessOutputStrings)
|
||||
{
|
||||
// Given a process launched with a valid binary and both standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect stdoutput to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Expect stderror to be rerouted to the parent
|
||||
EXPECT_TRUE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to match the known stdout and stderr of the child
|
||||
EXPECT_EQ(m_process->ConsumeStdOut(), KnownTestProcessOutputString(m_id));
|
||||
EXPECT_EQ(m_process->ConsumeStdErr(), KnownTestProcessErrorString(m_id));
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, NoStdOutOrStdErrRedirect_OutputIsEmpty)
|
||||
{
|
||||
// Given a process launched with a valid binary and both standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgs(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Do not expect stdoutput to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdOutput());
|
||||
|
||||
// Do not expect stdouterr to be rerouted to the parent
|
||||
EXPECT_FALSE(m_process->GetProcessInfo().ParentHasStdError());
|
||||
|
||||
// Expect the output to to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeNoRedirects_OutputsAreEmpty)
|
||||
{
|
||||
// Given a process outputting large text with no standard output and no standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect the output to to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeNoRedirectsAndTerminated_OutputsAreEmpty)
|
||||
{
|
||||
// Given a process outputting large text with no standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, LongSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
|
||||
// When the process is running
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// Expect the output to to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
|
||||
// When the process is terminated
|
||||
m_process->Terminate(0);
|
||||
|
||||
// Expect the output to to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeRedirectsAndReadWhilstRunning_OutputsAreEmpty)
|
||||
{
|
||||
// Given a process outputting large text with no standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, ShortSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::None,
|
||||
TestImpact::StdErrorRouting::None,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the outputs are read as the process is running
|
||||
while (m_process->IsRunning())
|
||||
{
|
||||
// Expect the outputs to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeRedirectsAndTerminated_OutputsAreEmpty)
|
||||
{
|
||||
// Given a process outputting large text with both standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, LongSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process is terminated
|
||||
m_process->Terminate(0);
|
||||
|
||||
// Expect the outputs to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeRedirectsAndBlockedUntilExit_OutputsAreLargeTextFileSize)
|
||||
{
|
||||
// Given a process outputting large text with both standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath,
|
||||
args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
// When the process exits
|
||||
m_process->BlockUntilExit();
|
||||
|
||||
// Expect the output lengths to be that of the large text output from the child process
|
||||
EXPECT_EQ(m_process->ConsumeStdOut().value().length(), LargeTextSize);
|
||||
EXPECT_EQ(m_process->ConsumeStdErr().value().length(), LargeTextSize);
|
||||
}
|
||||
|
||||
TEST_F(ProcessTestFixture, LargePipeRedirectsAndReadWhilstRunning_TotalOutputsAreLargeTextFileSize)
|
||||
{
|
||||
// Given a process outputting large text with both standard output and standard error redirected to parent
|
||||
const AZStd::string args = ConstructTestProcessArgsLargeText(m_id, NoSleep);
|
||||
TestImpact::ProcessInfo processInfo(
|
||||
m_id,
|
||||
TestImpact::StdOutputRouting::ToParent,
|
||||
TestImpact::StdErrorRouting::ToParent,
|
||||
ValidProcessPath, args);
|
||||
m_process = TestImpact::LaunchProcess(processInfo);
|
||||
|
||||
size_t stdOutBytes = 0;
|
||||
size_t stdErrBytes = 0;
|
||||
while (m_process->IsRunning())
|
||||
{
|
||||
// When the outputs are read as the process is running
|
||||
if (auto output = m_process->ConsumeStdOut(); output.has_value())
|
||||
{
|
||||
stdOutBytes += output.value().length();
|
||||
}
|
||||
|
||||
if (auto output = m_process->ConsumeStdErr(); output.has_value())
|
||||
{
|
||||
stdErrBytes += output.value().length();
|
||||
}
|
||||
}
|
||||
|
||||
// Expect the output lengths to be that of the large text output from the child process
|
||||
EXPECT_EQ(stdOutBytes, LargeTextSize);
|
||||
EXPECT_EQ(stdErrBytes, LargeTextSize);
|
||||
|
||||
// Expect the outputs to be empty
|
||||
EXPECT_FALSE(m_process->ConsumeStdOut().has_value());
|
||||
EXPECT_FALSE(m_process->ConsumeStdErr().has_value());
|
||||
}
|
||||
} // namespace UnitTest
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue