Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CTest / cmCTestTestHandler.cxx
blobb22d8cfbe14859c23bb87dd7522bf8f7ebfea5a2
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestTestHandler.cxx,v $
5 Language: C++
6 Date: $Date: 2009-02-27 21:28:07 $
7 Version: $Revision: 1.94 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "cmCTestTestHandler.h"
19 #include "cmCTestMultiProcessHandler.h"
20 #include "cmCTest.h"
21 #include "cmake.h"
22 #include "cmGeneratedFileStream.h"
23 #include <cmsys/Process.h>
24 #include <cmsys/RegularExpression.hxx>
25 #include <cmsys/Base64.h>
26 #include "cmMakefile.h"
27 #include "cmGlobalGenerator.h"
28 #include "cmLocalGenerator.h"
29 #include "cmCommand.h"
30 #include "cmSystemTools.h"
31 #include "cmXMLSafe.h"
33 #include <stdlib.h>
34 #include <math.h>
35 #include <float.h>
37 #include <memory> // auto_ptr
39 //----------------------------------------------------------------------
40 class cmCTestSubdirCommand : public cmCommand
42 public:
43 /**
44 * This is a virtual constructor for the command.
46 virtual cmCommand* Clone()
48 cmCTestSubdirCommand* c = new cmCTestSubdirCommand;
49 c->TestHandler = this->TestHandler;
50 return c;
53 /**
54 * This is called when the command is first encountered in
55 * the CMakeLists.txt file.
57 virtual bool InitialPass(std::vector<std::string> const& args,
58 cmExecutionStatus &);
60 /**
61 * The name of the command as specified in CMakeList.txt.
63 virtual const char* GetName() { return "subdirs";}
65 // Unused methods
66 virtual const char* GetTerseDocumentation() { return ""; }
67 virtual const char* GetFullDocumentation() { return ""; }
69 cmTypeMacro(cmCTestSubdirCommand, cmCommand);
71 cmCTestTestHandler* TestHandler;
74 //----------------------------------------------------------------------
75 bool cmCTestSubdirCommand
76 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
78 if(args.size() < 1 )
80 this->SetError("called with incorrect number of arguments");
81 return false;
83 std::vector<std::string>::const_iterator it;
84 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
85 for ( it = args.begin(); it != args.end(); ++ it )
87 cmSystemTools::ChangeDirectory(cwd.c_str());
88 std::string fname = cwd;
89 fname += "/";
90 fname += *it;
92 if ( !cmSystemTools::FileExists(fname.c_str()) )
94 // No subdirectory? So what...
95 continue;
97 cmSystemTools::ChangeDirectory(fname.c_str());
98 const char* testFilename;
99 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
101 // does the CTestTestfile.cmake exist ?
102 testFilename = "CTestTestfile.cmake";
104 else if( cmSystemTools::FileExists("DartTestfile.txt") )
106 // does the DartTestfile.txt exist ?
107 testFilename = "DartTestfile.txt";
109 else
111 // No CTestTestfile? Who cares...
112 cmSystemTools::ChangeDirectory(cwd.c_str());
113 continue;
115 fname += "/";
116 fname += testFilename;
117 bool readit =
118 this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
119 fname.c_str());
120 cmSystemTools::ChangeDirectory(cwd.c_str());
121 if(!readit)
123 std::string m = "Could not find include file: ";
124 m += fname;
125 this->SetError(m.c_str());
126 return false;
129 return true;
132 //----------------------------------------------------------------------
133 class cmCTestAddSubdirectoryCommand : public cmCommand
135 public:
137 * This is a virtual constructor for the command.
139 virtual cmCommand* Clone()
141 cmCTestAddSubdirectoryCommand* c = new cmCTestAddSubdirectoryCommand;
142 c->TestHandler = this->TestHandler;
143 return c;
147 * This is called when the command is first encountered in
148 * the CMakeLists.txt file.
150 virtual bool InitialPass(std::vector<std::string> const& args,
151 cmExecutionStatus &);
154 * The name of the command as specified in CMakeList.txt.
156 virtual const char* GetName() { return "add_subdirectory";}
158 // Unused methods
159 virtual const char* GetTerseDocumentation() { return ""; }
160 virtual const char* GetFullDocumentation() { return ""; }
162 cmTypeMacro(cmCTestAddSubdirectoryCommand, cmCommand);
164 cmCTestTestHandler* TestHandler;
167 //----------------------------------------------------------------------
168 bool cmCTestAddSubdirectoryCommand
169 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
171 if(args.size() < 1 )
173 this->SetError("called with incorrect number of arguments");
174 return false;
177 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
178 cmSystemTools::ChangeDirectory(cwd.c_str());
179 std::string fname = cwd;
180 fname += "/";
181 fname += args[1];
183 if ( !cmSystemTools::FileExists(fname.c_str()) )
185 // No subdirectory? So what...
186 return true;
188 cmSystemTools::ChangeDirectory(fname.c_str());
189 const char* testFilename;
190 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
192 // does the CTestTestfile.cmake exist ?
193 testFilename = "CTestTestfile.cmake";
195 else if( cmSystemTools::FileExists("DartTestfile.txt") )
197 // does the DartTestfile.txt exist ?
198 testFilename = "DartTestfile.txt";
200 else
202 // No CTestTestfile? Who cares...
203 cmSystemTools::ChangeDirectory(cwd.c_str());
204 return true;
206 fname += "/";
207 fname += testFilename;
208 bool readit =
209 this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
210 fname.c_str());
211 cmSystemTools::ChangeDirectory(cwd.c_str());
212 if(!readit)
214 std::string m = "Could not find include file: ";
215 m += fname;
216 this->SetError(m.c_str());
217 return false;
219 return true;
222 //----------------------------------------------------------------------
223 class cmCTestAddTestCommand : public cmCommand
225 public:
227 * This is a virtual constructor for the command.
229 virtual cmCommand* Clone()
231 cmCTestAddTestCommand* c = new cmCTestAddTestCommand;
232 c->TestHandler = this->TestHandler;
233 return c;
237 * This is called when the command is first encountered in
238 * the CMakeLists.txt file.
240 virtual bool InitialPass(std::vector<std::string> const&,
241 cmExecutionStatus &);
244 * The name of the command as specified in CMakeList.txt.
246 virtual const char* GetName() { return "ADD_TEST";}
248 // Unused methods
249 virtual const char* GetTerseDocumentation() { return ""; }
250 virtual const char* GetFullDocumentation() { return ""; }
252 cmTypeMacro(cmCTestAddTestCommand, cmCommand);
254 cmCTestTestHandler* TestHandler;
257 //----------------------------------------------------------------------
258 bool cmCTestAddTestCommand
259 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
261 if ( args.size() < 2 )
263 this->SetError("called with incorrect number of arguments");
264 return false;
266 return this->TestHandler->AddTest(args);
269 //----------------------------------------------------------------------
270 class cmCTestSetTestsPropertiesCommand : public cmCommand
272 public:
274 * This is a virtual constructor for the command.
276 virtual cmCommand* Clone()
278 cmCTestSetTestsPropertiesCommand* c
279 = new cmCTestSetTestsPropertiesCommand;
280 c->TestHandler = this->TestHandler;
281 return c;
285 * This is called when the command is first encountered in
286 * the CMakeLists.txt file.
288 virtual bool InitialPass(std::vector<std::string> const&,
289 cmExecutionStatus &);
292 * The name of the command as specified in CMakeList.txt.
294 virtual const char* GetName() { return "SET_TESTS_PROPERTIES";}
296 // Unused methods
297 virtual const char* GetTerseDocumentation() { return ""; }
298 virtual const char* GetFullDocumentation() { return ""; }
300 cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);
302 cmCTestTestHandler* TestHandler;
305 //----------------------------------------------------------------------
306 bool cmCTestSetTestsPropertiesCommand
307 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
309 return this->TestHandler->SetTestsProperties(args);
312 //----------------------------------------------------------------------
313 // get the next number in a string with numbers separated by ,
314 // pos is the start of the search and pos2 is the end of the search
315 // pos becomes pos2 after a call to GetNextNumber.
316 // -1 is returned at the end of the list.
317 inline int GetNextNumber(std::string const& in,
318 int& val,
319 std::string::size_type& pos,
320 std::string::size_type& pos2)
322 pos2 = in.find(',', pos);
323 if(pos2 != in.npos)
325 if(pos2-pos == 0)
327 val = -1;
329 else
331 val = atoi(in.substr(pos, pos2-pos).c_str());
333 pos = pos2+1;
334 return 1;
336 else
338 if(in.size()-pos == 0)
340 val = -1;
342 else
344 val = atoi(in.substr(pos, in.size()-pos).c_str());
346 return 0;
350 //----------------------------------------------------------------------
351 // get the next number in a string with numbers separated by ,
352 // pos is the start of the search and pos2 is the end of the search
353 // pos becomes pos2 after a call to GetNextNumber.
354 // -1 is returned at the end of the list.
355 inline int GetNextRealNumber(std::string const& in,
356 double& val,
357 std::string::size_type& pos,
358 std::string::size_type& pos2)
360 pos2 = in.find(',', pos);
361 if(pos2 != in.npos)
363 if(pos2-pos == 0)
365 val = -1;
367 else
369 val = atof(in.substr(pos, pos2-pos).c_str());
371 pos = pos2+1;
372 return 1;
374 else
376 if(in.size()-pos == 0)
378 val = -1;
380 else
382 val = atof(in.substr(pos, in.size()-pos).c_str());
384 return 0;
389 //----------------------------------------------------------------------
390 cmCTestTestHandler::cmCTestTestHandler()
392 this->UseUnion = false;
394 this->UseIncludeLabelRegExpFlag = false;
395 this->UseExcludeLabelRegExpFlag = false;
396 this->UseIncludeRegExpFlag = false;
397 this->UseExcludeRegExpFlag = false;
398 this->UseExcludeRegExpFirst = false;
400 this->CustomMaximumPassedTestOutputSize = 1 * 1024;
401 this->CustomMaximumFailedTestOutputSize = 300 * 1024;
403 this->MemCheck = false;
405 this->LogFile = 0;
407 // regex to detect <DartMeasurement>...</DartMeasurement>
408 this->DartStuff.compile(
409 "(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
410 // regex to detect each individual <DartMeasurement>...</DartMeasurement>
411 this->DartStuff1.compile(
412 "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)");
415 //----------------------------------------------------------------------
416 void cmCTestTestHandler::Initialize()
418 this->Superclass::Initialize();
420 this->ElapsedTestingTime = -1;
422 this->TestResults.clear();
424 this->CustomTestsIgnore.clear();
425 this->StartTest = "";
426 this->EndTest = "";
428 this->CustomPreTest.clear();
429 this->CustomPostTest.clear();
430 this->CustomMaximumPassedTestOutputSize = 1 * 1024;
431 this->CustomMaximumFailedTestOutputSize = 300 * 1024;
433 this->TestsToRun.clear();
435 this->UseIncludeRegExpFlag = false;
436 this->UseExcludeRegExpFlag = false;
437 this->UseExcludeRegExpFirst = false;
438 this->IncludeLabelRegularExpression = "";
439 this->ExcludeLabelRegularExpression = "";
440 this->IncludeRegExp = "";
441 this->ExcludeRegExp = "";
443 TestsToRunString = "";
444 this->UseUnion = false;
445 this->TestList.clear();
448 //----------------------------------------------------------------------
449 void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
451 this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
452 this->CustomPreTest);
453 this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
454 this->CustomPostTest);
455 this->CTest->PopulateCustomVector(mf,
456 "CTEST_CUSTOM_TESTS_IGNORE",
457 this->CustomTestsIgnore);
458 this->CTest->PopulateCustomInteger(mf,
459 "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
460 this->CustomMaximumPassedTestOutputSize);
461 this->CTest->PopulateCustomInteger(mf,
462 "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
463 this->CustomMaximumFailedTestOutputSize);
466 //----------------------------------------------------------------------
467 int cmCTestTestHandler::PreProcessHandler()
469 if ( !this->ExecuteCommands(this->CustomPreTest) )
471 cmCTestLog(this->CTest, ERROR_MESSAGE,
472 "Problem executing pre-test command(s)." << std::endl);
473 return 0;
475 return 1;
478 //----------------------------------------------------------------------
479 int cmCTestTestHandler::PostProcessHandler()
481 if ( !this->ExecuteCommands(this->CustomPostTest) )
483 cmCTestLog(this->CTest, ERROR_MESSAGE,
484 "Problem executing post-test command(s)." << std::endl);
485 return 0;
487 return 1;
490 //----------------------------------------------------------------------
491 //clearly it would be nice if this were broken up into a few smaller
492 //functions and commented...
493 int cmCTestTestHandler::ProcessHandler()
495 // Update internal data structure from generic one
496 this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
497 this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion")));
498 const char* val;
499 val = this->GetOption("LabelRegularExpression");
500 if ( val )
502 this->UseIncludeLabelRegExpFlag = true;
503 this->IncludeLabelRegExp = val;
505 val = this->GetOption("ExcludeLabelRegularExpression");
506 if ( val )
508 this->UseExcludeLabelRegExpFlag = true;
509 this->ExcludeLabelRegularExpression = val;
511 val = this->GetOption("IncludeRegularExpression");
512 if ( val )
514 this->UseIncludeRegExp();
515 this->SetIncludeRegExp(val);
517 val = this->GetOption("ExcludeRegularExpression");
518 if ( val )
520 this->UseExcludeRegExp();
521 this->SetExcludeRegExp(val);
524 this->TestResults.clear();
525 // do not output startup if this is a sub-process for parallel tests
526 if(!this->CTest->GetParallelSubprocess())
528 cmCTestLog(this->CTest, HANDLER_OUTPUT,
529 (this->MemCheck ? "Memory check" : "Test")
530 << " project " << cmSystemTools::GetCurrentWorkingDirectory()
531 << std::endl);
533 if ( ! this->PreProcessHandler() )
535 return -1;
538 cmGeneratedFileStream mLogFile;
539 this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
540 this->LogFile = &mLogFile;
542 std::vector<cmStdString> passed;
543 std::vector<cmStdString> failed;
544 int total;
545 this->ProcessDirectory(passed, failed);
547 total = int(passed.size()) + int(failed.size());
549 if (total == 0)
551 if ( !this->CTest->GetShowOnly() )
553 cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!"
554 << std::endl);
557 else
559 if (this->HandlerVerbose && passed.size() &&
560 (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag))
562 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
563 << "The following tests passed:" << std::endl);
564 for(std::vector<cmStdString>::iterator j = passed.begin();
565 j != passed.end(); ++j)
567 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\t" << *j
568 << std::endl);
572 float percent = float(passed.size()) * 100.0f / total;
573 if ( failed.size() > 0 && percent > 99)
575 percent = 99;
577 if(!this->CTest->GetParallelSubprocess())
579 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
580 << static_cast<int>(percent + .5) << "% tests passed, "
581 << failed.size() << " tests failed out of "
582 << total << std::endl);
585 if (failed.size())
587 cmGeneratedFileStream ofs;
588 if(!this->CTest->GetParallelSubprocess())
590 cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
591 << "The following tests FAILED:" << std::endl);
592 this->StartLogFile("TestsFailed", ofs);
594 std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
595 for(ftit = this->TestResults.begin();
596 ftit != this->TestResults.end(); ++ftit)
598 if ( ftit->Status != cmCTestTestHandler::COMPLETED )
600 ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
601 cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
602 << ftit->TestCount << " - "
603 << ftit->Name.c_str() << " ("
604 << this->GetTestStatus(ftit->Status) << ")"
605 << std::endl);
613 if ( this->CTest->GetProduceXML() )
615 cmGeneratedFileStream xmlfile;
616 if( !this->StartResultingXML(
617 (this->MemCheck ? cmCTest::PartMemCheck : cmCTest::PartTest),
618 (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile) )
620 cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create "
621 << (this->MemCheck ? "memory check" : "testing")
622 << " XML file" << std::endl);
623 this->LogFile = 0;
624 return 1;
626 this->GenerateDartOutput(xmlfile);
629 if ( ! this->PostProcessHandler() )
631 this->LogFile = 0;
632 return -1;
635 if ( !failed.empty() )
637 this->LogFile = 0;
638 return -1;
640 this->LogFile = 0;
641 return 0;
644 //----------------------------------------------------------------------
645 void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it,
646 std::vector<cmStdString> &passed,
647 std::vector<cmStdString> &failed,
648 int cnt, int tmsize)
650 const std::string& testname = it->Name;
651 std::vector<std::string>& args = it->Args;
652 cmCTestTestResult cres;
653 cres.Properties = &*it;
654 cres.ExecutionTime = 0;
655 cres.ReturnValue = -1;
656 cres.Status = cmCTestTestHandler::NOT_RUN;
657 cres.TestCount = cnt;
658 cres.Name = testname;
659 cres.Path = it->Directory.c_str();
661 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << cnt << "/");
662 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << tmsize << " ");
663 if ( this->MemCheck )
665 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
667 else
669 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
671 cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
672 const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
673 std::string outname = testname + " ";
674 outname.resize(maxTestNameWidth, '.');
675 *this->LogFile << cnt << "/" << tmsize << " Testing: " << testname
676 << std::endl;
678 if ( this->CTest->GetShowOnly() )
680 cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
682 else
684 cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
687 cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... ");
688 // find the test executable
689 std::string actualCommand = this->FindTheExecutable(args[1].c_str());
690 std::string testCommand
691 = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
693 // continue if we did not find the executable
694 if (testCommand == "")
696 *this->LogFile << "Unable to find executable: " << args[1].c_str()
697 << std::endl;
698 cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
699 << args[1].c_str() << std::endl);
700 cres.Output = "Unable to find executable: " + args[1];
701 if ( !this->CTest->GetShowOnly() )
703 cres.FullCommandLine = actualCommand;
704 this->TestResults.push_back( cres );
705 failed.push_back(testname);
706 return;
710 // add the arguments
711 std::vector<std::string>::const_iterator j = args.begin();
712 ++j; // skip test name
713 ++j; // skip command as it is in actualCommand
714 std::vector<const char*> arguments;
715 this->GenerateTestCommand(arguments);
716 arguments.push_back(actualCommand.c_str());
717 for(;j != args.end(); ++j)
719 testCommand += " ";
720 testCommand += cmSystemTools::EscapeSpaces(j->c_str());
721 arguments.push_back(j->c_str());
723 arguments.push_back(0);
726 * Run an executable command and put the stdout in output.
728 std::string output;
729 int retVal = 0;
732 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
733 << (this->MemCheck?"MemCheck":"Test")
734 << " command: " << testCommand
735 << std::endl);
736 *this->LogFile << cnt << "/" << tmsize
737 << " Test: " << testname.c_str() << std::endl;
738 *this->LogFile << "Command: ";
739 std::vector<cmStdString>::size_type ll;
740 for ( ll = 0; ll < arguments.size()-1; ll ++ )
742 *this->LogFile << "\"" << arguments[ll] << "\" ";
744 *this->LogFile
745 << std::endl
746 << "Directory: " << it->Directory << std::endl
747 << "\"" << testname.c_str() << "\" start time: "
748 << this->CTest->CurrentTime() << std::endl
749 << "Output:" << std::endl
750 << "----------------------------------------------------------"
751 << std::endl;
752 int res = 0;
753 double clock_start, clock_finish;
754 clock_start = cmSystemTools::GetTime();
756 if ( !this->CTest->GetShowOnly() )
758 res = this->CTest->RunTest(arguments, &output, &retVal, this->LogFile,
759 it->Timeout, &it->Environment);
762 clock_finish = cmSystemTools::GetTime();
766 cres.ExecutionTime = (double)(clock_finish - clock_start);
767 cres.FullCommandLine = testCommand;
768 std::string reason;
769 if ( !this->CTest->GetShowOnly() )
771 bool testFailed = false;
772 std::vector<std::pair<cmsys::RegularExpression,
773 std::string> >::iterator passIt;
774 bool forceFail = false;
775 if ( it->RequiredRegularExpressions.size() > 0 )
777 bool found = false;
778 for ( passIt = it->RequiredRegularExpressions.begin();
779 passIt != it->RequiredRegularExpressions.end();
780 ++ passIt )
782 if ( passIt->first.find(output.c_str()) )
784 found = true;
785 reason = "Required regular expression found.";
788 if ( !found )
790 reason = "Required regular expression not found.";
791 forceFail = true;
793 reason += "Regex=[";
794 for ( passIt = it->RequiredRegularExpressions.begin();
795 passIt != it->RequiredRegularExpressions.end();
796 ++ passIt )
798 reason += passIt->second;
799 reason += "\n";
801 reason += "]";
803 if ( it->ErrorRegularExpressions.size() > 0 )
805 for ( passIt = it->ErrorRegularExpressions.begin();
806 passIt != it->ErrorRegularExpressions.end();
807 ++ passIt )
809 if ( passIt->first.find(output.c_str()) )
811 reason = "Error regular expression found in output.";
812 reason += " Regex=[";
813 reason += passIt->second;
814 reason += "]";
815 forceFail = true;
820 if (res == cmsysProcess_State_Exited &&
821 (retVal == 0 || it->RequiredRegularExpressions.size()) &&
822 !forceFail)
824 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed");
825 if ( it->WillFail )
827 cmCTestLog(this->CTest, HANDLER_OUTPUT, " - But it should fail!");
828 cres.Status = cmCTestTestHandler::FAILED;
829 testFailed = true;
831 else
833 cres.Status = cmCTestTestHandler::COMPLETED;
835 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
837 else
839 testFailed = true;
841 cres.Status = cmCTestTestHandler::FAILED;
842 if ( res == cmsysProcess_State_Expired )
844 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout" << std::endl);
845 cres.Status = cmCTestTestHandler::TIMEOUT;
847 else if ( res == cmsysProcess_State_Exception )
849 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
850 switch ( retVal )
852 case cmsysProcess_Exception_Fault:
853 cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
854 cres.Status = cmCTestTestHandler::SEGFAULT;
855 break;
856 case cmsysProcess_Exception_Illegal:
857 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
858 cres.Status = cmCTestTestHandler::ILLEGAL;
859 break;
860 case cmsysProcess_Exception_Interrupt:
861 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
862 cres.Status = cmCTestTestHandler::INTERRUPT;
863 break;
864 case cmsysProcess_Exception_Numerical:
865 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
866 cres.Status = cmCTestTestHandler::NUMERICAL;
867 break;
868 default:
869 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
870 cres.Status = cmCTestTestHandler::OTHER_FAULT;
872 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
874 else if ( res == cmsysProcess_State_Error )
876 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res
877 << std::endl);
878 cres.Status = cmCTestTestHandler::BAD_COMMAND;
880 else
882 // Force fail will also be here?
883 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason);
884 if ( it->WillFail )
886 cres.Status = cmCTestTestHandler::COMPLETED;
887 cmCTestLog(this->CTest, HANDLER_OUTPUT, " - supposed to fail");
888 testFailed = false;
890 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
893 if ( testFailed )
895 failed.push_back(testname);
897 else
899 passed.push_back(testname);
901 if (!output.empty() && output.find("<DartMeasurement") != output.npos)
903 if (this->DartStuff.find(output.c_str()))
905 std::string dartString = this->DartStuff.match(1);
906 // keep searching and replacing until none are left
907 while (this->DartStuff1.find(output.c_str()))
909 // replace the exact match for the string
910 cmSystemTools::ReplaceString(output,
911 this->DartStuff1.match(1).c_str(), "");
913 cres.RegressionImages
914 = this->GenerateRegressionImages(dartString);
919 // if this is doing MemCheck then all the output needs to be put into
920 // Output since that it what is parsed to by cmCTestMemCheckHandler
921 if(!this->MemCheck)
923 if ( cres.Status == cmCTestTestHandler::COMPLETED )
925 this->CleanTestOutput(output, static_cast<size_t>
926 (this->CustomMaximumPassedTestOutputSize));
928 else
930 this->CleanTestOutput(output, static_cast<size_t>
931 (this->CustomMaximumFailedTestOutputSize));
934 cres.Reason = reason;
935 if ( this->LogFile )
937 bool pass = true;
938 const char* reasonType = "Test Pass Reason";
939 if(cres.Status != cmCTestTestHandler::COMPLETED &&
940 cres.Status != cmCTestTestHandler::NOT_RUN)
942 reasonType = "Test Fail Reason";
943 pass = false;
945 double ttime = clock_finish - clock_start;
946 int hours = static_cast<int>(ttime / (60 * 60));
947 int minutes = static_cast<int>(ttime / 60) % 60;
948 int seconds = static_cast<int>(ttime) % 60;
949 char buffer[100];
950 sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
951 *this->LogFile
952 << "----------------------------------------------------------"
953 << std::endl;
954 if(cres.Reason.size())
956 *this->LogFile << reasonType << ":\n" << cres.Reason << "\n";
958 else
960 if(pass)
962 *this->LogFile << "Test Passed.\n";
964 else
966 *this->LogFile << "Test Failed.\n";
969 *this->LogFile << "\"" << testname.c_str() << "\" end time: "
970 << this->CTest->CurrentTime() << std::endl
971 << "\"" << testname.c_str() << "\" time elapsed: "
972 << buffer << std::endl
973 << "----------------------------------------------------------"
974 << std::endl << std::endl;
976 cres.Output = output;
977 cres.ReturnValue = retVal;
978 cres.CompletionStatus = "Completed";
979 this->TestResults.push_back( cres );
982 //----------------------------------------------------------------------
983 void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
985 // if not using Labels to filter then return
986 if (!this->UseIncludeLabelRegExpFlag )
988 return;
990 // if there are no labels and we are filtering by labels
991 // then exclude the test as it does not have the label
992 if(it.Labels.size() == 0 )
994 it.IsInBasedOnREOptions = false;
995 return;
997 // check to see if the label regular expression matches
998 bool found = false; // assume it does not match
999 // loop over all labels and look for match
1000 for(std::vector<std::string>::iterator l = it.Labels.begin();
1001 l != it.Labels.end(); ++l)
1003 if(this->IncludeLabelRegularExpression.find(*l))
1005 found = true;
1008 // if no match was found, exclude the test
1009 if(!found)
1011 it.IsInBasedOnREOptions = false;
1016 //----------------------------------------------------------------------
1017 void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
1019 // if not using Labels to filter then return
1020 if (!this->UseExcludeLabelRegExpFlag )
1022 return;
1024 // if there are no labels and we are excluding by labels
1025 // then do nothing as a no label can not be a match
1026 if(it.Labels.size() == 0 )
1028 return;
1030 // check to see if the label regular expression matches
1031 bool found = false; // assume it does not match
1032 // loop over all labels and look for match
1033 for(std::vector<std::string>::iterator l = it.Labels.begin();
1034 l != it.Labels.end(); ++l)
1036 if(this->ExcludeLabelRegularExpression.find(*l))
1038 found = true;
1041 // if match was found, exclude the test
1042 if(found)
1044 it.IsInBasedOnREOptions = false;
1048 //----------------------------------------------------------------------
1049 void cmCTestTestHandler::CheckLabelFilter(cmCTestTestProperties& it)
1051 this->CheckLabelFilterInclude(it);
1052 this->CheckLabelFilterExclude(it);
1055 //----------------------------------------------------------------------
1056 void cmCTestTestHandler::ComputeTestList()
1058 this->TestList.clear(); // clear list of test
1059 if(this->CTest->GetParallelSubprocess())
1061 this->LoadTestList();
1062 return;
1064 else
1066 this->GetListOfTests();
1068 cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
1069 // how many tests are in based on RegExp?
1070 int inREcnt = 0;
1071 cmCTestTestHandler::ListOfTests::iterator it;
1072 for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
1074 this->CheckLabelFilter(*it);
1075 if (it->IsInBasedOnREOptions)
1077 inREcnt ++;
1080 // expand the test list based on the union flag
1081 if (this->UseUnion)
1083 this->ExpandTestsToRunInformation((int)tmsize);
1085 else
1087 this->ExpandTestsToRunInformation(inREcnt);
1089 // Now create a final list of tests to run
1090 int cnt = 0;
1091 inREcnt = 0;
1092 std::string last_directory = "";
1093 ListOfTests finalList;
1094 for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
1096 cnt ++;
1097 if (it->IsInBasedOnREOptions)
1099 inREcnt++;
1102 if (this->UseUnion)
1104 // if it is not in the list and not in the regexp then skip
1105 if ((this->TestsToRun.size() &&
1106 std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
1107 == this->TestsToRun.end()) && !it->IsInBasedOnREOptions)
1109 continue;
1112 else
1114 // is this test in the list of tests to run? If not then skip it
1115 if ((this->TestsToRun.size() &&
1116 std::find(this->TestsToRun.begin(),
1117 this->TestsToRun.end(), inREcnt)
1118 == this->TestsToRun.end()) || !it->IsInBasedOnREOptions)
1120 continue;
1123 it->Index = cnt; // save the index into the test list for this test
1124 finalList.push_back(*it);
1126 // Save the total number of tests before exclusions
1127 this->TotalNumberOfTests = this->TestList.size();
1128 // Set the TestList to the final list of all test
1129 this->TestList = finalList;
1132 bool cmCTestTestHandler::GetValue(const char* tag,
1133 int& value,
1134 std::ifstream& fin)
1136 std::string line;
1137 bool ret = true;
1138 cmSystemTools::GetLineFromStream(fin, line);
1139 if(line == tag)
1141 fin >> value;
1142 ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
1144 else
1146 cmCTestLog(this->CTest, ERROR_MESSAGE,
1147 "parse error: missing tag: "
1148 << tag << " found [" << line << "]" << std::endl);
1149 ret = false;
1151 return ret;
1154 bool cmCTestTestHandler::GetValue(const char* tag,
1155 double& value,
1156 std::ifstream& fin)
1158 std::string line;
1159 cmSystemTools::GetLineFromStream(fin, line);
1160 bool ret = true;
1161 if(line == tag)
1163 fin >> value;
1164 ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
1166 else
1168 cmCTestLog(this->CTest, ERROR_MESSAGE,
1169 "parse error: missing tag: "
1170 << tag << " found [" << line << "]" << std::endl);
1171 ret = false;
1173 return ret;
1176 bool cmCTestTestHandler::GetValue(const char* tag,
1177 bool& value,
1178 std::ifstream& fin)
1180 std::string line;
1181 cmSystemTools::GetLineFromStream(fin, line);
1182 bool ret = true;
1183 if(line == tag)
1185 #ifdef __HAIKU__
1186 int tmp = 0;
1187 fin >> tmp;
1188 value = false;
1189 if(tmp)
1191 value = true;
1193 #else
1194 fin >> value;
1195 #endif
1196 ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
1198 else
1200 cmCTestLog(this->CTest, ERROR_MESSAGE,
1201 "parse error: missing tag: "
1202 << tag << " found [" << line << "]" << std::endl);
1203 ret = false;
1205 return ret;
1208 bool cmCTestTestHandler::GetValue(const char* tag,
1209 size_t& value,
1210 std::ifstream& fin)
1212 std::string line;
1213 cmSystemTools::GetLineFromStream(fin, line);
1214 bool ret = true;
1215 if(line == tag)
1217 fin >> value;
1218 ret = cmSystemTools::GetLineFromStream(fin, line); // read blank line
1220 else
1222 cmCTestLog(this->CTest, ERROR_MESSAGE,
1223 "parse error: missing tag: "
1224 << tag << " found [" << line.c_str() << "]" << std::endl);
1225 ret = false;
1227 return ret;
1230 bool cmCTestTestHandler::GetValue(const char* tag,
1231 std::string& value,
1232 std::ifstream& fin)
1234 std::string line;
1235 cmSystemTools::GetLineFromStream(fin, line);
1236 bool ret = true;
1237 if(line == tag)
1239 ret = cmSystemTools::GetLineFromStream(fin, value);
1241 else
1243 cmCTestLog(this->CTest, ERROR_MESSAGE,
1244 "parse error: missing tag: "
1245 << tag << " found [" << line << "]" << std::endl);
1246 ret = false;
1248 return ret;
1252 // This should load only one test and is used in -j N mode.
1253 // it is used by the sub-process ctest runs which should have
1254 // only one -I N test to run.
1255 void cmCTestTestHandler::LoadTestList()
1257 this->TestList.clear();
1258 std::string fname = this->CTest->GetBinaryDir()
1259 + "/Testing/Temporary/PCache.txt";
1260 std::ifstream fin(fname.c_str());
1261 std::string line;
1262 if(!fin)
1264 cmCTestLog(this->CTest, ERROR_MESSAGE,
1265 "Could not load PCache.txt file: "
1266 << fname.c_str() << std::endl);
1267 return;
1269 bool ok = true;
1270 int numTestsToRun = 0;
1271 ok = ok && this->GetValue("TotalNumberOfTests:",
1272 this->TotalNumberOfTests, fin);
1273 ok = ok && this->GetValue("NumberOfTestsToRun:", numTestsToRun, fin);
1274 this->ExpandTestsToRunInformation(this->TotalNumberOfTests);
1275 if(this->TestsToRun.size() != 1)
1277 cmCTestLog(this->CTest, ERROR_MESSAGE,
1278 "Error when in parallel mode only one test should be run: "
1279 << this->TestsToRun.size() << std::endl);
1281 int testIndexToRun = this->TestsToRun[0];
1282 this->CTest->SetParallelSubprocessId(testIndexToRun);
1283 if(!ok)
1285 return;
1287 for(int i =0; i < numTestsToRun; i++)
1289 cmCTestTestProperties p;
1290 int numArgs = 0;
1291 ok = this->GetValue("Name:", p.Name, fin);
1292 ok = ok && this->GetValue("Directory:", p.Directory, fin);
1293 ok = ok && this->GetValue("Args:", numArgs, fin);
1294 for(int j =0; j < numArgs; ++j)
1296 cmSystemTools::GetLineFromStream(fin, line);
1297 p.Args.push_back(line);
1299 int numDep = 0;
1300 ok = ok && this->GetValue("Depends:", numDep, fin);
1301 for(int j =0; j < numDep; ++j)
1303 cmSystemTools::GetLineFromStream(fin, line);
1304 p.Depends.push_back(line);
1306 int numErrRegex = 0;
1307 ok = ok && this->GetValue("ErrorRegularExpressions:",
1308 numErrRegex, fin);
1309 for(int j =0; j < numErrRegex; j++)
1311 cmSystemTools::GetLineFromStream(fin, line);
1312 std::pair<cmsys::RegularExpression, std::string> rpair;
1313 rpair.first.compile(line.c_str());
1314 rpair.second = line;
1315 p.ErrorRegularExpressions.push_back(rpair);
1317 int numReqRegex = 0;
1318 ok = ok && this->GetValue("RequiredRegularExpressions:",
1319 numReqRegex, fin);
1320 for(int j =0; j < numReqRegex; j++)
1322 cmSystemTools::GetLineFromStream(fin, line);
1323 std::pair<cmsys::RegularExpression, std::string> rpair;
1324 rpair.first.compile(line.c_str());
1325 rpair.second = line;
1326 p.RequiredRegularExpressions.push_back(rpair);
1328 int numMeasure = 0;
1329 ok = ok && this->GetValue("Measurements:",
1330 numMeasure, fin);
1331 for(int j =0; j < numMeasure; j++)
1333 cmStdString m;
1334 cmStdString v;
1335 cmSystemTools::GetLineFromStream(fin, line);
1336 m = line;
1337 cmSystemTools::GetLineFromStream(fin, line);
1338 v = line;
1339 p.Measurements[m] = v;
1341 int isinre;
1342 ok = ok && this->GetValue("IsInBasedOnREOptions:", isinre, fin);
1343 ok = ok && this->GetValue("WillFail:", p.WillFail, fin);
1344 ok = ok && this->GetValue("TimeOut:", p.Timeout, fin);
1345 ok = ok && this->GetValue("Index:", p.Index, fin);
1346 int numEnv = 0;
1347 ok = ok && this->GetValue("Environment:",
1348 numEnv, fin);
1349 for(int j =0; j < numEnv; j++)
1351 cmSystemTools::GetLineFromStream(fin, line);
1352 p.Environment.push_back(line);
1354 int numLabels = 0;
1355 ok = ok && this->GetValue("Labels:",
1356 numLabels, fin);
1357 for(int j =0; j < numLabels; j++)
1359 cmSystemTools::GetLineFromStream(fin, line);
1360 p.Labels.push_back(line);
1362 if(!ok)
1364 cmCTestLog(this->CTest, ERROR_MESSAGE,
1365 "Internal Error reading cached test information."
1366 << std::endl);
1367 return;
1369 if(p.Index == testIndexToRun)
1371 // add the one test and stop reading
1372 this->TestList.push_back(p);
1373 return;
1377 std::string cmCTestTestHandler::SaveTestList()
1379 std::string fname = this->CTest->GetBinaryDir()
1380 + "/Testing/Temporary/PCache.txt";
1381 cmGeneratedFileStream fout(fname.c_str());
1382 if(!fout)
1384 cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
1385 << "Could not open PCache.txt for write:"
1386 << fname.c_str()
1387 << std::endl);
1389 fout << "TotalNumberOfTests:\n";
1390 fout << this->TotalNumberOfTests << "\n";
1391 fout << "NumberOfTestsToRun:\n";
1392 fout << this->TestList.size() << "\n";
1393 for (ListOfTests::iterator it = this->TestList.begin();
1394 it != this->TestList.end(); it ++ )
1396 cmCTestTestProperties& p = *it;
1397 fout << "Name:\n"
1398 << p.Name.c_str()
1399 << "\nDirectory:\n"
1400 << p.Directory.c_str()
1401 << "\nArgs:\n"
1402 << p.Args.size() << "\n";
1403 for(std::vector<std::string>::iterator i = p.Args.begin();
1404 i != p.Args.end(); ++i)
1406 fout << i->c_str() << "\n";
1408 fout << "Depends:\n" << p.Depends.size() << "\n";
1409 for(std::vector<std::string>::iterator i = p.Depends.begin();
1410 i != p.Depends.end(); ++i)
1412 fout << i->c_str() << "\n";
1414 std::vector<std::pair<cmsys::RegularExpression,
1415 std::string> >::iterator regxi;
1416 fout << "ErrorRegularExpressions:\n" <<
1417 p.ErrorRegularExpressions.size() << "\n";
1418 for(regxi = p.ErrorRegularExpressions.begin();
1419 regxi != p.ErrorRegularExpressions.end(); regxi++)
1421 fout << regxi->second << "\n";
1423 fout << "RequiredRegularExpressions:\n" <<
1424 p.RequiredRegularExpressions.size() << "\n";
1425 for(regxi = p.RequiredRegularExpressions.begin();
1426 regxi != p.RequiredRegularExpressions.end(); regxi++)
1428 fout << regxi->second << "\n";
1430 fout << "Measurements:\n" <<
1431 p.Measurements.size() << "\n";
1432 for(std::map<cmStdString, cmStdString>::const_iterator m =
1433 p.Measurements.begin(); m != p.Measurements.end(); ++m)
1435 fout << m->first << "\n";
1436 fout << m->second << "\n";
1439 fout << "IsInBasedOnREOptions:\n"
1440 << p.IsInBasedOnREOptions
1441 << "\nWillFail:\n"
1442 << p.WillFail
1443 << "\nTimeOut:\n"
1444 << p.Timeout
1445 << "\nIndex:\n"
1446 << p.Index << "\n";
1447 fout << "Environment:\n" <<
1448 p.Environment.size() << "\n";
1449 for(std::vector<std::string>::const_iterator e =
1450 p.Environment.begin(); e != p.Environment.end(); ++e)
1452 fout << *e << "\n";
1454 fout << "Labels:\n" <<
1455 p.Labels.size() << "\n";
1456 for(std::vector<std::string>::const_iterator e =
1457 p.Labels.begin(); e != p.Labels.end(); ++e)
1459 fout << *e << "\n";
1462 fout.close();
1463 return fname;
1466 void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
1467 std::vector<cmStdString> &failed)
1469 this->ComputeTestList();
1470 cmCTestMultiProcessHandler parallel;
1471 parallel.SetCTest(this->CTest);
1472 parallel.SetParallelLevel(this->CTest->GetParallelLevel());
1473 cmCTestMultiProcessHandler::TestSet depends;
1474 cmCTestMultiProcessHandler::TestMap tests;
1475 std::map<int, cmStdString> testnames;
1476 for (ListOfTests::iterator it = this->TestList.begin();
1477 it != this->TestList.end(); it ++ )
1479 cmCTestTestProperties& p = *it;
1480 testnames[p.Index] = p.Name;
1481 if(p.Depends.size())
1483 for(std::vector<std::string>::iterator i = p.Depends.begin();
1484 i != p.Depends.end(); ++i)
1486 for(ListOfTests::iterator it2 = this->TestList.begin();
1487 it2 != this->TestList.end(); it2 ++ )
1489 if(it2->Name == *i)
1491 depends.insert(it2->Index);
1492 break; // break out of test loop as name can only match 1
1497 tests[it->Index] = depends;
1499 parallel.SetCTestCommand(this->CTest->GetCTestExecutable());
1500 parallel.SetTests(tests, testnames);
1501 std::string fname = this->SaveTestList();
1502 parallel.SetTestCacheFile(fname.c_str());
1503 parallel.SetPassFailVectors(&passed, &failed);
1504 this->TestResults.clear();
1505 parallel.SetTestResults(&this->TestResults);
1506 parallel.RunTests();
1507 cmSystemTools::RemoveFile(fname.c_str());
1511 //----------------------------------------------------------------------
1512 void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
1513 std::vector<cmStdString> &failed)
1515 if(this->CTest->GetParallelLevel() > 0)
1517 this->ProcessParallel(passed, failed);
1518 return;
1520 // save the current working directory
1521 std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
1522 // compute the list of tests to run
1523 this->ComputeTestList();
1524 this->StartTest = this->CTest->CurrentTime();
1525 this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
1526 double elapsed_time_start = cmSystemTools::GetTime();
1527 *this->LogFile << "Start testing: " << this->StartTest << std::endl
1528 << "----------------------------------------------------------"
1529 << std::endl;
1530 std::string last_directory = "";
1531 // run each test
1532 for (ListOfTests::iterator it = this->TestList.begin();
1533 it != this->TestList.end(); it ++ )
1535 if (!(last_directory == it->Directory))
1537 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
1538 "Changing directory into " << it->Directory.c_str() << "\n");
1539 *this->LogFile << "Changing directory into: " << it->Directory.c_str()
1540 << std::endl;
1541 last_directory = it->Directory;
1542 cmSystemTools::ChangeDirectory(it->Directory.c_str());
1544 // process this one test
1545 this->ProcessOneTest(&(*it), passed, failed, it->Index,
1546 static_cast<int>(this->TotalNumberOfTests));
1549 this->EndTest = this->CTest->CurrentTime();
1550 this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
1551 this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
1552 if ( this->LogFile )
1554 *this->LogFile << "End testing: " << this->EndTest << std::endl;
1556 cmSystemTools::ChangeDirectory(current_dir.c_str());
1559 //----------------------------------------------------------------------
1560 void cmCTestTestHandler::GenerateTestCommand(std::vector<const char*>&)
1564 //----------------------------------------------------------------------
1565 void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
1567 if ( !this->CTest->GetProduceXML() )
1569 return;
1572 this->CTest->StartXML(os, this->AppendXML);
1573 os << "<Testing>\n"
1574 << "\t<StartDateTime>" << this->StartTest << "</StartDateTime>\n"
1575 << "\t<StartTestTime>" << this->StartTestTime << "</StartTestTime>\n"
1576 << "\t<TestList>\n";
1577 cmCTestTestHandler::TestResultsVector::size_type cc;
1578 for ( cc = 0; cc < this->TestResults.size(); cc ++ )
1580 cmCTestTestResult *result = &this->TestResults[cc];
1581 std::string testPath = result->Path + "/" + result->Name;
1582 os << "\t\t<Test>" << cmXMLSafe(
1583 this->CTest->GetShortPathToFile(testPath.c_str()))
1584 << "</Test>" << std::endl;
1586 os << "\t</TestList>\n";
1587 for ( cc = 0; cc < this->TestResults.size(); cc ++ )
1589 cmCTestTestResult *result = &this->TestResults[cc];
1590 this->WriteTestResultHeader(os, result);
1591 os << "\t\t<Results>" << std::endl;
1592 if ( result->Status != cmCTestTestHandler::NOT_RUN )
1594 if ( result->Status != cmCTestTestHandler::COMPLETED ||
1595 result->ReturnValue )
1597 os << "\t\t\t<NamedMeasurement type=\"text/string\" "
1598 "name=\"Exit Code\"><Value>"
1599 << cmXMLSafe(this->GetTestStatus(result->Status))
1600 << "</Value>"
1601 "</NamedMeasurement>\n"
1602 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1603 "name=\"Exit Value\"><Value>"
1604 << result->ReturnValue
1605 << "</Value></NamedMeasurement>"
1606 << std::endl;
1608 os << result->RegressionImages;
1609 os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
1610 << "name=\"Execution Time\"><Value>"
1611 << result->ExecutionTime
1612 << "</Value></NamedMeasurement>\n";
1613 if(result->Reason.size())
1615 const char* reasonType = "Pass Reason";
1616 if(result->Status != cmCTestTestHandler::COMPLETED &&
1617 result->Status != cmCTestTestHandler::NOT_RUN)
1619 reasonType = "Fail Reason";
1621 os << "\t\t\t<NamedMeasurement type=\"text/string\" "
1622 << "name=\"" << reasonType << "\"><Value>"
1623 << cmXMLSafe(result->Reason)
1624 << "</Value></NamedMeasurement>\n";
1627 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1628 << "name=\"Completion Status\"><Value>"
1629 << cmXMLSafe(result->CompletionStatus)
1630 << "</Value></NamedMeasurement>\n";
1633 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1634 << "name=\"Command Line\"><Value>"
1635 << cmXMLSafe(result->FullCommandLine)
1636 << "</Value></NamedMeasurement>\n";
1637 std::map<cmStdString,cmStdString>::iterator measureIt;
1638 for ( measureIt = result->Properties->Measurements.begin();
1639 measureIt != result->Properties->Measurements.end();
1640 ++ measureIt )
1643 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1644 << "name=\"" << measureIt->first.c_str() << "\"><Value>"
1645 << cmXMLSafe(measureIt->second)
1646 << "</Value></NamedMeasurement>\n";
1649 << "\t\t\t<Measurement>\n"
1650 << "\t\t\t\t<Value>";
1651 os << cmXMLSafe(result->Output);
1653 << "</Value>\n"
1654 << "\t\t\t</Measurement>\n"
1655 << "\t\t</Results>\n";
1656 this->WriteTestResultFooter(os, result);
1659 os << "\t<EndDateTime>" << this->EndTest << "</EndDateTime>\n"
1660 << "\t<EndTestTime>" << this->EndTestTime << "</EndTestTime>\n"
1661 << "<ElapsedMinutes>"
1662 << static_cast<int>(this->ElapsedTestingTime/6)/10.0
1663 << "</ElapsedMinutes>"
1664 << "</Testing>" << std::endl;
1665 this->CTest->EndXML(os);
1668 //----------------------------------------------------------------------------
1669 void cmCTestTestHandler::WriteTestResultHeader(std::ostream& os,
1670 cmCTestTestResult* result)
1672 os << "\t<Test Status=\"";
1673 if ( result->Status == cmCTestTestHandler::COMPLETED )
1675 os << "passed";
1677 else if ( result->Status == cmCTestTestHandler::NOT_RUN )
1679 os << "notrun";
1681 else
1683 os << "failed";
1685 std::string testPath = result->Path + "/" + result->Name;
1686 os << "\">\n"
1687 << "\t\t<Name>" << cmXMLSafe(result->Name) << "</Name>\n"
1688 << "\t\t<Path>" << cmXMLSafe(
1689 this->CTest->GetShortPathToFile(result->Path.c_str())) << "</Path>\n"
1690 << "\t\t<FullName>" << cmXMLSafe(
1691 this->CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
1692 << "\t\t<FullCommandLine>"
1693 << cmXMLSafe(result->FullCommandLine)
1694 << "</FullCommandLine>\n";
1697 //----------------------------------------------------------------------------
1698 void cmCTestTestHandler::WriteTestResultFooter(std::ostream& os,
1699 cmCTestTestResult* result)
1701 if(!result->Properties->Labels.empty())
1703 os << "\t\t<Labels>\n";
1704 std::vector<std::string> const& labels = result->Properties->Labels;
1705 for(std::vector<std::string>::const_iterator li = labels.begin();
1706 li != labels.end(); ++li)
1708 os << "\t\t\t<Label>" << cmXMLSafe(*li) << "</Label>\n";
1710 os << "\t\t</Labels>\n";
1714 << "\t</Test>" << std::endl;
1717 //----------------------------------------------------------------------
1718 int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
1720 std::vector<cmStdString>::iterator it;
1721 for ( it = vec.begin(); it != vec.end(); ++it )
1723 int retVal = 0;
1724 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command: " << *it
1725 << std::endl);
1726 if ( !cmSystemTools::RunSingleCommand(it->c_str(), 0, &retVal, 0, true
1727 /*this->Verbose*/) || retVal != 0 )
1729 cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem running command: "
1730 << *it << std::endl);
1731 return 0;
1734 return 1;
1738 //----------------------------------------------------------------------
1739 // Find the appropriate executable to run for a test
1740 std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
1742 std::string resConfig;
1743 std::vector<std::string> extraPaths;
1744 std::vector<std::string> failedPaths;
1745 return cmCTestTestHandler::FindExecutable(this->CTest,
1746 exe, resConfig,
1747 extraPaths,
1748 failedPaths);
1751 // add additional configurations to the search path
1752 void cmCTestTestHandler
1753 ::AddConfigurations(cmCTest *ctest,
1754 std::vector<std::string> &attempted,
1755 std::vector<std::string> &attemptedConfigs,
1756 std::string filepath,
1757 std::string &filename)
1759 std::string tempPath;
1761 if (filepath.size() &&
1762 filepath[filepath.size()-1] != '/')
1764 filepath += "/";
1766 tempPath = filepath + filename;
1767 attempted.push_back(tempPath);
1768 attemptedConfigs.push_back("");
1770 if(ctest->GetConfigType().size())
1772 tempPath = filepath;
1773 tempPath += ctest->GetConfigType();
1774 tempPath += "/";
1775 tempPath += filename;
1776 attempted.push_back(tempPath);
1777 attemptedConfigs.push_back(ctest->GetConfigType());
1778 // If the file is an OSX bundle then the configtyp
1779 // will be at the start of the path
1780 tempPath = ctest->GetConfigType();
1781 tempPath += "/";
1782 tempPath += filepath;
1783 tempPath += filename;
1784 attempted.push_back(tempPath);
1785 attemptedConfigs.push_back(ctest->GetConfigType());
1787 else
1789 // no config specified to try some options
1790 tempPath = filepath;
1791 tempPath += "Release/";
1792 tempPath += filename;
1793 attempted.push_back(tempPath);
1794 attemptedConfigs.push_back("Release");
1795 tempPath = filepath;
1796 tempPath += "Debug/";
1797 tempPath += filename;
1798 attempted.push_back(tempPath);
1799 attemptedConfigs.push_back("Debug");
1800 tempPath = filepath;
1801 tempPath += "MinSizeRel/";
1802 tempPath += filename;
1803 attempted.push_back(tempPath);
1804 attemptedConfigs.push_back("MinSizeRel");
1805 tempPath = filepath;
1806 tempPath += "RelWithDebInfo/";
1807 tempPath += filename;
1808 attempted.push_back(tempPath);
1809 attemptedConfigs.push_back("RelWithDebInfo");
1810 tempPath = filepath;
1811 tempPath += "Deployment/";
1812 tempPath += filename;
1813 attempted.push_back(tempPath);
1814 attemptedConfigs.push_back("Deployment");
1815 tempPath = filepath;
1816 tempPath += "Development/";
1817 tempPath += filename;
1818 attempted.push_back(tempPath);
1819 attemptedConfigs.push_back("Deployment");
1824 //----------------------------------------------------------------------
1825 // Find the appropriate executable to run for a test
1826 std::string cmCTestTestHandler
1827 ::FindExecutable(cmCTest *ctest,
1828 const char *testCommand,
1829 std::string &resultingConfig,
1830 std::vector<std::string> &extraPaths,
1831 std::vector<std::string> &failed)
1833 // now run the compiled test if we can find it
1834 std::vector<std::string> attempted;
1835 std::vector<std::string> attemptedConfigs;
1836 std::string tempPath;
1837 std::string filepath =
1838 cmSystemTools::GetFilenamePath(testCommand);
1839 std::string filename =
1840 cmSystemTools::GetFilenameName(testCommand);
1842 cmCTestTestHandler::AddConfigurations(ctest, attempted,
1843 attemptedConfigs,
1844 filepath,filename);
1846 // even if a fullpath was specified also try it relative to the current
1847 // directory
1848 if (filepath.size() && filepath[0] == '/')
1850 std::string localfilepath = filepath.substr(1,filepath.size()-1);
1851 cmCTestTestHandler::AddConfigurations(ctest, attempted,
1852 attemptedConfigs,
1853 localfilepath,filename);
1857 // if extraPaths are provided and we were not passed a full path, try them,
1858 // try any extra paths
1859 if (filepath.size() == 0)
1861 for (unsigned int i = 0; i < extraPaths.size(); ++i)
1863 std::string filepathExtra =
1864 cmSystemTools::GetFilenamePath(extraPaths[i]);
1865 std::string filenameExtra =
1866 cmSystemTools::GetFilenameName(extraPaths[i]);
1867 cmCTestTestHandler::AddConfigurations(ctest,attempted,
1868 attemptedConfigs,
1869 filepathExtra,
1870 filenameExtra);
1874 // store the final location in fullPath
1875 std::string fullPath;
1877 // now look in the paths we specified above
1878 for(unsigned int ai=0;
1879 ai < attempted.size() && fullPath.size() == 0; ++ai)
1881 // first check without exe extension
1882 if(cmSystemTools::FileExists(attempted[ai].c_str())
1883 && !cmSystemTools::FileIsDirectory(attempted[ai].c_str()))
1885 fullPath = cmSystemTools::CollapseFullPath(attempted[ai].c_str());
1886 resultingConfig = attemptedConfigs[ai];
1888 // then try with the exe extension
1889 else
1891 failed.push_back(attempted[ai].c_str());
1892 tempPath = attempted[ai];
1893 tempPath += cmSystemTools::GetExecutableExtension();
1894 if(cmSystemTools::FileExists(tempPath.c_str())
1895 && !cmSystemTools::FileIsDirectory(tempPath.c_str()))
1897 fullPath = cmSystemTools::CollapseFullPath(tempPath.c_str());
1898 resultingConfig = attemptedConfigs[ai];
1900 else
1902 failed.push_back(tempPath.c_str());
1907 // if everything else failed, check the users path, but only if a full path
1908 // wasn't specified
1909 if (fullPath.size() == 0 && filepath.size() == 0)
1911 std::string path = cmSystemTools::FindProgram(filename.c_str());
1912 if (path != "")
1914 resultingConfig = "";
1915 return path;
1918 if(fullPath.size() == 0)
1920 cmCTestLog(ctest, HANDLER_OUTPUT,
1921 "Could not find executable " << testCommand << "\n"
1922 << "Looked in the following places:\n");
1923 for(std::vector<std::string>::iterator i = failed.begin();
1924 i != failed.end(); ++i)
1926 cmCTestLog(ctest, HANDLER_OUTPUT,
1927 i->c_str() << "\n");
1931 return fullPath;
1935 //----------------------------------------------------------------------
1936 void cmCTestTestHandler::GetListOfTests()
1938 if ( !this->IncludeLabelRegExp.empty() )
1940 this->IncludeLabelRegularExpression.
1941 compile(this->IncludeLabelRegExp.c_str());
1943 if ( !this->IncludeLabelRegExp.empty() )
1945 this->ExcludeLabelRegularExpression.
1946 compile(this->ExcludeLabelRegExp.c_str());
1948 if ( !this->IncludeRegExp.empty() )
1950 this->IncludeTestsRegularExpression.compile(this->IncludeRegExp.c_str());
1952 if ( !this->ExcludeRegExp.empty() )
1954 this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp.c_str());
1956 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
1957 "Constructing a list of tests" << std::endl);
1958 cmake cm;
1959 cmGlobalGenerator gg;
1960 gg.SetCMakeInstance(&cm);
1961 std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
1962 lg->SetGlobalGenerator(&gg);
1963 cmMakefile *mf = lg->GetMakefile();
1964 mf->AddDefinition("CTEST_CONFIGURATION_TYPE",
1965 this->CTest->GetConfigType().c_str());
1967 // Add handler for ADD_TEST
1968 cmCTestAddTestCommand* newCom1 = new cmCTestAddTestCommand;
1969 newCom1->TestHandler = this;
1970 cm.AddCommand(newCom1);
1972 // Add handler for SUBDIRS
1973 cmCTestSubdirCommand* newCom2 =
1974 new cmCTestSubdirCommand;
1975 newCom2->TestHandler = this;
1976 cm.AddCommand(newCom2);
1978 // Add handler for ADD_SUBDIRECTORY
1979 cmCTestAddSubdirectoryCommand* newCom3 =
1980 new cmCTestAddSubdirectoryCommand;
1981 newCom3->TestHandler = this;
1982 cm.AddCommand(newCom3);
1984 // Add handler for SET_SOURCE_FILES_PROPERTIES
1985 cmCTestSetTestsPropertiesCommand* newCom4
1986 = new cmCTestSetTestsPropertiesCommand;
1987 newCom4->TestHandler = this;
1988 cm.AddCommand(newCom4);
1990 const char* testFilename;
1991 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
1993 // does the CTestTestfile.cmake exist ?
1994 testFilename = "CTestTestfile.cmake";
1996 else if( cmSystemTools::FileExists("DartTestfile.txt") )
1998 // does the DartTestfile.txt exist ?
1999 testFilename = "DartTestfile.txt";
2001 else
2003 return;
2006 if ( !mf->ReadListFile(0, testFilename) )
2008 return;
2010 if ( cmSystemTools::GetErrorOccuredFlag() )
2012 return;
2014 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
2015 "Done constructing a list of tests" << std::endl);
2018 //----------------------------------------------------------------------
2019 void cmCTestTestHandler::UseIncludeRegExp()
2021 this->UseIncludeRegExpFlag = true;
2024 //----------------------------------------------------------------------
2025 void cmCTestTestHandler::UseExcludeRegExp()
2027 this->UseExcludeRegExpFlag = true;
2028 this->UseExcludeRegExpFirst = this->UseIncludeRegExpFlag ? false : true;
2031 //----------------------------------------------------------------------
2032 const char* cmCTestTestHandler::GetTestStatus(int status)
2034 static const char statuses[][100] = {
2035 "Not Run",
2036 "Timeout",
2037 "SEGFAULT",
2038 "ILLEGAL",
2039 "INTERRUPT",
2040 "NUMERICAL",
2041 "OTHER_FAULT",
2042 "Failed",
2043 "BAD_COMMAND",
2044 "Completed"
2047 if ( status < cmCTestTestHandler::NOT_RUN ||
2048 status > cmCTestTestHandler::COMPLETED )
2050 return "No Status";
2052 return statuses[status];
2055 //----------------------------------------------------------------------
2056 void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
2058 if (this->TestsToRunString.empty())
2060 return;
2063 int start;
2064 int end = -1;
2065 double stride = -1;
2066 std::string::size_type pos = 0;
2067 std::string::size_type pos2;
2068 // read start
2069 if(GetNextNumber(this->TestsToRunString, start, pos, pos2))
2071 // read end
2072 if(GetNextNumber(this->TestsToRunString, end, pos, pos2))
2074 // read stride
2075 if(GetNextRealNumber(this->TestsToRunString, stride, pos, pos2))
2077 int val =0;
2078 // now read specific numbers
2079 while(GetNextNumber(this->TestsToRunString, val, pos, pos2))
2081 this->TestsToRun.push_back(val);
2083 this->TestsToRun.push_back(val);
2088 // if start is not specified then we assume we start at 1
2089 if(start == -1)
2091 start = 1;
2094 // if end isnot specified then we assume we end with the last test
2095 if(end == -1)
2097 end = static_cast<int>(numTests);
2100 // if the stride wasn't specified then it defaults to 1
2101 if(stride == -1)
2103 stride = 1;
2106 // if we have a range then add it
2107 if(end != -1 && start != -1 && stride > 0)
2109 int i = 0;
2110 while (i*stride + start <= end)
2112 this->TestsToRun.push_back(static_cast<int>(i*stride+start));
2113 ++i;
2117 // sort the array
2118 std::sort(this->TestsToRun.begin(), this->TestsToRun.end(),
2119 std::less<int>());
2120 // remove duplicates
2121 std::vector<int>::iterator new_end =
2122 std::unique(this->TestsToRun.begin(), this->TestsToRun.end());
2123 this->TestsToRun.erase(new_end, this->TestsToRun.end());
2126 //----------------------------------------------------------------------
2127 // Just for convenience
2128 #define SPACE_REGEX "[ \t\r\n]"
2129 //----------------------------------------------------------------------
2130 std::string cmCTestTestHandler::GenerateRegressionImages(
2131 const std::string& xml)
2133 cmsys::RegularExpression twoattributes(
2134 "<DartMeasurement"
2135 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2136 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2137 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
2138 cmsys::RegularExpression threeattributes(
2139 "<DartMeasurement"
2140 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2141 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2142 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2143 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
2144 cmsys::RegularExpression fourattributes(
2145 "<DartMeasurement"
2146 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2147 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2148 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2149 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2150 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
2151 cmsys::RegularExpression cdatastart(
2152 "<DartMeasurement"
2153 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2154 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2155 SPACE_REGEX "*>"
2156 SPACE_REGEX "*<!\\[CDATA\\[");
2157 cmsys::RegularExpression cdataend(
2158 "]]>"
2159 SPACE_REGEX "*</DartMeasurement>");
2160 cmsys::RegularExpression measurementfile(
2161 "<DartMeasurementFile"
2162 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2163 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
2164 SPACE_REGEX "*>([^<]*)</DartMeasurementFile>");
2166 cmOStringStream ostr;
2167 bool done = false;
2168 std::string cxml = xml;
2169 while ( ! done )
2171 if ( twoattributes.find(cxml) )
2173 ostr
2174 << "\t\t\t<NamedMeasurement"
2175 << " " << twoattributes.match(1) << "=\""
2176 << twoattributes.match(2) << "\""
2177 << " " << twoattributes.match(3) << "=\""
2178 << twoattributes.match(4) << "\""
2179 << "><Value>" << twoattributes.match(5)
2180 << "</Value></NamedMeasurement>"
2181 << std::endl;
2182 cxml.erase(twoattributes.start(),
2183 twoattributes.end() - twoattributes.start());
2185 else if ( threeattributes.find(cxml) )
2187 ostr
2188 << "\t\t\t<NamedMeasurement"
2189 << " " << threeattributes.match(1) << "=\""
2190 << threeattributes.match(2) << "\""
2191 << " " << threeattributes.match(3) << "=\""
2192 << threeattributes.match(4) << "\""
2193 << " " << threeattributes.match(5) << "=\""
2194 << threeattributes.match(6) << "\""
2195 << "><Value>" << threeattributes.match(7)
2196 << "</Value></NamedMeasurement>"
2197 << std::endl;
2198 cxml.erase(threeattributes.start(),
2199 threeattributes.end() - threeattributes.start());
2201 else if ( fourattributes.find(cxml) )
2203 ostr
2204 << "\t\t\t<NamedMeasurement"
2205 << " " << fourattributes.match(1) << "=\""
2206 << fourattributes.match(2) << "\""
2207 << " " << fourattributes.match(3) << "=\""
2208 << fourattributes.match(4) << "\""
2209 << " " << fourattributes.match(5) << "=\""
2210 << fourattributes.match(6) << "\""
2211 << " " << fourattributes.match(7) << "=\""
2212 << fourattributes.match(8) << "\""
2213 << "><Value>" << fourattributes.match(9)
2214 << "</Value></NamedMeasurement>"
2215 << std::endl;
2216 cxml.erase(fourattributes.start(),
2217 fourattributes.end() - fourattributes.start());
2219 else if ( cdatastart.find(cxml) && cdataend.find(cxml) )
2221 ostr
2222 << "\t\t\t<NamedMeasurement"
2223 << " " << cdatastart.match(1) << "=\""
2224 << cdatastart.match(2) << "\""
2225 << " " << cdatastart.match(3) << "=\""
2226 << cdatastart.match(4) << "\""
2227 << "><Value><![CDATA["
2228 << cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end())
2229 << "]]></Value></NamedMeasurement>"
2230 << std::endl;
2231 cxml.erase(cdatastart.start(),
2232 cdataend.end() - cdatastart.start());
2234 else if ( measurementfile.find(cxml) )
2236 const std::string& filename =
2237 cmCTest::CleanString(measurementfile.match(5));
2238 if ( cmSystemTools::FileExists(filename.c_str()) )
2240 long len = cmSystemTools::FileLength(filename.c_str());
2241 if ( len == 0 )
2243 std::string k1 = measurementfile.match(1);
2244 std::string v1 = measurementfile.match(2);
2245 std::string k2 = measurementfile.match(3);
2246 std::string v2 = measurementfile.match(4);
2247 if ( cmSystemTools::LowerCase(k1) == "type" )
2249 v1 = "text/string";
2251 if ( cmSystemTools::LowerCase(k2) == "type" )
2253 v2 = "text/string";
2256 ostr
2257 << "\t\t\t<NamedMeasurement"
2258 << " " << k1 << "=\"" << v1 << "\""
2259 << " " << k2 << "=\"" << v2 << "\""
2260 << " encoding=\"none\""
2261 << "><Value>Image " << filename.c_str()
2262 << " is empty</Value></NamedMeasurement>";
2264 else
2266 std::ifstream ifs(filename.c_str(), std::ios::in
2267 #ifdef _WIN32
2268 | std::ios::binary
2269 #endif
2271 unsigned char *file_buffer = new unsigned char [ len + 1 ];
2272 ifs.read(reinterpret_cast<char*>(file_buffer), len);
2273 unsigned char *encoded_buffer
2274 = new unsigned char [ static_cast<int>(len * 1.5 + 5) ];
2276 unsigned long rlen
2277 = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
2278 unsigned long cc;
2280 ostr
2281 << "\t\t\t<NamedMeasurement"
2282 << " " << measurementfile.match(1) << "=\""
2283 << measurementfile.match(2) << "\""
2284 << " " << measurementfile.match(3) << "=\""
2285 << measurementfile.match(4) << "\""
2286 << " encoding=\"base64\""
2287 << ">" << std::endl << "\t\t\t\t<Value>";
2288 for ( cc = 0; cc < rlen; cc ++ )
2290 ostr << encoded_buffer[cc];
2291 if ( cc % 60 == 0 && cc )
2293 ostr << std::endl;
2296 ostr
2297 << "</Value>" << std::endl << "\t\t\t</NamedMeasurement>"
2298 << std::endl;
2299 delete [] file_buffer;
2300 delete [] encoded_buffer;
2303 else
2305 int idx = 4;
2306 if ( measurementfile.match(1) == "name" )
2308 idx = 2;
2310 ostr
2311 << "\t\t\t<NamedMeasurement"
2312 << " name=\"" << measurementfile.match(idx) << "\""
2313 << " text=\"text/string\""
2314 << "><Value>File " << filename.c_str()
2315 << " not found</Value></NamedMeasurement>"
2316 << std::endl;
2317 cmCTestLog(this->CTest, HANDLER_OUTPUT, "File \"" << filename.c_str()
2318 << "\" not found." << std::endl);
2320 cxml.erase(measurementfile.start(),
2321 measurementfile.end() - measurementfile.start());
2323 else
2325 done = true;
2328 return ostr.str();
2331 //----------------------------------------------------------------------
2332 void cmCTestTestHandler::SetIncludeRegExp(const char *arg)
2334 this->IncludeRegExp = arg;
2337 //----------------------------------------------------------------------
2338 void cmCTestTestHandler::SetExcludeRegExp(const char *arg)
2340 this->ExcludeRegExp = arg;
2343 //----------------------------------------------------------------------
2344 void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
2346 if ( !in )
2348 return;
2350 this->TestsToRunString = in;
2351 // if the argument is a file, then read it and use the contents as the
2352 // string
2353 if(cmSystemTools::FileExists(in))
2355 std::ifstream fin(in);
2356 unsigned long filelen = cmSystemTools::FileLength(in);
2357 char* buff = new char[filelen+1];
2358 fin.getline(buff, filelen);
2359 buff[fin.gcount()] = 0;
2360 this->TestsToRunString = buff;
2364 //----------------------------------------------------------------------
2365 bool cmCTestTestHandler::CleanTestOutput(std::string& output,
2366 size_t remove_threshold)
2368 if ( remove_threshold == 0 )
2370 return true;
2372 if ( output.find("CTEST_FULL_OUTPUT") != output.npos )
2374 return true;
2376 cmOStringStream ostr;
2377 std::string::size_type cc;
2378 std::string::size_type skipsize = 0;
2379 int inTag = 0;
2380 int skipped = 0;
2381 for ( cc = 0; cc < output.size(); cc ++ )
2383 int ch = output[cc];
2384 if ( ch < 0 || ch > 255 )
2386 break;
2388 if ( ch == '<' )
2390 inTag = 1;
2392 if ( !inTag )
2394 int notskip = 0;
2395 // Skip
2396 if ( skipsize < remove_threshold )
2398 ostr << static_cast<char>(ch);
2399 notskip = 1;
2401 skipsize ++;
2402 if ( notskip && skipsize >= remove_threshold )
2404 skipped = 1;
2407 else
2409 ostr << static_cast<char>(ch);
2411 if ( ch == '>' )
2413 inTag = 0;
2416 if ( skipped )
2418 ostr << "..." << std::endl << "The rest of the test output was removed "
2419 "since it exceeds the threshold of "
2420 << remove_threshold << " characters." << std::endl;
2422 output = ostr.str();
2423 return true;
2426 //----------------------------------------------------------------------
2427 bool cmCTestTestHandler::SetTestsProperties(
2428 const std::vector<std::string>& args)
2430 std::vector<std::string>::const_iterator it;
2431 std::vector<cmStdString> tests;
2432 bool found = false;
2433 for ( it = args.begin(); it != args.end(); ++ it )
2435 if ( *it == "PROPERTIES" )
2437 found = true;
2438 break;
2440 tests.push_back(*it);
2442 if ( !found )
2444 return false;
2446 ++ it; // skip PROPERTIES
2447 for ( ; it != args.end(); ++ it )
2449 std::string key = *it;
2450 ++ it;
2451 if ( it == args.end() )
2453 break;
2455 std::string val = *it;
2456 std::vector<cmStdString>::const_iterator tit;
2457 for ( tit = tests.begin(); tit != tests.end(); ++ tit )
2459 cmCTestTestHandler::ListOfTests::iterator rtit;
2460 for ( rtit = this->TestList.begin();
2461 rtit != this->TestList.end();
2462 ++ rtit )
2464 if ( *tit == rtit->Name )
2466 if ( key == "WILL_FAIL" )
2468 rtit->WillFail = cmSystemTools::IsOn(val.c_str());
2470 if ( key == "TIMEOUT" )
2472 rtit->Timeout = atof(val.c_str());
2474 if ( key == "FAIL_REGULAR_EXPRESSION" )
2476 std::vector<std::string> lval;
2477 cmSystemTools::ExpandListArgument(val.c_str(), lval);
2478 std::vector<std::string>::iterator crit;
2479 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
2481 rtit->ErrorRegularExpressions.push_back(
2482 std::pair<cmsys::RegularExpression, std::string>(
2483 cmsys::RegularExpression(crit->c_str()),
2484 std::string(crit->c_str())));
2487 if ( key == "DEPENDS" )
2489 std::vector<std::string> lval;
2490 cmSystemTools::ExpandListArgument(val.c_str(), lval);
2491 std::vector<std::string>::iterator crit;
2492 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
2494 rtit->Depends.push_back(*crit);
2497 if ( key == "ENVIRONMENT" )
2499 std::vector<std::string> lval;
2500 cmSystemTools::ExpandListArgument(val.c_str(), lval);
2501 std::vector<std::string>::iterator crit;
2502 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
2504 rtit->Environment.push_back(*crit);
2507 if ( key == "LABELS" )
2509 std::vector<std::string> lval;
2510 cmSystemTools::ExpandListArgument(val.c_str(), lval);
2511 std::vector<std::string>::iterator crit;
2512 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
2514 rtit->Labels.push_back(*crit);
2518 if ( key == "MEASUREMENT" )
2520 size_t pos = val.find_first_of("=");
2521 if ( pos != val.npos )
2523 std::string mKey = val.substr(0, pos);
2524 const char* mVal = val.c_str() + pos + 1;
2525 rtit->Measurements[mKey] = mVal;
2527 else
2529 rtit->Measurements[val] = "1";
2532 if ( key == "PASS_REGULAR_EXPRESSION" )
2534 std::vector<std::string> lval;
2535 cmSystemTools::ExpandListArgument(val.c_str(), lval);
2536 std::vector<std::string>::iterator crit;
2537 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
2539 rtit->RequiredRegularExpressions.push_back(
2540 std::pair<cmsys::RegularExpression, std::string>(
2541 cmsys::RegularExpression(crit->c_str()),
2542 std::string(crit->c_str())));
2549 return true;
2552 //----------------------------------------------------------------------
2553 bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
2555 const std::string& testname = args[0];
2556 cmCTestLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl);
2557 if (this->UseExcludeRegExpFlag &&
2558 this->UseExcludeRegExpFirst &&
2559 this->ExcludeTestsRegularExpression.find(testname.c_str()))
2561 return true;
2563 if ( this->MemCheck )
2565 std::vector<cmStdString>::iterator it;
2566 bool found = false;
2567 for ( it = this->CustomTestsIgnore.begin();
2568 it != this->CustomTestsIgnore.end(); ++ it )
2570 if ( *it == testname )
2572 found = true;
2573 break;
2576 if ( found )
2578 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore memcheck: "
2579 << *it << std::endl);
2580 return true;
2583 else
2585 std::vector<cmStdString>::iterator it;
2586 bool found = false;
2587 for ( it = this->CustomTestsIgnore.begin();
2588 it != this->CustomTestsIgnore.end(); ++ it )
2590 if ( *it == testname )
2592 found = true;
2593 break;
2596 if ( found )
2598 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore test: "
2599 << *it << std::endl);
2600 return true;
2604 cmCTestTestProperties test;
2605 test.Name = testname;
2606 test.Args = args;
2607 test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
2608 cmCTestLog(this->CTest, DEBUG, "Set test directory: "
2609 << test.Directory << std::endl);
2611 test.IsInBasedOnREOptions = true;
2612 test.WillFail = false;
2613 test.Timeout = 0;
2614 if (this->UseIncludeRegExpFlag &&
2615 !this->IncludeTestsRegularExpression.find(testname.c_str()))
2617 test.IsInBasedOnREOptions = false;
2619 else if (this->UseExcludeRegExpFlag &&
2620 !this->UseExcludeRegExpFirst &&
2621 this->ExcludeTestsRegularExpression.find(testname.c_str()))
2623 test.IsInBasedOnREOptions = false;
2625 this->TestList.push_back(test);
2626 return true;