diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx index a22c7be41..934481b88 100644 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ b/Source/CTest/cmCTestBatchTestHandler.cxx @@ -89,7 +89,7 @@ void cmCTestBatchTestHandler::WriteTestCommand(int test, std::fstream& fout) command = cmSystemTools::ConvertToOutputPath(command.c_str()); //Prepends memcheck args to our command string if this is a memcheck - this->TestHandler->GenerateTestCommand(processArgs); + this->TestHandler->GenerateTestCommand(processArgs, test); processArgs.push_back(command); for(std::vector::iterator arg = processArgs.begin(); diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 8baa673e7..3ae2ac6a7 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -200,6 +200,7 @@ void cmCTestMemCheckHandler::Initialize() this->CustomMaximumPassedTestOutputSize = 0; this->CustomMaximumFailedTestOutputSize = 0; this->MemoryTester = ""; + this->MemoryTesterDynamicOptions.clear(); this->MemoryTesterOptions.clear(); this->MemoryTesterStyle = UNKNOWN; this->MemoryTesterOutputFile = ""; @@ -242,12 +243,28 @@ int cmCTestMemCheckHandler::PostProcessHandler() //---------------------------------------------------------------------- void cmCTestMemCheckHandler::GenerateTestCommand( - std::vector& args) + std::vector& args, int test) { std::vector::size_type pp; - std::string memcheckcommand = ""; - memcheckcommand + cmStdString index; + cmOStringStream stream; + std::string memcheckcommand = cmSystemTools::ConvertToOutputPath(this->MemoryTester.c_str()); + stream << test; + index = stream.str(); + for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ ) + { + cmStdString arg = this->MemoryTesterDynamicOptions[pp]; + cmStdString::size_type pos = arg.find("??"); + if (pos != cmStdString::npos) + { + arg.replace(pos, 2, index); + } + args.push_back(arg); + memcheckcommand += " \""; + memcheckcommand += arg; + memcheckcommand += "\""; + } for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ ) { args.push_back(this->MemoryTesterOptions[pp]); @@ -478,7 +495,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() = cmSystemTools::ParseArguments(memoryTesterOptions.c_str()); this->MemoryTesterOutputFile - = this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.log"; + = this->CTest->GetBinaryDir() + + "/Testing/Temporary/MemoryChecker.??.log"; switch ( this->MemoryTesterStyle ) { @@ -510,7 +528,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() } std::string outputFile = "--log-file=" + this->MemoryTesterOutputFile; - this->MemoryTesterOptions.push_back(outputFile); + this->MemoryTesterDynamicOptions.push_back(outputFile); break; } case cmCTestMemCheckHandler::PURIFY: @@ -538,19 +556,19 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() outputFile = "-log-file="; #endif outputFile += this->MemoryTesterOutputFile; - this->MemoryTesterOptions.push_back(outputFile); + this->MemoryTesterDynamicOptions.push_back(outputFile); break; } case cmCTestMemCheckHandler::BOUNDS_CHECKER: { this->BoundsCheckerXMLFile = this->MemoryTesterOutputFile; std::string dpbdFile = this->CTest->GetBinaryDir() - + "/Testing/Temporary/MemoryChecker.DPbd"; + + "/Testing/Temporary/MemoryChecker.??.DPbd"; this->BoundsCheckerDPBDFile = dpbdFile; - this->MemoryTesterOptions.push_back("/B"); - this->MemoryTesterOptions.push_back(dpbdFile); - this->MemoryTesterOptions.push_back("/X"); - this->MemoryTesterOptions.push_back(this->MemoryTesterOutputFile); + this->MemoryTesterDynamicOptions.push_back("/B"); + this->MemoryTesterDynamicOptions.push_back(dpbdFile); + this->MemoryTesterDynamicOptions.push_back("/X"); + this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile); this->MemoryTesterOptions.push_back("/M"); break; } @@ -898,25 +916,23 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( // This method puts the bounds checker output file into the output // for the test void -cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res) +cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res, + int test) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessBoundsCheckerTest for : " << res.Name.c_str() << std::endl); - if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) ) + cmStdString ofile = testOutputFileName(test); + if ( ofile.empty() ) { - std::string log = "Cannot find memory tester output file: " - + this->MemoryTesterOutputFile; - cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } // put a scope around this to close ifs so the file can be removed { - std::ifstream ifs(this->MemoryTesterOutputFile.c_str()); + std::ifstream ifs(ofile.c_str()); if ( !ifs ) { - std::string log = "Cannot read memory tester output file: " - + this->MemoryTesterOutputFile; + std::string log = "Cannot read memory tester output file: " + ofile; cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } @@ -939,38 +955,39 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res) } void -cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res) +cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res, + int test) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessPurifyTest for : " << res.Name.c_str() << std::endl); - appendMemTesterOutput(res); + appendMemTesterOutput(res, test); } void -cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res) +cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res, + int test) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "PostProcessValgrindTest for : " << res.Name.c_str() << std::endl); - appendMemTesterOutput(res); + appendMemTesterOutput(res, test); } void -cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res) +cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res, + int test) { - if ( !cmSystemTools::FileExists(this->MemoryTesterOutputFile.c_str()) ) + cmStdString ofile = testOutputFileName(test); + + if ( ofile.empty() ) { - std::string log = "Cannot find memory tester output file: " - + this->MemoryTesterOutputFile; - cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } - std::ifstream ifs(this->MemoryTesterOutputFile.c_str()); + std::ifstream ifs(ofile.c_str()); if ( !ifs ) { - std::string log = "Cannot read memory tester output file: " - + this->MemoryTesterOutputFile; + std::string log = "Cannot read memory tester output file: " + ofile; cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); return; } @@ -981,3 +998,25 @@ cmCTestMemCheckHandler::appendMemTesterOutput(cmCTestTestResult& res) res.Output += "\n"; } } + +cmStdString +cmCTestMemCheckHandler::testOutputFileName(int test) +{ + cmStdString index; + cmOStringStream stream; + stream << test; + index = stream.str(); + cmStdString ofile = this->MemoryTesterOutputFile; + cmStdString::size_type pos = ofile.find("??"); + ofile.replace(pos, 2, index); + + if ( !cmSystemTools::FileExists(ofile.c_str()) ) + { + std::string log = "Cannot find memory tester output file: " + + ofile; + cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl); + ofile = ""; + } + + return ofile; +} diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index 0a8c1b3f0..040d2e092 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -37,7 +37,7 @@ public: protected: virtual int PreProcessHandler(); virtual int PostProcessHandler(); - virtual void GenerateTestCommand(std::vector& args); + virtual void GenerateTestCommand(std::vector& args, int test); private: @@ -89,6 +89,7 @@ private: std::string BoundsCheckerDPBDFile; std::string BoundsCheckerXMLFile; std::string MemoryTester; + std::vector MemoryTesterDynamicOptions; std::vector MemoryTesterOptions; int MemoryTesterStyle; std::string MemoryTesterOutputFile; @@ -117,12 +118,16 @@ private: bool ProcessMemCheckBoundsCheckerOutput(const std::string& str, std::string& log, int* results); - void PostProcessPurifyTest(cmCTestTestResult& res); - void PostProcessBoundsCheckerTest(cmCTestTestResult& res); - void PostProcessValgrindTest(cmCTestTestResult& res); + void PostProcessPurifyTest(cmCTestTestResult& res, int test); + void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test); + void PostProcessValgrindTest(cmCTestTestResult& res, int test); ///! append MemoryTesterOutputFile to the test log - void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res); + void appendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res, + int test); + + ///! generate the output filename for the given test index + cmStdString testOutputFileName(int test); }; #endif diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index ddd7e4545..0e2fa41b9 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -389,13 +389,13 @@ void cmCTestRunTest::MemCheckPostProcess() switch ( handler->MemoryTesterStyle ) { case cmCTestMemCheckHandler::VALGRIND: - handler->PostProcessValgrindTest(this->TestResult); + handler->PostProcessValgrindTest(this->TestResult, this->Index); break; case cmCTestMemCheckHandler::PURIFY: - handler->PostProcessPurifyTest(this->TestResult); + handler->PostProcessPurifyTest(this->TestResult, this->Index); break; case cmCTestMemCheckHandler::BOUNDS_CHECKER: - handler->PostProcessBoundsCheckerTest(this->TestResult); + handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index); break; default: break; @@ -524,7 +524,7 @@ void cmCTestRunTest::ComputeArguments() = cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str()); //Prepends memcheck args to our command string - this->TestHandler->GenerateTestCommand(this->Arguments); + this->TestHandler->GenerateTestCommand(this->Arguments, this->Index); for(std::vector::iterator i = this->Arguments.begin(); i != this->Arguments.end(); ++i) { diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 7a3edb5c3..497774d1b 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -1107,7 +1107,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector &passed, } //---------------------------------------------------------------------- -void cmCTestTestHandler::GenerateTestCommand(std::vector&) +void cmCTestTestHandler::GenerateTestCommand(std::vector&, int) { } diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 8e59e5915..93b793b20 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -153,7 +153,7 @@ protected: // compute a final test list virtual int PreProcessHandler(); virtual int PostProcessHandler(); - virtual void GenerateTestCommand(std::vector& args); + virtual void GenerateTestCommand(std::vector& args, int test); int ExecuteCommands(std::vector& vec); void WriteTestResultHeader(std::ostream& os, cmCTestTestResult* result); diff --git a/Tests/CTestTestMemcheck/CMakeLists.txt b/Tests/CTestTestMemcheck/CMakeLists.txt index 2db92826a..86d73854b 100644 --- a/Tests/CTestTestMemcheck/CMakeLists.txt +++ b/Tests/CTestTestMemcheck/CMakeLists.txt @@ -66,6 +66,7 @@ function(gen_mc_test NAME CHECKER) -D PSEUDO_PURIFY=$ -D PSEUDO_VALGRIND=$ -D ERROR_COMMAND=$ + ${ARGN} ) endfunction(gen_mc_test) @@ -74,10 +75,11 @@ function(gen_mcnl_test NAME CHECKER) -D PSEUDO_BC=$ -D PSEUDO_PURIFY=$ -D PSEUDO_VALGRIND=$ + ${ARGN} ) set_tests_properties(CTestTestMemcheck${NAME} PROPERTIES - PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/Testing/Temporary/MemoryChecker.log\n(.*\n)?Error in read script: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/test.cmake\n") + PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/Testing/Temporary/MemoryChecker.1.log\n(.*\n)?Error in read script: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/${NAME}/test.cmake\n") endfunction(gen_mcnl_test) unset(CTEST_EXTRA_CONFIG) @@ -109,14 +111,17 @@ set(CTEST_EXTRA_CONFIG "set(CTEST_CUSTOM_MEMCHECK_IGNORE RunCMakeAgain)\n") set(CMAKELISTS_EXTRA_CODE "add_test(NAME RunCMakeAgain COMMAND \"\${CMAKE_COMMAND}\" --version)") gen_mc_test(DummyValgrindIgnoreMemcheck "\${PSEUDO_VALGRIND}") +unset(CTEST_EXTRA_CONFIG) +gen_mc_test(DummyValgrindTwoTargets "\${PSEUDO_VALGRIND}" "-VV") + set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE \"\${CMAKE_CURRENT_BINARY_DIR}/does-not-exist\")") unset(CMAKELISTS_EXTRA_CODE) gen_mc_test(DummyValgrindInvalidSupFile "\${PSEUDO_VALGRIND}") -# CTest will add the logfile option as last option. Tell the dummy memcheck -# to ignore that argument. This will cause the logfile to be missing, which -# will be the prove for us that the custom option is indeed used. -set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"--\")") +# CTest will add the logfile option before any custom options. Set the logfile +# again, this time to an empty string. This will cause the logfile to be +# missing, which will be the prove for us that the custom option is indeed used. +set(CTEST_EXTRA_CONFIG "set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"--log-file=\")") gen_mc_test(DummyValgrindCustomOptions "\${PSEUDO_VALGRIND}") unset(CTEST_EXTRA_CONFIG) @@ -161,4 +166,8 @@ set_tests_properties(CTestTestMemcheckDummyValgrindInvalidSupFile PROPERTIES PASS_REGULAR_EXPRESSION "\nCannot find memory checker suppression file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/does-not-exist\n") set_tests_properties(CTestTestMemcheckDummyValgrindCustomOptions PROPERTIES - PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/Testing/Temporary/MemoryChecker.log\n(.*\n)?Error in read script: ${CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/test.cmake\n") + PASS_REGULAR_EXPRESSION "\nCannot find memory tester output file: ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/Testing/Temporary/MemoryChecker.1.log\n(.*\n)?Error in read script: ${CMAKE_CURRENT_BINARY_DIR}/DummyValgrindCustomOptions/test.cmake\n") + +set_tests_properties(CTestTestMemcheckDummyValgrindTwoTargets PROPERTIES + PASS_REGULAR_EXPRESSION + "\nMemory check project ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets\n.*\n *Start 1: RunCMake\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.1.log\" \"-q\".*\n *Start 2: RunCMakeAgain\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.2.log\" \"-q\".*\n") diff --git a/Tests/CTestTestMemcheck/memtester.cxx.in b/Tests/CTestTestMemcheck/memtester.cxx.in index da6f5a459..55a34e34f 100644 --- a/Tests/CTestTestMemcheck/memtester.cxx.in +++ b/Tests/CTestTestMemcheck/memtester.cxx.in @@ -28,12 +28,6 @@ main(int argc, char **argv) std::string logfile; for (int i = 1; i < argc; i++) { std::string arg = argv[i]; - // stop processing options, this allows to force - // the logfile to be ignored - if (arg == "--") - { - break; - } if (arg.find(logarg) == 0) { if (nextarg) @@ -46,7 +40,7 @@ main(int argc, char **argv) { logfile = arg.substr(logarg.length()); } - break; + // keep searching, it may be overridden later to provoke an error } }