diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 01d397684..99810d97c 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -358,6 +358,7 @@ SET(CTEST_SRCS cmCTest.cxx CTest/cmCTestMultiProcessHandler.cxx CTest/cmCTestReadCustomFilesCommand.cxx CTest/cmCTestRunScriptCommand.cxx + CTest/cmCTestRunTest.cxx CTest/cmCTestScriptHandler.cxx CTest/cmCTestSleepCommand.cxx CTest/cmCTestStartCommand.cxx diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx new file mode 100644 index 000000000..118188a6f --- /dev/null +++ b/Source/CTest/cmCTestRunTest.cxx @@ -0,0 +1,547 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "cmCTestRunTest.h" +#include "cmCTest.h" +#include "cmSystemTools.h" + +cmCTestRunTest::cmCTestRunTest() +{ + this->OptimizeForCTest = true; + cmCTestTestHandler::cmCTestTestResult result; + this->TestResult = result; +} + +cmCTestRunTest::~cmCTestRunTest() +{ +} + +void cmCTestRunTest::SetTestHandler(cmCTestTestHandler * handler) +{ + this->TestHandler = handler; + this->CTest = handler->CTest; +} + +//---------------------------------------------------------------------- +// Executes a test. Returns whether it passed or failed +bool cmCTestRunTest::Execute() +{ + const std::string& testname = this->TestProperties->Name; + std::vector& args = this->TestProperties->Args; + this->TestResult.Properties = this->TestProperties; + this->TestResult.ExecutionTime = 0; + this->TestResult.ReturnValue = -1; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->TestResult.TestCount = this->TestProperties->Index; + this->TestResult.Name = testname; + this->TestResult.Path = this->TestProperties->Directory.c_str(); + + cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) + << this->TestProperties->Index << "/"); + cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) + << this->TestHandler->TotalNumberOfTests << " "); + if ( this->TestHandler->MemCheck ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check"); + } + else + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing"); + } + cmCTestLog(this->CTest, HANDLER_OUTPUT, " "); + const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth(); + std::string outname = testname + " "; + outname.resize(maxTestNameWidth, '.'); + *this->TestHandler->LogFile << this->TestProperties->Index << "/" + << this->TestHandler->TotalNumberOfTests << " Testing: " + << testname << std::endl; + + if ( this->CTest->GetShowOnly() ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl); + } + else + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str()); + } + + cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... "); + // find the test executable + std::string actualCommand + = this->TestHandler->FindTheExecutable(args[1].c_str()); + std::string testCommand + = cmSystemTools::ConvertToOutputPath(actualCommand.c_str()); + + // continue if we did not find the executable + if (testCommand == "") + { + *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]; + if ( !this->CTest->GetShowOnly() ) + { + this->TestResult.FullCommandLine = actualCommand; + this->TestHandler->TestResults.push_back( this->TestResult ); + return false; + } + } + + // add the arguments + std::vector::const_iterator j = args.begin(); + ++j; // skip test name + ++j; // skip command as it is in actualCommand + std::vector arguments; + this->TestHandler->GenerateTestCommand(arguments); + arguments.push_back(actualCommand.c_str()); + for(;j != args.end(); ++j) + { + testCommand += " "; + testCommand += cmSystemTools::EscapeSpaces(j->c_str()); + arguments.push_back(j->c_str()); + } + arguments.push_back(0); + + /** + * Run an executable command and put the stdout in output. + */ + std::string output; + int retVal = 0; + + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl + << (this->TestHandler->MemCheck?"MemCheck":"Test") + << " command: " << testCommand + << std::endl); + *this->TestHandler->LogFile << this->TestProperties->Index << "/" + << this->TestHandler->TotalNumberOfTests + << " Test: " << testname.c_str() << std::endl; + *this->TestHandler->LogFile << "Command: "; + std::vector::size_type ll; + for ( ll = 0; ll < arguments.size()-1; ll ++ ) + { + *this->TestHandler->LogFile << "\"" << arguments[ll] << "\" "; + } + *this->TestHandler->LogFile + << std::endl + << "Directory: " << this->TestProperties->Directory << std::endl + << "\"" << testname.c_str() << "\" start time: " + << this->CTest->CurrentTime() << std::endl + << "Output:" << std::endl + << "----------------------------------------------------------" + << std::endl; + int res = 0; + double clock_start, clock_finish; + clock_start = cmSystemTools::GetTime(); + + if ( !this->CTest->GetShowOnly() ) + { + res = this->RunTestProcess(arguments, &output, &retVal, + this->TestHandler->LogFile, + this->TestProperties->Timeout, + &this->TestProperties->Environment); + this->ProcessOutput = output; //save process output in the object + } + + clock_finish = cmSystemTools::GetTime(); + + this->TestResult.ExecutionTime = (double)(clock_finish - clock_start); + this->TestResult.FullCommandLine = testCommand; + std::string reason; + + bool passed = true; + + if ( !this->CTest->GetShowOnly() ) + { + std::vector >::iterator passIt; + bool forceFail = false; + if ( this->TestProperties->RequiredRegularExpressions.size() > 0 ) + { + bool found = false; + for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); + passIt != this->TestProperties->RequiredRegularExpressions.end(); + ++ passIt ) + { + if ( passIt->first.find(output.c_str()) ) + { + found = true; + reason = "Required regular expression found."; + } + } + if ( !found ) + { + reason = "Required regular expression not found."; + forceFail = true; + } + reason += "Regex=["; + for ( passIt = this->TestProperties->RequiredRegularExpressions.begin(); + passIt != this->TestProperties->RequiredRegularExpressions.end(); + ++ passIt ) + { + reason += passIt->second; + reason += "\n"; + } + reason += "]"; + } + if ( this->TestProperties->ErrorRegularExpressions.size() > 0 ) + { + for ( passIt = this->TestProperties->ErrorRegularExpressions.begin(); + passIt != this->TestProperties->ErrorRegularExpressions.end(); + ++ passIt ) + { + if ( passIt->first.find(output.c_str()) ) + { + reason = "Error regular expression found in output."; + reason += " Regex=["; + reason += passIt->second; + reason += "]"; + forceFail = true; + } + } + } + + if (res == cmsysProcess_State_Exited) + { + bool success = + !forceFail && (retVal == 0 || + this->TestProperties->RequiredRegularExpressions.size()); + if((success && !this->TestProperties->WillFail) + || (!success && this->TestProperties->WillFail)) + { + this->TestResult.Status = cmCTestTestHandler::COMPLETED; + cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed " ); + } + else + { + this->TestResult.Status = cmCTestTestHandler::FAILED; + cmCTestLog(this->CTest, HANDLER_OUTPUT, + "***Failed " << reason ); + } + } + else if ( res == cmsysProcess_State_Expired ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout"); + this->TestResult.Status = cmCTestTestHandler::TIMEOUT; + } + else if ( res == cmsysProcess_State_Exception ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: "); + switch ( retVal ) + { + case cmsysProcess_Exception_Fault: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault"); + this->TestResult.Status = cmCTestTestHandler::SEGFAULT; + break; + case cmsysProcess_Exception_Illegal: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal"); + this->TestResult.Status = cmCTestTestHandler::ILLEGAL; + break; + case cmsysProcess_Exception_Interrupt: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt"); + this->TestResult.Status = cmCTestTestHandler::INTERRUPT; + break; + case cmsysProcess_Exception_Numerical: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical"); + this->TestResult.Status = cmCTestTestHandler::NUMERICAL; + break; + default: + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other"); + this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT; + } + } + else // if ( res == cmsysProcess_State_Error ) + { + cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res ); + this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND; + } + + passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; + + char buf[1024]; + sprintf(buf, "%6.2f sec", this->TestResult.ExecutionTime); + cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" ); + if ( this->TestHandler->LogFile ) + { + *this->TestHandler->LogFile << "\nTest time = " << buf << std::endl; + } + this->DartProcessing(output); + } + + // if this is doing MemCheck then all the output needs to be put into + // Output since that is what is parsed by cmCTestMemCheckHandler + if(!this->TestHandler->MemCheck) + { + if ( this->TestResult.Status == cmCTestTestHandler::COMPLETED ) + { + this->TestHandler->CleanTestOutput(output, static_cast + (this->TestHandler->CustomMaximumPassedTestOutputSize)); + } + else + { + this->TestHandler->CleanTestOutput(output, static_cast + (this->TestHandler->CustomMaximumFailedTestOutputSize)); + } + } + this->TestResult.Reason = reason; + if ( this->TestHandler->LogFile ) + { + bool pass = true; + const char* reasonType = "Test Pass Reason"; + if(this->TestResult.Status != cmCTestTestHandler::COMPLETED && + this->TestResult.Status != cmCTestTestHandler::NOT_RUN) + { + reasonType = "Test Fail Reason"; + pass = false; + } + double ttime = clock_finish - clock_start; + int hours = static_cast(ttime / (60 * 60)); + int minutes = static_cast(ttime / 60) % 60; + int seconds = static_cast(ttime) % 60; + char buffer[100]; + sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); + *this->TestHandler->LogFile + << "----------------------------------------------------------" + << std::endl; + if(this->TestResult.Reason.size()) + { + *this->TestHandler->LogFile << reasonType << ":\n" + << this->TestResult.Reason << "\n"; + } + else + { + if(pass) + { + *this->TestHandler->LogFile << "Test Passed.\n"; + } + else + { + *this->TestHandler->LogFile << "Test Failed.\n"; + } + } + *this->TestHandler->LogFile << "\"" << testname.c_str() << "\" end time: " + << this->CTest->CurrentTime() << std::endl + << "\"" << testname.c_str() << "\" time elapsed: " + << buffer << std::endl + << "----------------------------------------------------------" + << std::endl << std::endl; + } + this->TestResult.Output = output; + this->TestResult.ReturnValue = retVal; + this->TestResult.CompletionStatus = "Completed"; + this->TestHandler->TestResults.push_back( this->TestResult ); + + return passed; +} + +//---------------------------------------------------------------------- +void cmCTestRunTest::DartProcessing(std::string& output) +{ + if (!output.empty() && output.find("TestHandler->DartStuff.find(output.c_str())) + { + std::string dartString = this->TestHandler->DartStuff.match(1); + // keep searching and replacing until none are left + while (this->TestHandler->DartStuff1.find(output.c_str())) + { + // replace the exact match for the string + cmSystemTools::ReplaceString(output, + this->TestHandler->DartStuff1.match(1).c_str(), ""); + } + this->TestResult.RegressionImages + = this->TestHandler->GenerateRegressionImages(dartString); + } + } +} + +//---------------------------------------------------------------------- +int cmCTestRunTest::RunTestProcess(std::vector argv, + std::string* output, int *retVal, + std::ostream* log, double testTimeOut, + std::vector* environment) +{ + std::vector origEnv; + bool modifyEnv = (environment && environment->size()>0); + + // determine how much time we have + double timeout = this->CTest->GetRemainingTimeAllowed() - 120; + if (this->CTest->GetTimeOut() && this->CTest->GetTimeOut() < timeout) + { + timeout = this->CTest->GetTimeOut(); + } + if (testTimeOut + && testTimeOut < this->CTest->GetRemainingTimeAllowed()) + { + timeout = testTimeOut; + } + + // always have at least 1 second if we got to here + if (timeout <= 0) + { + timeout = 1; + } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Test timeout computed to be: " << timeout << "\n"); + + if(cmSystemTools::SameFile(argv[0], this->CTest->CTestSelf.c_str()) && + !this->CTest->ForceNewCTestProcess && + this->OptimizeForCTest) + { + cmCTest inst; + inst.ConfigType = this->CTest->ConfigType; + inst.TimeOut = timeout; + + // Capture output of the child ctest. + cmOStringStream oss; + inst.SetStreams(&oss, &oss); + + std::vector args; + for(unsigned int i =0; i < argv.size(); ++i) + { + if(argv[i]) + { + // make sure we pass the timeout in for any build and test + // invocations. Since --build-generator is required this is a + // good place to check for it, and to add the arguments in + if (strcmp(argv[i],"--build-generator") == 0 && timeout) + { + args.push_back("--test-timeout"); + cmOStringStream msg; + msg << timeout; + args.push_back(msg.str()); + } + args.push_back(argv[i]); + } + } + if ( log ) + { + *log << "* Run internal CTest" << std::endl; + } + std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory(); + + if (modifyEnv) + { + origEnv = cmSystemTools::AppendEnv(environment); + } + + *retVal = inst.Run(args, output); + *output += oss.str(); + if ( log ) + { + *log << output->c_str(); + } + cmSystemTools::ChangeDirectory(oldpath.c_str()); + + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Internal cmCTest object used to run test." << std::endl + << *output << std::endl); + + if (modifyEnv) + { + cmSystemTools::RestoreEnv(origEnv); + } + + return cmsysProcess_State_Exited; + } + std::vector tempOutput; + if ( output ) + { + *output = ""; + } + + if (modifyEnv) + { + origEnv = cmSystemTools::AppendEnv(environment); + } + + cmsysProcess* cp = cmsysProcess_New(); + cmsysProcess_SetCommand(cp, &*argv.begin()); + cmCTestLog(this->CTest, DEBUG, "Command is: " << argv[0] << std::endl); + if(cmSystemTools::GetRunCommandHideConsole()) + { + cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); + } + + cmsysProcess_SetTimeout(cp, timeout); + cmsysProcess_Execute(cp); + + char* data; + int length; + while(cmsysProcess_WaitForData(cp, &data, &length, 0)) + { + if ( output ) + { + tempOutput.insert(tempOutput.end(), data, data+length); + } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length)); + if ( log ) + { + log->write(data, length); + } + } + + cmsysProcess_WaitForExit(cp, 0); + if(output && tempOutput.begin() != tempOutput.end()) + { + //We are waiting for exit before finally appending to the output + output->append(&*tempOutput.begin(), tempOutput.size()); + } + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "-- Process completed" + << std::endl); + + int result = cmsysProcess_GetState(cp); + + if(result == cmsysProcess_State_Exited) + { + *retVal = cmsysProcess_GetExitValue(cp); + if(*retVal != 0 && this->CTest->OutputTestOutputOnTestFailure) + { + this->CTest->OutputTestErrors(tempOutput); + } + } + else if(result == cmsysProcess_State_Exception) + { + if(this->CTest->OutputTestOutputOnTestFailure) + { + this->CTest->OutputTestErrors(tempOutput); + } + *retVal = cmsysProcess_GetExitException(cp); + std::string outerr = "\n*** Exception executing: "; + outerr += cmsysProcess_GetExceptionString(cp); + *output += outerr; + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl + << std::flush); + } + else if(result == cmsysProcess_State_Error) + { + std::string outerr = "\n*** ERROR executing: "; + outerr += cmsysProcess_GetErrorString(cp); + *output += outerr; + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str() << std::endl + << std::flush); + } + cmsysProcess_Delete(cp); + + if (modifyEnv) + { + cmSystemTools::RestoreEnv(origEnv); + } + + return result; +} + diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h new file mode 100644 index 000000000..1438a60fb --- /dev/null +++ b/Source/CTest/cmCTestRunTest.h @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef cmCTestRunTest_h +#define cmCTestRunTest_h + +#include +#include + +/** \class cmRunTest + * \brief represents a single test to be run + * + * cmRunTest contains the information related to running a single test + */ +class cmCTestRunTest +{ +public: + cmCTestRunTest(); + ~cmCTestRunTest(); + + void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties * prop) + { this->TestProperties = prop; } + + cmCTestTestHandler::cmCTestTestProperties * GetTestProperties() + { return this->TestProperties; } + + void SetTestHandler(cmCTestTestHandler * handler); + + void SetOptimizeForCTest(bool optimize) + { this->OptimizeForCTest = optimize; } + + bool GetOptimizeForCTest() + { return this->OptimizeForCTest; } + + std::string GetProcessOutput() + { return this->ProcessOutput; } + + //Provides a handle to the log stream in case someone wants + // to asynchronously process the log + std::ostream * GetLogStream() + { return this->TestHandler->LogFile; } + + cmCTestTestHandler::cmCTestTestResult GetTestResults() + { return this->TestResult; } + + //Runs the test + bool Execute(); +protected: + void DartProcessing(std::string& output); + int RunTestProcess(std::vector argv, + std::string* output, int *retVal, + std::ostream* log, double testTimeOut, + std::vector* environment); +private: + cmCTestTestHandler::cmCTestTestProperties * TestProperties; + //Pointer back to the "parent"; the handler that invoked this test run + cmCTestTestHandler * TestHandler; + cmCTest * CTest; + //If the executable to run is ctest, don't create a new process; + //just instantiate a new cmTest. (Can be disabled for a single test + //if this option is set to false.) + bool OptimizeForCTest; + std::string ProcessOutput; + //The test results + cmCTestTestHandler::cmCTestTestResult TestResult; +}; + +#endif + diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 1494ee619..2ff8e30b2 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -18,6 +18,7 @@ #include "cmCTestTestHandler.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTest.h" +#include "cmCTestRunTest.h" #include "cmake.h" #include "cmGeneratedFileStream.h" #include @@ -589,15 +590,12 @@ int cmCTestTestHandler::ProcessHandler() cmCTestTestResult *result = &this->TestResults[cc]; totalTestTime += result->ExecutionTime; } - this->PrintLabelSummary(); + char buf[1024]; sprintf(buf, "%6.2f sec", totalTestTime); cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time = " << buf << "\n" ); - if ( this->LogFile ) - { - *this->LogFile << "\nTotal Test time = " << buf << std::endl; - } + } if (failed.size()) @@ -659,58 +657,6 @@ int cmCTestTestHandler::ProcessHandler() return 0; } -//---------------------------------------------------------------------- -void cmCTestTestHandler::PrintLabelSummary() -{ - cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin(); - cmCTestTestHandler::TestResultsVector::iterator ri = - this->TestResults.begin(); - std::map labelTimes; - std::set labels; - // initialize maps - for(; it != this->TestList.end(); ++it) - { - cmCTestTestProperties& p = *it; - if(p.Labels.size() != 0) - { - for(std::vector::iterator l = p.Labels.begin(); - l != p.Labels.end(); ++l) - { - labels.insert(*l); - labelTimes[*l] = 0; - } - } - } - it = this->TestList.begin(); - ri = this->TestResults.begin(); - // fill maps - for(; it != this->TestList.end(); ++it, ++ri) - { - cmCTestTestProperties& p = *it; - cmCTestTestResult &result = *ri; - if(p.Labels.size() != 0) - { - for(std::vector::iterator l = p.Labels.begin(); - l != p.Labels.end(); ++l) - { - labelTimes[*l] += result.ExecutionTime; - } - } - } - // now print times - for(std::set::const_iterator i = labels.begin(); - i != labels.end(); ++i) - { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTime in " - << *i << " = " << labelTimes[*i] << " sec" ); - if ( this->LogFile ) - { - *this->LogFile << "\nTime in " << *i << " = " - << labelTimes[*i] << " sec" << std::endl; - } - } -} - //---------------------------------------------------------------------- void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it, std::vector &passed, @@ -950,10 +896,6 @@ void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it, char buf[1024]; sprintf(buf, "%6.2f sec", cres.ExecutionTime); cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" ); - if ( this->LogFile ) - { - *this->LogFile << "\nTest time = " << buf << std::endl; - } if (!output.empty() && output.find("DartStuff.find(output.c_str())) @@ -1599,6 +1541,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector &passed, << "----------------------------------------------------------" << std::endl; std::string last_directory = ""; + // run each test for (ListOfTests::iterator it = this->TestList.begin(); it != this->TestList.end(); it ++ ) @@ -1613,9 +1556,20 @@ void cmCTestTestHandler::ProcessDirectory(std::vector &passed, cmSystemTools::ChangeDirectory(it->Directory.c_str()); } // process this one test - this->ProcessOneTest(&(*it), passed, failed, it->Index, - static_cast(this->TotalNumberOfTests)); - } + cmCTestRunTest testRun; + testRun.SetTestProperties(&(*it)); + testRun.SetTestHandler(this); + + bool testPassed = testRun.Execute(); //run the test + if(testPassed && !this->CTest->GetShowOnly()) + { + passed.push_back(it->Name); + } + else if(!testPassed) + { + failed.push_back(it->Name); + } + } this->EndTest = this->CTest->CurrentTime(); this->EndTestTime = static_cast(cmSystemTools::GetTime()); this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start; diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index b0188e124..fe16e820d 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -30,6 +30,7 @@ class cmMakefile; */ class cmCTestTestHandler : public cmCTestGenericHandler { + friend class cmCTestRunTest; public: cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler); @@ -185,7 +186,6 @@ private: */ virtual void GenerateDartOutput(std::ostream& os); - void PrintLabelSummary(); /** * Run the tests for a directory and any subdirectories */ diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index abf47a21c..0b74107ea 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1192,6 +1192,7 @@ int cmCTest::RunTest(std::vector argv, { if ( output ) { + //ZACH: need to grab the output here tempOutput.insert(tempOutput.end(), data, data+length); } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(data, length)); @@ -1204,6 +1205,7 @@ int cmCTest::RunTest(std::vector argv, cmsysProcess_WaitForExit(cp, 0); if(output && tempOutput.begin() != tempOutput.end()) { + //We are waiting for exit before finally appending to the output output->append(&*tempOutput.begin(), tempOutput.size()); } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "-- Process completed" diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 5eca3c3bf..2a0d4bfcc 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -49,6 +49,7 @@ class cmCTestScriptHandler; class cmCTest { + friend class cmCTestRunTest; public: /** Enumerate parts of the testing and submission process. */ enum Part