From 48b613392848610d243962086fb289a93cc41f0d Mon Sep 17 00:00:00 2001 From: Zach Mullen Date: Thu, 10 Dec 2009 14:38:32 -0500 Subject: [PATCH] [0008668: CTest Dev: Missing executables shown as failed tests when using MPI.] Added a wrapping option to add_test so that exes built by the project can be safely wrapped in other exes and be listed as "not run" rather than "failed" if they are not built. --- Source/CTest/cmCTestRunTest.cxx | 75 +++++++++++++++++++++++------ Source/CTest/cmCTestRunTest.h | 6 +++ Source/CTest/cmCTestTestHandler.cxx | 30 +++++++++++- Source/CTest/cmCTestTestHandler.h | 4 +- Source/cmAddTestCommand.h | 8 ++- 5 files changed, 103 insertions(+), 20 deletions(-) diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index a984c6c6c..83119c737 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -26,6 +26,8 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler) this->TestResult.Status = 0; this->TestResult.TestCount = 0; this->TestResult.Properties = 0; + this->PrefixCommand = ""; + this->UsePrefixCommand = false; } cmCTestRunTest::~cmCTestRunTest() @@ -303,29 +305,27 @@ bool cmCTestRunTest::StartTest(size_t total) << this->TestProperties->Name << std::endl); this->ComputeArguments(); std::vector& args = this->TestProperties->Args; + std::vector& pargs = this->TestProperties->PrefixArgs; this->TestResult.Properties = this->TestProperties; this->TestResult.ExecutionTime = 0; this->TestResult.ReturnValue = -1; this->TestResult.CompletionStatus = "Failed to start"; this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; - this->TestResult.TestCount = this->TestProperties->Index; + this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory.c_str(); + // if we are using a prefix command, make sure THAT executable exists + if (this->UsePrefixCommand && this->PrefixCommand == "") + { + this->ExeNotFound(pargs[0]); + return false; + } + // log and return if we did not find the executable if (this->ActualCommand == "") { - // if the command was not found create a TestResult object - // that has that information - this->TestProcess = new cmProcess; - *this->TestHandler->LogFile << "Unable to find executable: " - << args[1].c_str() << std::endl; - cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: " - << args[1].c_str() << std::endl); - this->TestResult.Output = "Unable to find executable: " + args[1]; - this->TestResult.FullCommandLine = ""; - this->TestResult.CompletionStatus = "Not Run"; - this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->ExeNotFound(args[1]); return false; } this->StartTime = this->CTest->CurrentTime(); @@ -334,12 +334,36 @@ bool cmCTestRunTest::StartTest(size_t total) &this->TestProperties->Environment); } +void cmCTestRunTest::ExeNotFound(std::string exe) +{ + this->TestProcess = new cmProcess; + *this->TestHandler->LogFile << "Unable to find executable: " + << exe.c_str() << std::endl; + cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: " + << exe.c_str() << std::endl); + this->TestResult.Output = "Unable to find executable: " + exe; + this->TestResult.FullCommandLine = ""; + this->TestResult.CompletionStatus = "Not Run"; + this->TestResult.Reason = ""; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; +} + void cmCTestRunTest::ComputeArguments() { std::vector::const_iterator j = this->TestProperties->Args.begin(); ++j; // skip test name + this->TestCommand = ""; + + //If we are using a prefix command, find the exe for it + if(this->TestProperties->PrefixArgs.size()) + { + this->UsePrefixCommand = true; + this->PrefixCommand = this->TestHandler->FindTheExecutable( + this->TestProperties->PrefixArgs[0].c_str()); + } + // find the test executable if(this->TestHandler->MemCheck) { @@ -354,8 +378,6 @@ void cmCTestRunTest::ComputeArguments() this->TestProperties->Args[1].c_str()); ++j; //skip the executable (it will be actualCommand) } - this->TestCommand - = cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str()); //Prepends memcheck args to our command string this->TestHandler->GenerateTestCommand(this->Arguments); @@ -365,6 +387,27 @@ void cmCTestRunTest::ComputeArguments() this->TestCommand += " "; this->TestCommand += cmSystemTools::EscapeSpaces(j->c_str()); } + //Add user specified prefix args + if(this->UsePrefixCommand) + { + this->TestCommand += + cmSystemTools::ConvertToOutputPath(this->PrefixCommand.c_str()); + + std::vector::iterator i = + this->TestProperties->PrefixArgs.begin(); + ++i; //skip the exe name + for(; i != this->TestProperties->PrefixArgs.end(); ++i) + { + this->TestCommand += " "; + this->TestCommand += cmSystemTools::EscapeSpaces(i->c_str()); + this->Arguments.push_back(*i); + } + this->Arguments.push_back(this->ActualCommand); + this->TestCommand += " "; + } + //Add regular test args + this->TestCommand + += cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str()); for(;j != this->TestProperties->Args.end(); ++j) { @@ -411,7 +454,9 @@ bool cmCTestRunTest::CreateProcess(double testTimeOut, this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory( this->TestProperties->Directory.c_str()); - this->TestProcess->SetCommand(this->ActualCommand.c_str()); + this->TestProcess->SetCommand(this->UsePrefixCommand ? + this->PrefixCommand.c_str() : + this->ActualCommand.c_str()); this->TestProcess->SetCommandArguments(this->Arguments); std::vector origEnv; diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index bfeda209a..fa0e8af7e 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -53,6 +53,7 @@ public: void ComputeArguments(); private: void DartProcessing(); + void ExeNotFound(std::string exe); bool CreateProcess(double testTimeOut, std::vector* environment); void WriteLogOutputTop(size_t completed, size_t total); @@ -71,6 +72,10 @@ private: //flag for whether the env was modified for this run bool ModifyEnv; + + bool UsePrefixCommand; + std::string PrefixCommand; + //stores the original environment if we are modifying it std::vector OrigEnv; std::string ProcessOutput; @@ -96,5 +101,6 @@ inline int getNumWidth(size_t n) } return numWidth; } + #endif diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index cbac2726c..dadd39cf3 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -269,7 +269,30 @@ bool cmCTestAddTestCommand this->SetError("called with incorrect number of arguments"); return false; } - return this->TestHandler->AddTest(args); + + bool prefixCmdFound = false; + std::vector actualArgs, prefix; + + //separate the regular command and the prefix command (bug 8668) + for(std::vector::const_iterator i = args.begin(); + i != args.end(); ++i) + { + if(*i == "EXEC_PREFIX_CMD") + { + prefixCmdFound = true; + continue; + } + if(prefixCmdFound) + { + prefix.push_back(*i); + } + else + { + actualArgs.push_back(*i); + } + } + + return this->TestHandler->AddTest(actualArgs, prefix); } //---------------------------------------------------------------------- @@ -2104,10 +2127,12 @@ bool cmCTestTestHandler::SetTestsProperties( } //---------------------------------------------------------------------- -bool cmCTestTestHandler::AddTest(const std::vector& args) +bool cmCTestTestHandler::AddTest(const std::vector& args, + const std::vector& prefix) { const std::string& testname = args[0]; cmCTestLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl); + if (this->UseExcludeRegExpFlag && this->UseExcludeRegExpFirst && this->ExcludeTestsRegularExpression.find(testname.c_str())) @@ -2158,6 +2183,7 @@ bool cmCTestTestHandler::AddTest(const std::vector& args) cmCTestTestProperties test; test.Name = testname; test.Args = args; + test.PrefixArgs = prefix; test.Directory = cmSystemTools::GetCurrentWorkingDirectory(); cmCTestLog(this->CTest, DEBUG, "Set test directory: " << test.Directory << std::endl); diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index ceb502084..eedd81158 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -66,7 +66,8 @@ public: /* * Add the test to the list of tests to be executed */ - bool AddTest(const std::vector& args); + bool AddTest(const std::vector& args, + const std::vector& prefix); /* * Set tests properties @@ -84,6 +85,7 @@ public: cmStdString Name; cmStdString Directory; std::vector Args; + std::vector PrefixArgs; std::vector Depends; std::vector > ErrorRegularExpressions; diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h index 2070fd3b5..a360ac001 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -56,7 +56,8 @@ public: virtual const char* GetFullDocumentation() { return - " add_test(testname Exename arg1 arg2 ...)\n" + " add_test(testname Exename arg1 arg2 ... \n" + " [EXEC_PREFIX_CMD wrapperExe args...])\n" "If the ENABLE_TESTING command has been run, this command adds a " "test target to the current directory. If ENABLE_TESTING has not " "been run, this command does nothing. " @@ -65,7 +66,10 @@ public: "built by this project or an arbitrary executable on the " "system (like tclsh). The test will be run with the current working " "directory set to the CMakeList.txt files corresponding directory " - "in the binary tree." + "in the binary tree.\n" + "Use EXEC_PREFIX_CMD to wrap an executable built by this project " + "in another executable such as mpiexec. This will only run the " + "test if the wrapped executable was built." "\n" " add_test(NAME [CONFIGURATIONS [Debug|Release|...]]\n" " COMMAND [arg1 [arg2 ...]])\n"