/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once #include "cmConfigure.h" // IWYU pragma: keep #include #include #include #include #include #include #include #include #include #include #include #include "cmsys/RegularExpression.hxx" #include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestResourceSpec.h" #include "cmCTestTypes.h" #include "cmDuration.h" #include "cmListFileCache.h" #include "cmValue.h" class cmMakefile; class cmXMLWriter; /** \class cmCTestTestHandler * \brief A class that handles ctest -S invocations * */ class cmCTestTestHandler : public cmCTestGenericHandler { friend class cmCTest; friend class cmCTestRunTest; friend class cmCTestMultiProcessHandler; public: using Superclass = cmCTestGenericHandler; /** * The main entry point for this class */ int ProcessHandler() override; /** * When both -R and -I are used should the resulting test list be the * intersection or the union of the lists. By default it is the * intersection. */ void SetUseUnion(bool val) { this->UseUnion = val; } /** * Set whether or not CTest should only execute the tests that failed * on the previous run. By default this is false. */ void SetRerunFailed(bool val) { this->RerunFailed = val; } /** * This method is called when reading CTest custom file */ void PopulateCustomVectors(cmMakefile* mf) override; //! Control the use of the regular expresisons, call these methods to turn /// them on void UseIncludeRegExp(); void UseExcludeRegExp(); void SetIncludeRegExp(const std::string&); void SetExcludeRegExp(const std::string&); void SetMaxIndex(int n) { this->MaxIndex = n; } int GetMaxIndex() { return this->MaxIndex; } void SetTestOutputSizePassed(int n) { this->CustomMaximumPassedTestOutputSize = n; } void SetTestOutputSizeFailed(int n) { this->CustomMaximumFailedTestOutputSize = n; } //! Set test output truncation mode. Return false if unknown mode. bool SetTestOutputTruncation(const std::string& mode); //! pass the -I argument down void SetTestsToRunInformation(cmValue); cmCTestTestHandler(); /* * Add the test to the list of tests to be executed */ bool AddTest(const std::vector& args); /* * Set tests properties */ bool SetTestsProperties(const std::vector& args); /** * Set directory properties */ bool SetDirectoryProperties(const std::vector& args); void Initialize() override; struct cmCTestTestResourceRequirement { std::string ResourceType; int SlotsNeeded; int UnitsNeeded; bool operator==(const cmCTestTestResourceRequirement& other) const; bool operator!=(const cmCTestTestResourceRequirement& other) const; }; struct Signal { int Number = 0; std::string Name; }; struct cmCTestTestProperties { void AppendError(cm::string_view err); cm::optional Error; std::string Name; std::string Directory; std::vector Args; std::vector RequiredFiles; std::vector Depends; std::vector AttachedFiles; std::vector AttachOnFail; std::vector> ErrorRegularExpressions; std::vector> RequiredRegularExpressions; std::vector> SkipRegularExpressions; std::vector> TimeoutRegularExpressions; std::map Measurements; bool IsInBasedOnREOptions = true; bool WillFail = false; bool Disabled = false; float Cost = 0; int PreviousRuns = 0; bool RunSerial = false; cm::optional Timeout; cm::optional TimeoutSignal; cm::optional TimeoutGracePeriod; cmDuration AlternateTimeout; int Index = 0; // Requested number of process slots int Processors = 1; bool WantAffinity = false; std::vector Affinity; // return code of test which will mark test as "not run" int SkipReturnCode = -1; std::vector Environment; std::vector EnvironmentModification; std::vector Labels; std::set LockedResources; std::set FixturesSetup; std::set FixturesCleanup; std::set FixturesRequired; std::set RequireSuccessDepends; std::vector> ResourceGroups; // Private test generator properties used to track backtraces cmListFileBacktrace Backtrace; }; struct cmCTestTestResult { std::string Name; std::string Path; std::string Reason; std::string FullCommandLine; std::string Environment; cmDuration ExecutionTime = cmDuration::zero(); std::int64_t ReturnValue = 0; int Status = NOT_RUN; std::string ExceptionStatus; bool CompressOutput; std::string CompletionStatus; std::string CustomCompletionStatus; std::string Output; std::string TestMeasurementsOutput; int TestCount = 0; cmCTestTestProperties* Properties = nullptr; }; struct cmCTestTestResultLess { bool operator()(const cmCTestTestResult& lhs, const cmCTestTestResult& rhs) const { return lhs.TestCount < rhs.TestCount; } }; // add configurations to a search path for an executable static void AddConfigurations(cmCTest* ctest, std::vector& attempted, std::vector& attemptedConfigs, std::string filepath, std::string& filename); // full signature static method to find an executable static std::string FindExecutable(cmCTest* ctest, const std::string& testCommand, std::string& resultingConfig, std::vector& extraPaths, std::vector& failed); static bool ParseResourceGroupsProperty( const std::string& val, std::vector>& resourceGroups); using ListOfTests = std::vector; // Support for writing test results in JUnit XML format. void SetJUnitXMLFileName(const std::string& id); protected: using SetOfTests = std::set; // compute a final test list virtual int PreProcessHandler(); virtual int PostProcessHandler(); virtual void GenerateTestCommand(std::vector& args, int test); int ExecuteCommands(std::vector& vec); bool ProcessOptions(); void LogTestSummary(const std::vector& passed, const std::vector& failed, const cmDuration& durationInSecs); void LogDisabledTests(const std::vector& disabledTests); void LogFailedTests(const std::vector& failed, const SetOfTests& resultsSet); bool GenerateXML(); void WriteTestResultHeader(cmXMLWriter& xml, cmCTestTestResult const& result); void WriteTestResultFooter(cmXMLWriter& xml, cmCTestTestResult const& result); // Write attached test files into the xml void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result); void AttachFile(cmXMLWriter& xml, std::string const& file, std::string const& name); //! Clean test output to specified length and truncation mode void CleanTestOutput(std::string& output, size_t length, cmCTestTypes::TruncationMode truncate); cmDuration ElapsedTestingTime; using TestResultsVector = std::vector; TestResultsVector TestResults; std::vector CustomTestsIgnore; std::string StartTest; std::string EndTest; std::chrono::system_clock::time_point StartTestTime; std::chrono::system_clock::time_point EndTestTime; bool MemCheck; int CustomMaximumPassedTestOutputSize; int CustomMaximumFailedTestOutputSize; cmCTestTypes::TruncationMode TestOutputTruncation; int MaxIndex; public: enum { // Program statuses NOT_RUN = 0, TIMEOUT, SEGFAULT, ILLEGAL, INTERRUPT, NUMERICAL, OTHER_FAULT, FAILED, BAD_COMMAND, COMPLETED }; private: /** * Write test results in CTest's Test.xml format */ virtual void GenerateCTestXML(cmXMLWriter& xml); /** * Write test results in JUnit XML format */ bool WriteJUnitXML(); void PrintLabelOrSubprojectSummary(bool isSubProject); /** * Run the tests for a directory and any subdirectories */ bool ProcessDirectory(std::vector& passed, std::vector& failed); /** * Get the list of tests in directory and subdirectories. */ bool GetListOfTests(); // compute the lists of tests that will actually run // based on union regex and -I stuff bool ComputeTestList(); // compute the lists of tests that will actually run // based on LastTestFailed.log void ComputeTestListForRerunFailed(); // add required setup/cleanup tests not already in the // list of tests to be run and update dependencies between // tests to account for fixture setup/cleanup void UpdateForFixtures(ListOfTests& tests) const; void UpdateMaxTestNameWidth(); bool GetValue(const char* tag, std::string& value, std::istream& fin); bool GetValue(const char* tag, int& value, std::istream& fin); bool GetValue(const char* tag, size_t& value, std::istream& fin); bool GetValue(const char* tag, bool& value, std::istream& fin); bool GetValue(const char* tag, double& value, std::istream& fin); /** * Find the executable for a test */ std::string FindTheExecutable(const std::string& exe); std::string GetTestStatus(cmCTestTestResult const&); void ExpandTestsToRunInformation(size_t numPossibleTests); void ExpandTestsToRunInformationForRerunFailed(); std::vector CustomPreTest; std::vector CustomPostTest; std::vector TestsToRun; bool UseIncludeRegExpFlag; bool UseExcludeRegExpFlag; bool UseExcludeRegExpFirst; std::string IncludeRegExp; std::string ExcludeRegExp; std::string ExcludeFixtureRegExp; std::string ExcludeFixtureSetupRegExp; std::string ExcludeFixtureCleanupRegExp; std::vector IncludeLabelRegularExpressions; std::vector ExcludeLabelRegularExpressions; cmsys::RegularExpression IncludeTestsRegularExpression; cmsys::RegularExpression ExcludeTestsRegularExpression; bool UseResourceSpec; cmCTestResourceSpec ResourceSpec; std::string ResourceSpecFile; void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content); void CheckLabelFilter(cmCTestTestProperties& it); void CheckLabelFilterExclude(cmCTestTestProperties& it); void CheckLabelFilterInclude(cmCTestTestProperties& it); std::string TestsToRunString; bool UseUnion; ListOfTests TestList; size_t TotalNumberOfTests; cmsys::RegularExpression AllTestMeasurementsRegex; cmsys::RegularExpression SingleTestMeasurementRegex; cmsys::RegularExpression CustomCompletionStatusRegex; cmsys::RegularExpression CustomLabelRegex; std::ostream* LogFile; cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; int RepeatCount = 1; bool RerunFailed; std::string JUnitXMLFileName; };