Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CTest / cmCTestTestHandler.cxx
blob5f0adc5e1c42c21cbcc78ab6bd681cc48a14b707
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestTestHandler.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/31 21:33:07 $
7 Version: $Revision: 1.68 $
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"
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"
32 #include <stdlib.h>
33 #include <math.h>
34 #include <float.h>
36 #include <memory> // auto_ptr
38 //----------------------------------------------------------------------
39 class cmCTestSubdirCommand : public cmCommand
41 public:
42 /**
43 * This is a virtual constructor for the command.
45 virtual cmCommand* Clone()
47 cmCTestSubdirCommand* c = new cmCTestSubdirCommand;
48 c->TestHandler = this->TestHandler;
49 return c;
52 /**
53 * This is called when the command is first encountered in
54 * the CMakeLists.txt file.
56 virtual bool InitialPass(std::vector<std::string> const& args,
57 cmExecutionStatus &);
59 /**
60 * The name of the command as specified in CMakeList.txt.
62 virtual const char* GetName() { return "subdirs";}
64 // Unused methods
65 virtual const char* GetTerseDocumentation() { return ""; }
66 virtual const char* GetFullDocumentation() { return ""; }
68 cmTypeMacro(cmCTestSubdirCommand, cmCommand);
70 cmCTestTestHandler* TestHandler;
73 //----------------------------------------------------------------------
74 bool cmCTestSubdirCommand
75 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
77 if(args.size() < 1 )
79 this->SetError("called with incorrect number of arguments");
80 return false;
82 std::vector<std::string>::const_iterator it;
83 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
84 for ( it = args.begin(); it != args.end(); ++ it )
86 cmSystemTools::ChangeDirectory(cwd.c_str());
87 std::string fname = cwd;
88 fname += "/";
89 fname += *it;
91 if ( !cmSystemTools::FileExists(fname.c_str()) )
93 // No subdirectory? So what...
94 continue;
96 cmSystemTools::ChangeDirectory(fname.c_str());
97 const char* testFilename;
98 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
100 // does the CTestTestfile.cmake exist ?
101 testFilename = "CTestTestfile.cmake";
103 else if( cmSystemTools::FileExists("DartTestfile.txt") )
105 // does the DartTestfile.txt exist ?
106 testFilename = "DartTestfile.txt";
108 else
110 // No CTestTestfile? Who cares...
111 cmSystemTools::ChangeDirectory(cwd.c_str());
112 continue;
114 fname += "/";
115 fname += testFilename;
116 bool readit =
117 this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
118 fname.c_str());
119 cmSystemTools::ChangeDirectory(cwd.c_str());
120 if(!readit)
122 std::string m = "Could not find include file: ";
123 m += fname;
124 this->SetError(m.c_str());
125 return false;
128 return true;
131 //----------------------------------------------------------------------
132 class cmCTestAddSubdirectoryCommand : public cmCommand
134 public:
136 * This is a virtual constructor for the command.
138 virtual cmCommand* Clone()
140 cmCTestAddSubdirectoryCommand* c = new cmCTestAddSubdirectoryCommand;
141 c->TestHandler = this->TestHandler;
142 return c;
146 * This is called when the command is first encountered in
147 * the CMakeLists.txt file.
149 virtual bool InitialPass(std::vector<std::string> const& args,
150 cmExecutionStatus &);
153 * The name of the command as specified in CMakeList.txt.
155 virtual const char* GetName() { return "add_subdirectory";}
157 // Unused methods
158 virtual const char* GetTerseDocumentation() { return ""; }
159 virtual const char* GetFullDocumentation() { return ""; }
161 cmTypeMacro(cmCTestAddSubdirectoryCommand, cmCommand);
163 cmCTestTestHandler* TestHandler;
166 //----------------------------------------------------------------------
167 bool cmCTestAddSubdirectoryCommand
168 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
170 if(args.size() < 1 )
172 this->SetError("called with incorrect number of arguments");
173 return false;
176 std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
177 cmSystemTools::ChangeDirectory(cwd.c_str());
178 std::string fname = cwd;
179 fname += "/";
180 fname += args[1];
182 if ( !cmSystemTools::FileExists(fname.c_str()) )
184 // No subdirectory? So what...
185 return true;
187 cmSystemTools::ChangeDirectory(fname.c_str());
188 const char* testFilename;
189 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
191 // does the CTestTestfile.cmake exist ?
192 testFilename = "CTestTestfile.cmake";
194 else if( cmSystemTools::FileExists("DartTestfile.txt") )
196 // does the DartTestfile.txt exist ?
197 testFilename = "DartTestfile.txt";
199 else
201 // No CTestTestfile? Who cares...
202 cmSystemTools::ChangeDirectory(cwd.c_str());
203 return true;
205 fname += "/";
206 fname += testFilename;
207 bool readit =
208 this->Makefile->ReadListFile(this->Makefile->GetCurrentListFile(),
209 fname.c_str());
210 cmSystemTools::ChangeDirectory(cwd.c_str());
211 if(!readit)
213 std::string m = "Could not find include file: ";
214 m += fname;
215 this->SetError(m.c_str());
216 return false;
218 return true;
221 //----------------------------------------------------------------------
222 class cmCTestAddTestCommand : public cmCommand
224 public:
226 * This is a virtual constructor for the command.
228 virtual cmCommand* Clone()
230 cmCTestAddTestCommand* c = new cmCTestAddTestCommand;
231 c->TestHandler = this->TestHandler;
232 return c;
236 * This is called when the command is first encountered in
237 * the CMakeLists.txt file.
239 virtual bool InitialPass(std::vector<std::string> const&,
240 cmExecutionStatus &);
243 * The name of the command as specified in CMakeList.txt.
245 virtual const char* GetName() { return "ADD_TEST";}
247 // Unused methods
248 virtual const char* GetTerseDocumentation() { return ""; }
249 virtual const char* GetFullDocumentation() { return ""; }
251 cmTypeMacro(cmCTestAddTestCommand, cmCommand);
253 cmCTestTestHandler* TestHandler;
256 //----------------------------------------------------------------------
257 bool cmCTestAddTestCommand
258 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
260 if ( args.size() < 2 )
262 this->SetError("called with incorrect number of arguments");
263 return false;
265 return this->TestHandler->AddTest(args);
268 //----------------------------------------------------------------------
269 class cmCTestSetTestsPropertiesCommand : public cmCommand
271 public:
273 * This is a virtual constructor for the command.
275 virtual cmCommand* Clone()
277 cmCTestSetTestsPropertiesCommand* c
278 = new cmCTestSetTestsPropertiesCommand;
279 c->TestHandler = this->TestHandler;
280 return c;
284 * This is called when the command is first encountered in
285 * the CMakeLists.txt file.
287 virtual bool InitialPass(std::vector<std::string> const&,
288 cmExecutionStatus &);
291 * The name of the command as specified in CMakeList.txt.
293 virtual const char* GetName() { return "SET_TESTS_PROPERTIES";}
295 // Unused methods
296 virtual const char* GetTerseDocumentation() { return ""; }
297 virtual const char* GetFullDocumentation() { return ""; }
299 cmTypeMacro(cmCTestSetTestsPropertiesCommand, cmCommand);
301 cmCTestTestHandler* TestHandler;
304 //----------------------------------------------------------------------
305 bool cmCTestSetTestsPropertiesCommand
306 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
308 return this->TestHandler->SetTestsProperties(args);
311 //----------------------------------------------------------------------
312 // get the next number in a string with numbers separated by ,
313 // pos is the start of the search and pos2 is the end of the search
314 // pos becomes pos2 after a call to GetNextNumber.
315 // -1 is returned at the end of the list.
316 inline int GetNextNumber(std::string const& in,
317 int& val,
318 std::string::size_type& pos,
319 std::string::size_type& pos2)
321 pos2 = in.find(',', pos);
322 if(pos2 != in.npos)
324 if(pos2-pos == 0)
326 val = -1;
328 else
330 val = atoi(in.substr(pos, pos2-pos).c_str());
332 pos = pos2+1;
333 return 1;
335 else
337 if(in.size()-pos == 0)
339 val = -1;
341 else
343 val = atoi(in.substr(pos, in.size()-pos).c_str());
345 return 0;
349 //----------------------------------------------------------------------
350 // get the next number in a string with numbers separated by ,
351 // pos is the start of the search and pos2 is the end of the search
352 // pos becomes pos2 after a call to GetNextNumber.
353 // -1 is returned at the end of the list.
354 inline int GetNextRealNumber(std::string const& in,
355 double& val,
356 std::string::size_type& pos,
357 std::string::size_type& pos2)
359 pos2 = in.find(',', pos);
360 if(pos2 != in.npos)
362 if(pos2-pos == 0)
364 val = -1;
366 else
368 val = atof(in.substr(pos, pos2-pos).c_str());
370 pos = pos2+1;
371 return 1;
373 else
375 if(in.size()-pos == 0)
377 val = -1;
379 else
381 val = atof(in.substr(pos, in.size()-pos).c_str());
383 return 0;
388 //----------------------------------------------------------------------
389 cmCTestTestHandler::cmCTestTestHandler()
391 this->UseUnion = false;
393 this->UseIncludeRegExpFlag = false;
394 this->UseExcludeRegExpFlag = false;
395 this->UseExcludeRegExpFirst = false;
397 this->CustomMaximumPassedTestOutputSize = 1 * 1024;
398 this->CustomMaximumFailedTestOutputSize = 300 * 1024;
400 this->MemCheck = false;
402 this->LogFile = 0;
404 this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
407 //----------------------------------------------------------------------
408 void cmCTestTestHandler::Initialize()
410 this->Superclass::Initialize();
412 this->ElapsedTestingTime = -1;
414 this->TestResults.clear();
416 this->CustomTestsIgnore.clear();
417 this->StartTest = "";
418 this->EndTest = "";
420 this->CustomPreTest.clear();
421 this->CustomPostTest.clear();
422 this->CustomMaximumPassedTestOutputSize = 1 * 1024;
423 this->CustomMaximumFailedTestOutputSize = 300 * 1024;
425 this->TestsToRun.clear();
427 this->UseIncludeRegExpFlag = false;
428 this->UseExcludeRegExpFlag = false;
429 this->UseExcludeRegExpFirst = false;
430 this->IncludeRegExp = "";
431 this->ExcludeRegExp = "";
433 TestsToRunString = "";
434 this->UseUnion = false;
435 this->TestList.clear();
438 //----------------------------------------------------------------------
439 void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
441 this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
442 this->CustomPreTest);
443 this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
444 this->CustomPostTest);
445 this->CTest->PopulateCustomVector(mf,
446 "CTEST_CUSTOM_TESTS_IGNORE",
447 this->CustomTestsIgnore);
448 this->CTest->PopulateCustomInteger(mf,
449 "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
450 this->CustomMaximumPassedTestOutputSize);
451 this->CTest->PopulateCustomInteger(mf,
452 "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
453 this->CustomMaximumFailedTestOutputSize);
456 //----------------------------------------------------------------------
457 int cmCTestTestHandler::PreProcessHandler()
459 if ( !this->ExecuteCommands(this->CustomPreTest) )
461 cmCTestLog(this->CTest, ERROR_MESSAGE,
462 "Problem executing pre-test command(s)." << std::endl);
463 return 0;
465 return 1;
468 //----------------------------------------------------------------------
469 int cmCTestTestHandler::PostProcessHandler()
471 if ( !this->ExecuteCommands(this->CustomPostTest) )
473 cmCTestLog(this->CTest, ERROR_MESSAGE,
474 "Problem executing post-test command(s)." << std::endl);
475 return 0;
477 return 1;
480 //----------------------------------------------------------------------
481 //clearly it would be nice if this were broken up into a few smaller
482 //functions and commented...
483 int cmCTestTestHandler::ProcessHandler()
485 // Update internal data structure from generic one
486 this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
487 this->SetUseUnion(cmSystemTools::IsOn(this->GetOption("UseUnion")));
488 const char* val;
489 val = this->GetOption("IncludeRegularExpression");
490 if ( val )
492 this->UseIncludeRegExp();
493 this->SetIncludeRegExp(val);
495 val = this->GetOption("ExcludeRegularExpression");
496 if ( val )
498 this->UseExcludeRegExp();
499 this->SetExcludeRegExp(val);
502 this->TestResults.clear();
504 cmCTestLog(this->CTest, HANDLER_OUTPUT,
505 (this->MemCheck ? "Memory check" : "Test")
506 << " project " << cmSystemTools::GetCurrentWorkingDirectory()
507 << std::endl);
508 if ( ! this->PreProcessHandler() )
510 return -1;
513 cmGeneratedFileStream mLogFile;
514 this->StartLogFile((this->MemCheck ? "DynamicAnalysis" : "Test"), mLogFile);
515 this->LogFile = &mLogFile;
517 std::vector<cmStdString> passed;
518 std::vector<cmStdString> failed;
519 int total;
521 this->ProcessDirectory(passed, failed);
523 total = int(passed.size()) + int(failed.size());
525 if (total == 0)
527 if ( !this->CTest->GetShowOnly() )
529 cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!"
530 << std::endl);
533 else
535 if (this->HandlerVerbose && passed.size() &&
536 (this->UseIncludeRegExpFlag || this->UseExcludeRegExpFlag))
538 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
539 << "The following tests passed:" << std::endl);
540 for(std::vector<cmStdString>::iterator j = passed.begin();
541 j != passed.end(); ++j)
543 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\t" << *j
544 << std::endl);
548 float percent = float(passed.size()) * 100.0f / total;
549 if ( failed.size() > 0 && percent > 99)
551 percent = 99;
553 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl
554 << static_cast<int>(percent + .5) << "% tests passed, "
555 << failed.size() << " tests failed out of " << total << std::endl);
556 //fprintf(stderr,"\n%.0f%% tests passed, %i tests failed out of %i\n",
557 // percent, int(failed.size()), total);
559 if (failed.size())
561 cmGeneratedFileStream ofs;
563 cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl
564 << "The following tests FAILED:" << std::endl);
565 this->StartLogFile("TestsFailed", ofs);
567 std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
568 for(ftit = this->TestResults.begin();
569 ftit != this->TestResults.end(); ++ftit)
571 if ( ftit->Status != cmCTestTestHandler::COMPLETED )
573 ofs << ftit->TestCount << ":" << ftit->Name << std::endl;
574 cmCTestLog(this->CTest, HANDLER_OUTPUT, "\t" << std::setw(3)
575 << ftit->TestCount << " - " << ftit->Name.c_str() << " ("
576 << this->GetTestStatus(ftit->Status) << ")" << std::endl);
583 if ( this->CTest->GetProduceXML() )
585 cmGeneratedFileStream xmlfile;
586 if( !this->StartResultingXML(
587 (this->MemCheck ? "DynamicAnalysis" : "Test"), xmlfile) )
589 cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create "
590 << (this->MemCheck ? "memory check" : "testing")
591 << " XML file" << std::endl);
592 this->LogFile = 0;
593 return 1;
595 this->GenerateDartOutput(xmlfile);
598 if ( ! this->PostProcessHandler() )
600 this->LogFile = 0;
601 return -1;
604 if ( !failed.empty() )
606 this->LogFile = 0;
607 return -1;
609 this->LogFile = 0;
610 return 0;
613 //----------------------------------------------------------------------
614 void cmCTestTestHandler::ProcessOneTest(cmCTestTestProperties *it,
615 std::vector<cmStdString> &passed,
616 std::vector<cmStdString> &failed,
617 int cnt, int tmsize)
619 const std::string& testname = it->Name;
620 std::vector<std::string>& args = it->Args;
621 cmCTestTestResult cres;
622 cres.Properties = &*it;
623 cres.ExecutionTime = 0;
624 cres.ReturnValue = -1;
625 cres.Status = cmCTestTestHandler::NOT_RUN;
626 cres.TestCount = cnt;
627 cres.Name = testname;
628 cres.Path = it->Directory.c_str();
630 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << cnt << "/");
631 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) << tmsize << " ");
632 if ( this->MemCheck )
634 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
636 else
638 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
640 cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
641 std::string outname = testname;
642 outname.resize(30, ' ');
643 *this->LogFile << cnt << "/" << tmsize << " Testing: " << testname
644 << std::endl;
646 if ( this->CTest->GetShowOnly() )
648 cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
650 else
652 cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
655 cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... ");
656 // find the test executable
657 std::string actualCommand = this->FindTheExecutable(args[1].c_str());
658 std::string testCommand
659 = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
661 // continue if we did not find the executable
662 if (testCommand == "")
664 *this->LogFile << "Unable to find executable: " << args[1].c_str()
665 << std::endl;
666 cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
667 << args[1].c_str() << std::endl);
668 cres.Output = "Unable to find executable: " + args[1];
669 if ( !this->CTest->GetShowOnly() )
671 cres.FullCommandLine = actualCommand;
672 this->TestResults.push_back( cres );
673 failed.push_back(testname);
674 return;
678 // add the arguments
679 std::vector<std::string>::const_iterator j = args.begin();
680 ++j;
681 ++j;
682 std::vector<const char*> arguments;
683 this->GenerateTestCommand(arguments);
684 arguments.push_back(actualCommand.c_str());
685 for(;j != args.end(); ++j)
687 testCommand += " ";
688 testCommand += cmSystemTools::EscapeSpaces(j->c_str());
689 arguments.push_back(j->c_str());
691 arguments.push_back(0);
694 * Run an executable command and put the stdout in output.
696 std::string output;
697 int retVal = 0;
700 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
701 << (this->MemCheck?"MemCheck":"Test")
702 << " command: " << testCommand
703 << std::endl);
704 *this->LogFile << cnt << "/" << tmsize
705 << " Test: " << testname.c_str() << std::endl;
706 *this->LogFile << "Command: ";
707 std::vector<cmStdString>::size_type ll;
708 for ( ll = 0; ll < arguments.size()-1; ll ++ )
710 *this->LogFile << "\"" << arguments[ll] << "\" ";
712 *this->LogFile
713 << std::endl
714 << "Directory: " << it->Directory << std::endl
715 << "\"" << testname.c_str() << "\" start time: "
716 << this->CTest->CurrentTime() << std::endl
717 << "Output:" << std::endl
718 << "----------------------------------------------------------"
719 << std::endl;
720 int res = 0;
721 double clock_start, clock_finish;
722 clock_start = cmSystemTools::GetTime();
724 if ( !this->CTest->GetShowOnly() )
726 res = this->CTest->RunTest(arguments, &output, &retVal, this->LogFile,
727 it->Timeout);
730 clock_finish = cmSystemTools::GetTime();
732 if ( this->LogFile )
734 double ttime = clock_finish - clock_start;
735 int hours = static_cast<int>(ttime / (60 * 60));
736 int minutes = static_cast<int>(ttime / 60) % 60;
737 int seconds = static_cast<int>(ttime) % 60;
738 char buffer[100];
739 sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
740 *this->LogFile
741 << "----------------------------------------------------------"
742 << std::endl
743 << "\"" << testname.c_str() << "\" end time: "
744 << this->CTest->CurrentTime() << std::endl
745 << "\"" << testname.c_str() << "\" time elapsed: "
746 << buffer << std::endl
747 << "----------------------------------------------------------"
748 << std::endl << std::endl;
751 cres.ExecutionTime = (double)(clock_finish - clock_start);
752 cres.FullCommandLine = testCommand;
753 std::string reason;
754 if ( !this->CTest->GetShowOnly() )
756 bool testFailed = false;
757 std::vector<std::pair<cmsys::RegularExpression,
758 std::string> >::iterator passIt;
759 bool forceFail = false;
760 if ( it->RequiredRegularExpressions.size() > 0 )
762 bool found = false;
763 for ( passIt = it->RequiredRegularExpressions.begin();
764 passIt != it->RequiredRegularExpressions.end();
765 ++ passIt )
767 if ( passIt->first.find(output.c_str()) )
769 found = true;
772 if ( !found )
774 reason = "Required regular expression not found.";
775 reason += "Regex=[";
776 for ( passIt = it->RequiredRegularExpressions.begin();
777 passIt != it->RequiredRegularExpressions.end();
778 ++ passIt )
780 reason += passIt->second;
781 reason += "\n";
783 reason += "]";
784 forceFail = true;
787 if ( it->ErrorRegularExpressions.size() > 0 )
789 for ( passIt = it->ErrorRegularExpressions.begin();
790 passIt != it->ErrorRegularExpressions.end();
791 ++ passIt )
793 if ( passIt->first.find(output.c_str()) )
795 reason = "Error regular expression found in output.";
796 reason += " Regex=[";
797 reason += passIt->second;
798 reason += "]";
799 forceFail = true;
804 if (res == cmsysProcess_State_Exited &&
805 (retVal == 0 || it->RequiredRegularExpressions.size()) &&
806 !forceFail)
808 cmCTestLog(this->CTest, HANDLER_OUTPUT, " Passed");
809 if ( it->WillFail )
811 cmCTestLog(this->CTest, HANDLER_OUTPUT, " - But it should fail!");
812 cres.Status = cmCTestTestHandler::FAILED;
813 testFailed = true;
815 else
817 cres.Status = cmCTestTestHandler::COMPLETED;
819 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
821 else
823 testFailed = true;
825 cres.Status = cmCTestTestHandler::FAILED;
826 if ( res == cmsysProcess_State_Expired )
828 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout" << std::endl);
829 cres.Status = cmCTestTestHandler::TIMEOUT;
831 else if ( res == cmsysProcess_State_Exception )
833 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
834 switch ( retVal )
836 case cmsysProcess_Exception_Fault:
837 cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
838 cres.Status = cmCTestTestHandler::SEGFAULT;
839 break;
840 case cmsysProcess_Exception_Illegal:
841 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
842 cres.Status = cmCTestTestHandler::ILLEGAL;
843 break;
844 case cmsysProcess_Exception_Interrupt:
845 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
846 cres.Status = cmCTestTestHandler::INTERRUPT;
847 break;
848 case cmsysProcess_Exception_Numerical:
849 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
850 cres.Status = cmCTestTestHandler::NUMERICAL;
851 break;
852 default:
853 cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
854 cres.Status = cmCTestTestHandler::OTHER_FAULT;
856 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
858 else if ( res == cmsysProcess_State_Error )
860 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Bad command " << res
861 << std::endl);
862 cres.Status = cmCTestTestHandler::BAD_COMMAND;
864 else
866 // Force fail will also be here?
867 cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed " << reason);
868 if ( it->WillFail )
870 cres.Status = cmCTestTestHandler::COMPLETED;
871 cmCTestLog(this->CTest, HANDLER_OUTPUT, " - supposed to fail");
872 testFailed = false;
874 cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
877 if ( testFailed )
879 failed.push_back(testname);
881 else
883 passed.push_back(testname);
885 if (!output.empty() && output.find("<DartMeasurement") != output.npos)
887 if (this->DartStuff.find(output.c_str()))
889 std::string dartString = this->DartStuff.match(1);
890 cmSystemTools::ReplaceString(output, dartString.c_str(),"");
891 cres.RegressionImages
892 = this->GenerateRegressionImages(dartString);
897 // if this is doing MemCheck then all the output needs to be put into
898 // Output since that it what is parsed to by cmCTestMemCheckHandler
899 if(!this->MemCheck)
901 if ( cres.Status == cmCTestTestHandler::COMPLETED )
903 this->CleanTestOutput(output, static_cast<size_t>
904 (this->CustomMaximumPassedTestOutputSize));
906 else
908 this->CleanTestOutput(output, static_cast<size_t>
909 (this->CustomMaximumFailedTestOutputSize));
913 cres.Output = output;
914 cres.ReturnValue = retVal;
915 cres.CompletionStatus = "Completed";
916 this->TestResults.push_back( cres );
919 //----------------------------------------------------------------------
920 void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
921 std::vector<cmStdString> &failed)
923 std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
924 this->TestList.clear();
926 this->GetListOfTests();
927 cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
929 this->StartTest = this->CTest->CurrentTime();
930 this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
931 double elapsed_time_start = cmSystemTools::GetTime();
933 *this->LogFile << "Start testing: " << this->StartTest << std::endl
934 << "----------------------------------------------------------"
935 << std::endl;
937 // how many tests are in based on RegExp?
938 int inREcnt = 0;
939 cmCTestTestHandler::ListOfTests::iterator it;
940 for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
942 if (it->IsInBasedOnREOptions)
944 inREcnt ++;
947 // expand the test list based on the union flag
948 if (this->UseUnion)
950 this->ExpandTestsToRunInformation((int)tmsize);
952 else
954 this->ExpandTestsToRunInformation(inREcnt);
957 int cnt = 0;
958 inREcnt = 0;
959 std::string last_directory = "";
960 for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
962 cnt ++;
963 if (it->IsInBasedOnREOptions)
965 inREcnt++;
968 // if we are out of time then skip this test, we leave two minutes
969 // to submit results
970 if (this->CTest->GetRemainingTimeAllowed() - 120 <= 0)
972 continue;
975 if (!(last_directory == it->Directory))
977 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
978 "Changing directory into " << it->Directory.c_str() << "\n");
979 *this->LogFile << "Changing directory into: " << it->Directory.c_str()
980 << std::endl;
981 last_directory = it->Directory;
982 cmSystemTools::ChangeDirectory(it->Directory.c_str());
985 if (this->UseUnion)
987 // if it is not in the list and not in the regexp then skip
988 if ((this->TestsToRun.size() &&
989 std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
990 == this->TestsToRun.end()) && !it->IsInBasedOnREOptions)
992 continue;
995 else
997 // is this test in the list of tests to run? If not then skip it
998 if ((this->TestsToRun.size() &&
999 std::find(this->TestsToRun.begin(),
1000 this->TestsToRun.end(), inREcnt)
1001 == this->TestsToRun.end()) || !it->IsInBasedOnREOptions)
1003 continue;
1007 // process this one test
1008 this->ProcessOneTest(&(*it), passed, failed, cnt,
1009 static_cast<int>(tmsize));
1012 this->EndTest = this->CTest->CurrentTime();
1013 this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
1014 this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
1015 if ( this->LogFile )
1017 *this->LogFile << "End testing: " << this->EndTest << std::endl;
1019 cmSystemTools::ChangeDirectory(current_dir.c_str());
1022 //----------------------------------------------------------------------
1023 void cmCTestTestHandler::GenerateTestCommand(std::vector<const char*>&)
1027 //----------------------------------------------------------------------
1028 void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
1030 if ( !this->CTest->GetProduceXML() )
1032 return;
1035 this->CTest->StartXML(os);
1036 os << "<Testing>\n"
1037 << "\t<StartDateTime>" << this->StartTest << "</StartDateTime>\n"
1038 << "\t<StartTestTime>" << this->StartTestTime << "</StartTestTime>\n"
1039 << "\t<TestList>\n";
1040 cmCTestTestHandler::TestResultsVector::size_type cc;
1041 for ( cc = 0; cc < this->TestResults.size(); cc ++ )
1043 cmCTestTestResult *result = &this->TestResults[cc];
1044 std::string testPath = result->Path + "/" + result->Name;
1045 os << "\t\t<Test>" << cmCTest::MakeXMLSafe(
1046 this->CTest->GetShortPathToFile(testPath.c_str()))
1047 << "</Test>" << std::endl;
1049 os << "\t</TestList>\n";
1050 for ( cc = 0; cc < this->TestResults.size(); cc ++ )
1052 cmCTestTestResult *result = &this->TestResults[cc];
1053 os << "\t<Test Status=\"";
1054 if ( result->Status == cmCTestTestHandler::COMPLETED )
1056 os << "passed";
1058 else if ( result->Status == cmCTestTestHandler::NOT_RUN )
1060 os << "notrun";
1062 else
1064 os << "failed";
1066 std::string testPath = result->Path + "/" + result->Name;
1067 os << "\">\n"
1068 << "\t\t<Name>" << cmCTest::MakeXMLSafe(result->Name) << "</Name>\n"
1069 << "\t\t<Path>" << cmCTest::MakeXMLSafe(
1070 this->CTest->GetShortPathToFile(result->Path.c_str())) << "</Path>\n"
1071 << "\t\t<FullName>" << cmCTest::MakeXMLSafe(
1072 this->CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
1073 << "\t\t<FullCommandLine>"
1074 << cmCTest::MakeXMLSafe(result->FullCommandLine)
1075 << "</FullCommandLine>\n"
1076 << "\t\t<Results>" << std::endl;
1077 if ( result->Status != cmCTestTestHandler::NOT_RUN )
1079 if ( result->Status != cmCTestTestHandler::COMPLETED ||
1080 result->ReturnValue )
1082 os << "\t\t\t<NamedMeasurement type=\"text/string\" "
1083 "name=\"Exit Code\"><Value>"
1084 << this->GetTestStatus(result->Status) << "</Value>"
1085 "</NamedMeasurement>\n"
1086 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1087 "name=\"Exit Value\"><Value>"
1088 << result->ReturnValue << "</Value></NamedMeasurement>"
1089 << std::endl;
1091 os << result->RegressionImages;
1092 os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
1093 << "name=\"Execution Time\"><Value>"
1094 << result->ExecutionTime << "</Value></NamedMeasurement>\n";
1096 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1097 << "name=\"Completion Status\"><Value>"
1098 << result->CompletionStatus << "</Value></NamedMeasurement>\n";
1101 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1102 << "name=\"Command Line\"><Value>"
1103 << result->FullCommandLine << "</Value></NamedMeasurement>\n";
1104 std::map<cmStdString,cmStdString>::iterator measureIt;
1105 for ( measureIt = result->Properties->Measurements.begin();
1106 measureIt != result->Properties->Measurements.end();
1107 ++ measureIt )
1110 << "\t\t\t<NamedMeasurement type=\"text/string\" "
1111 << "name=\"" << measureIt->first.c_str() << "\"><Value>"
1112 << measureIt->second.c_str() << "</Value></NamedMeasurement>\n";
1115 << "\t\t\t<Measurement>\n"
1116 << "\t\t\t\t<Value>";
1117 os << cmCTest::MakeXMLSafe(result->Output);
1119 << "</Value>\n"
1120 << "\t\t\t</Measurement>\n"
1121 << "\t\t</Results>\n"
1122 << "\t</Test>" << std::endl;
1125 os << "\t<EndDateTime>" << this->EndTest << "</EndDateTime>\n"
1126 << "\t<EndTestTime>" << this->EndTestTime << "</EndTestTime>\n"
1127 << "<ElapsedMinutes>"
1128 << static_cast<int>(this->ElapsedTestingTime/6)/10.0
1129 << "</ElapsedMinutes>"
1130 << "</Testing>" << std::endl;
1131 this->CTest->EndXML(os);
1134 //----------------------------------------------------------------------
1135 int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
1137 std::vector<cmStdString>::iterator it;
1138 for ( it = vec.begin(); it != vec.end(); ++it )
1140 int retVal = 0;
1141 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Run command: " << *it
1142 << std::endl);
1143 if ( !cmSystemTools::RunSingleCommand(it->c_str(), 0, &retVal, 0, true
1144 /*this->Verbose*/) || retVal != 0 )
1146 cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem running command: "
1147 << *it << std::endl);
1148 return 0;
1151 return 1;
1155 //----------------------------------------------------------------------
1156 // Find the appropriate executable to run for a test
1157 std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
1159 std::string resConfig;
1160 std::vector<std::string> extraPaths;
1161 std::vector<std::string> failedPaths;
1162 return cmCTestTestHandler::FindExecutable(this->CTest,
1163 exe, resConfig,
1164 extraPaths,
1165 failedPaths);
1168 // add additional configuraitons to the search path
1169 void cmCTestTestHandler
1170 ::AddConfigurations(cmCTest *ctest,
1171 std::vector<std::string> &attempted,
1172 std::vector<std::string> &attemptedConfigs,
1173 std::string filepath,
1174 std::string &filename)
1176 std::string tempPath;
1178 if (filepath.size())
1180 filepath += "/";
1182 tempPath = filepath + filename;
1183 attempted.push_back(tempPath);
1184 attemptedConfigs.push_back("");
1186 if(ctest->GetConfigType().size())
1188 tempPath = filepath;
1189 tempPath += ctest->GetConfigType();
1190 tempPath += "/";
1191 tempPath += filename;
1192 attempted.push_back(tempPath);
1193 attemptedConfigs.push_back(ctest->GetConfigType());
1194 // If the file is an OSX bundle then the configtyp
1195 // will be at the start of the path
1196 tempPath = ctest->GetConfigType();
1197 tempPath += "/";
1198 tempPath += filepath;
1199 tempPath += filename;
1200 attempted.push_back(tempPath);
1201 attemptedConfigs.push_back(ctest->GetConfigType());
1203 else
1205 // no config specified to try some options
1206 tempPath = filepath;
1207 tempPath += "Release/";
1208 tempPath += filename;
1209 attempted.push_back(tempPath);
1210 attemptedConfigs.push_back("Release");
1211 tempPath = filepath;
1212 tempPath += "Debug/";
1213 tempPath += filename;
1214 attempted.push_back(tempPath);
1215 attemptedConfigs.push_back("Debug");
1216 tempPath = filepath;
1217 tempPath += "MinSizeRel/";
1218 tempPath += filename;
1219 attempted.push_back(tempPath);
1220 attemptedConfigs.push_back("MinSizeRel");
1221 tempPath = filepath;
1222 tempPath += "RelWithDebInfo/";
1223 tempPath += filename;
1224 attempted.push_back(tempPath);
1225 attemptedConfigs.push_back("RelWithDebInfo");
1226 tempPath = filepath;
1227 tempPath += "Deployment/";
1228 tempPath += filename;
1229 attempted.push_back(tempPath);
1230 attemptedConfigs.push_back("Deployment");
1231 tempPath = filepath;
1232 tempPath += "Development/";
1233 tempPath += filename;
1234 attempted.push_back(tempPath);
1235 attemptedConfigs.push_back("Deployment");
1240 //----------------------------------------------------------------------
1241 // Find the appropriate executable to run for a test
1242 std::string cmCTestTestHandler
1243 ::FindExecutable(cmCTest *ctest,
1244 const char *testCommand,
1245 std::string &resultingConfig,
1246 std::vector<std::string> &extraPaths,
1247 std::vector<std::string> &failed)
1249 // now run the compiled test if we can find it
1250 std::vector<std::string> attempted;
1251 std::vector<std::string> attemptedConfigs;
1252 std::string tempPath;
1253 std::string filepath =
1254 cmSystemTools::GetFilenamePath(testCommand);
1255 std::string filename =
1256 cmSystemTools::GetFilenameName(testCommand);
1258 cmCTestTestHandler::AddConfigurations(ctest, attempted,
1259 attemptedConfigs,
1260 filepath,filename);
1262 // if extraPaths are provided and we were not passed a full path, try them,
1263 // try any extra paths
1264 if (filepath.size() == 0)
1266 for (unsigned int i = 0; i < extraPaths.size(); ++i)
1268 std::string filepathExtra =
1269 cmSystemTools::GetFilenamePath(extraPaths[i]);
1270 std::string filenameExtra =
1271 cmSystemTools::GetFilenameName(extraPaths[i]);
1272 cmCTestTestHandler::AddConfigurations(ctest,attempted,
1273 attemptedConfigs,
1274 filepathExtra,
1275 filenameExtra);
1279 // store the final location in fullPath
1280 std::string fullPath;
1282 // now look in the paths we specified above
1283 for(unsigned int ai=0;
1284 ai < attempted.size() && fullPath.size() == 0; ++ai)
1286 // first check without exe extension
1287 if(cmSystemTools::FileExists(attempted[ai].c_str())
1288 && !cmSystemTools::FileIsDirectory(attempted[ai].c_str()))
1290 fullPath = cmSystemTools::CollapseFullPath(attempted[ai].c_str());
1291 resultingConfig = attemptedConfigs[ai];
1293 // then try with the exe extension
1294 else
1296 failed.push_back(attempted[ai].c_str());
1297 tempPath = attempted[ai];
1298 tempPath += cmSystemTools::GetExecutableExtension();
1299 if(cmSystemTools::FileExists(tempPath.c_str())
1300 && !cmSystemTools::FileIsDirectory(tempPath.c_str()))
1302 fullPath = cmSystemTools::CollapseFullPath(tempPath.c_str());
1303 resultingConfig = attemptedConfigs[ai];
1305 else
1307 failed.push_back(tempPath.c_str());
1312 // if everything else failed, check the users path, but only if a full path
1313 // wasn't specified
1314 if (fullPath.size() == 0 && filepath.size() == 0)
1316 std::string path = cmSystemTools::FindProgram(filename.c_str());
1317 if (path != "")
1319 resultingConfig = "";
1320 return path;
1323 if(fullPath.size() == 0)
1325 cmCTestLog(ctest, HANDLER_OUTPUT,
1326 "Could not find executable " << testCommand << "\n"
1327 << "Looked in the following places:\n");
1328 for(std::vector<std::string>::iterator i = failed.begin();
1329 i != failed.end(); ++i)
1331 cmCTestLog(ctest, HANDLER_OUTPUT,
1332 i->c_str() << "\n");
1336 return fullPath;
1340 //----------------------------------------------------------------------
1341 void cmCTestTestHandler::GetListOfTests()
1343 if ( !this->IncludeRegExp.empty() )
1345 this->IncludeTestsRegularExpression.compile(this->IncludeRegExp.c_str());
1347 if ( !this->ExcludeRegExp.empty() )
1349 this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp.c_str());
1351 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
1352 "Constructing a list of tests" << std::endl);
1353 cmake cm;
1354 cmGlobalGenerator gg;
1355 gg.SetCMakeInstance(&cm);
1356 std::auto_ptr<cmLocalGenerator> lg(gg.CreateLocalGenerator());
1357 lg->SetGlobalGenerator(&gg);
1358 cmMakefile *mf = lg->GetMakefile();
1359 mf->AddDefinition("CTEST_CONFIGURATION_TYPE",
1360 this->CTest->GetConfigType().c_str());
1362 // Add handler for ADD_TEST
1363 cmCTestAddTestCommand* newCom1 = new cmCTestAddTestCommand;
1364 newCom1->TestHandler = this;
1365 cm.AddCommand(newCom1);
1367 // Add handler for SUBDIRS
1368 cmCTestSubdirCommand* newCom2 =
1369 new cmCTestSubdirCommand;
1370 newCom2->TestHandler = this;
1371 cm.AddCommand(newCom2);
1373 // Add handler for ADD_SUBDIRECTORY
1374 cmCTestAddSubdirectoryCommand* newCom3 =
1375 new cmCTestAddSubdirectoryCommand;
1376 newCom3->TestHandler = this;
1377 cm.AddCommand(newCom3);
1379 // Add handler for SET_SOURCE_FILES_PROPERTIES
1380 cmCTestSetTestsPropertiesCommand* newCom4
1381 = new cmCTestSetTestsPropertiesCommand;
1382 newCom4->TestHandler = this;
1383 cm.AddCommand(newCom4);
1385 const char* testFilename;
1386 if( cmSystemTools::FileExists("CTestTestfile.cmake") )
1388 // does the CTestTestfile.cmake exist ?
1389 testFilename = "CTestTestfile.cmake";
1391 else if( cmSystemTools::FileExists("DartTestfile.txt") )
1393 // does the DartTestfile.txt exist ?
1394 testFilename = "DartTestfile.txt";
1396 else
1398 return;
1401 if ( !mf->ReadListFile(0, testFilename) )
1403 return;
1405 if ( cmSystemTools::GetErrorOccuredFlag() )
1407 return;
1409 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
1410 "Done constructing a list of tests" << std::endl);
1413 //----------------------------------------------------------------------
1414 void cmCTestTestHandler::UseIncludeRegExp()
1416 this->UseIncludeRegExpFlag = true;
1419 //----------------------------------------------------------------------
1420 void cmCTestTestHandler::UseExcludeRegExp()
1422 this->UseExcludeRegExpFlag = true;
1423 this->UseExcludeRegExpFirst = this->UseIncludeRegExpFlag ? false : true;
1426 //----------------------------------------------------------------------
1427 const char* cmCTestTestHandler::GetTestStatus(int status)
1429 static const char statuses[][100] = {
1430 "Not Run",
1431 "Timeout",
1432 "SEGFAULT",
1433 "ILLEGAL",
1434 "INTERRUPT",
1435 "NUMERICAL",
1436 "OTHER_FAULT",
1437 "Failed",
1438 "BAD_COMMAND",
1439 "Completed"
1442 if ( status < cmCTestTestHandler::NOT_RUN ||
1443 status > cmCTestTestHandler::COMPLETED )
1445 return "No Status";
1447 return statuses[status];
1450 //----------------------------------------------------------------------
1451 void cmCTestTestHandler::ExpandTestsToRunInformation(int numTests)
1453 if (this->TestsToRunString.empty())
1455 return;
1458 int start;
1459 int end = -1;
1460 double stride = -1;
1461 std::string::size_type pos = 0;
1462 std::string::size_type pos2;
1463 // read start
1464 if(GetNextNumber(this->TestsToRunString, start, pos, pos2))
1466 // read end
1467 if(GetNextNumber(this->TestsToRunString, end, pos, pos2))
1469 // read stride
1470 if(GetNextRealNumber(this->TestsToRunString, stride, pos, pos2))
1472 int val =0;
1473 // now read specific numbers
1474 while(GetNextNumber(this->TestsToRunString, val, pos, pos2))
1476 this->TestsToRun.push_back(val);
1478 this->TestsToRun.push_back(val);
1483 // if start is not specified then we assume we start at 1
1484 if(start == -1)
1486 start = 1;
1489 // if end isnot specified then we assume we end with the last test
1490 if(end == -1)
1492 end = numTests;
1495 // if the stride wasn't specified then it defaults to 1
1496 if(stride == -1)
1498 stride = 1;
1501 // if we have a range then add it
1502 if(end != -1 && start != -1 && stride > 0)
1504 int i = 0;
1505 while (i*stride + start <= end)
1507 this->TestsToRun.push_back(static_cast<int>(i*stride+start));
1508 ++i;
1512 // sort the array
1513 std::sort(this->TestsToRun.begin(), this->TestsToRun.end(),
1514 std::less<int>());
1515 // remove duplicates
1516 std::vector<int>::iterator new_end =
1517 std::unique(this->TestsToRun.begin(), this->TestsToRun.end());
1518 this->TestsToRun.erase(new_end, this->TestsToRun.end());
1521 //----------------------------------------------------------------------
1522 // Just for convenience
1523 #define SPACE_REGEX "[ \t\r\n]"
1524 //----------------------------------------------------------------------
1525 std::string cmCTestTestHandler::GenerateRegressionImages(
1526 const std::string& xml)
1528 cmsys::RegularExpression twoattributes(
1529 "<DartMeasurement"
1530 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1531 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1532 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
1533 cmsys::RegularExpression threeattributes(
1534 "<DartMeasurement"
1535 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1536 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1537 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1538 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
1539 cmsys::RegularExpression fourattributes(
1540 "<DartMeasurement"
1541 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1542 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1543 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1544 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1545 SPACE_REGEX "*>([^<]*)</DartMeasurement>");
1546 cmsys::RegularExpression measurementfile(
1547 "<DartMeasurementFile"
1548 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1549 SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
1550 SPACE_REGEX "*>([^<]*)</DartMeasurementFile>");
1552 cmOStringStream ostr;
1553 bool done = false;
1554 std::string cxml = xml;
1555 while ( ! done )
1557 if ( twoattributes.find(cxml) )
1559 ostr
1560 << "\t\t\t<NamedMeasurement"
1561 << " " << twoattributes.match(1) << "=\""
1562 << twoattributes.match(2) << "\""
1563 << " " << twoattributes.match(3) << "=\""
1564 << twoattributes.match(4) << "\""
1565 << "><Value>" << twoattributes.match(5)
1566 << "</Value></NamedMeasurement>"
1567 << std::endl;
1568 cxml.erase(twoattributes.start(),
1569 twoattributes.end() - twoattributes.start());
1571 else if ( threeattributes.find(cxml) )
1573 ostr
1574 << "\t\t\t<NamedMeasurement"
1575 << " " << threeattributes.match(1) << "=\""
1576 << threeattributes.match(2) << "\""
1577 << " " << threeattributes.match(3) << "=\""
1578 << threeattributes.match(4) << "\""
1579 << " " << threeattributes.match(5) << "=\""
1580 << threeattributes.match(6) << "\""
1581 << "><Value>" << threeattributes.match(7)
1582 << "</Value></NamedMeasurement>"
1583 << std::endl;
1584 cxml.erase(threeattributes.start(),
1585 threeattributes.end() - threeattributes.start());
1587 else if ( fourattributes.find(cxml) )
1589 ostr
1590 << "\t\t\t<NamedMeasurement"
1591 << " " << fourattributes.match(1) << "=\""
1592 << fourattributes.match(2) << "\""
1593 << " " << fourattributes.match(3) << "=\""
1594 << fourattributes.match(4) << "\""
1595 << " " << fourattributes.match(5) << "=\""
1596 << fourattributes.match(6) << "\""
1597 << " " << fourattributes.match(7) << "=\""
1598 << fourattributes.match(8) << "\""
1599 << "><Value>" << fourattributes.match(9)
1600 << "</Value></NamedMeasurement>"
1601 << std::endl;
1602 cxml.erase(fourattributes.start(),
1603 fourattributes.end() - fourattributes.start());
1605 else if ( measurementfile.find(cxml) )
1607 const std::string& filename =
1608 cmCTest::CleanString(measurementfile.match(5));
1609 if ( cmSystemTools::FileExists(filename.c_str()) )
1611 long len = cmSystemTools::FileLength(filename.c_str());
1612 if ( len == 0 )
1614 std::string k1 = measurementfile.match(1);
1615 std::string v1 = measurementfile.match(2);
1616 std::string k2 = measurementfile.match(3);
1617 std::string v2 = measurementfile.match(4);
1618 if ( cmSystemTools::LowerCase(k1) == "type" )
1620 v1 = "text/string";
1622 if ( cmSystemTools::LowerCase(k2) == "type" )
1624 v2 = "text/string";
1627 ostr
1628 << "\t\t\t<NamedMeasurement"
1629 << " " << k1 << "=\"" << v1 << "\""
1630 << " " << k2 << "=\"" << v2 << "\""
1631 << " encoding=\"none\""
1632 << "><Value>Image " << filename.c_str()
1633 << " is empty</Value></NamedMeasurement>";
1635 else
1637 std::ifstream ifs(filename.c_str(), std::ios::in
1638 #ifdef _WIN32
1639 | std::ios::binary
1640 #endif
1642 unsigned char *file_buffer = new unsigned char [ len + 1 ];
1643 ifs.read(reinterpret_cast<char*>(file_buffer), len);
1644 unsigned char *encoded_buffer
1645 = new unsigned char [ static_cast<int>(len * 1.5 + 5) ];
1647 unsigned long rlen
1648 = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
1649 unsigned long cc;
1651 ostr
1652 << "\t\t\t<NamedMeasurement"
1653 << " " << measurementfile.match(1) << "=\""
1654 << measurementfile.match(2) << "\""
1655 << " " << measurementfile.match(3) << "=\""
1656 << measurementfile.match(4) << "\""
1657 << " encoding=\"base64\""
1658 << ">" << std::endl << "\t\t\t\t<Value>";
1659 for ( cc = 0; cc < rlen; cc ++ )
1661 ostr << encoded_buffer[cc];
1662 if ( cc % 60 == 0 && cc )
1664 ostr << std::endl;
1667 ostr
1668 << "</Value>" << std::endl << "\t\t\t</NamedMeasurement>"
1669 << std::endl;
1670 delete [] file_buffer;
1671 delete [] encoded_buffer;
1674 else
1676 int idx = 4;
1677 if ( measurementfile.match(1) == "name" )
1679 idx = 2;
1681 ostr
1682 << "\t\t\t<NamedMeasurement"
1683 << " name=\"" << measurementfile.match(idx) << "\""
1684 << " text=\"text/string\""
1685 << "><Value>File " << filename.c_str()
1686 << " not found</Value></NamedMeasurement>"
1687 << std::endl;
1688 cmCTestLog(this->CTest, HANDLER_OUTPUT, "File \"" << filename.c_str()
1689 << "\" not found." << std::endl);
1691 cxml.erase(measurementfile.start(),
1692 measurementfile.end() - measurementfile.start());
1694 else
1696 done = true;
1699 return ostr.str();
1702 //----------------------------------------------------------------------
1703 void cmCTestTestHandler::SetIncludeRegExp(const char *arg)
1705 this->IncludeRegExp = arg;
1708 //----------------------------------------------------------------------
1709 void cmCTestTestHandler::SetExcludeRegExp(const char *arg)
1711 this->ExcludeRegExp = arg;
1714 //----------------------------------------------------------------------
1715 void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
1717 if ( !in )
1719 return;
1721 this->TestsToRunString = in;
1722 // if the argument is a file, then read it and use the contents as the
1723 // string
1724 if(cmSystemTools::FileExists(in))
1726 std::ifstream fin(in);
1727 unsigned long filelen = cmSystemTools::FileLength(in);
1728 char* buff = new char[filelen+1];
1729 fin.getline(buff, filelen);
1730 buff[fin.gcount()] = 0;
1731 this->TestsToRunString = buff;
1735 //----------------------------------------------------------------------
1736 bool cmCTestTestHandler::CleanTestOutput(std::string& output,
1737 size_t remove_threshold)
1739 if ( remove_threshold == 0 )
1741 return true;
1743 if ( output.find("CTEST_FULL_OUTPUT") != output.npos )
1745 return true;
1747 cmOStringStream ostr;
1748 std::string::size_type cc;
1749 std::string::size_type skipsize = 0;
1750 int inTag = 0;
1751 int skipped = 0;
1752 for ( cc = 0; cc < output.size(); cc ++ )
1754 int ch = output[cc];
1755 if ( ch < 0 || ch > 255 )
1757 break;
1759 if ( ch == '<' )
1761 inTag = 1;
1763 if ( !inTag )
1765 int notskip = 0;
1766 // Skip
1767 if ( skipsize < remove_threshold )
1769 ostr << static_cast<char>(ch);
1770 notskip = 1;
1772 skipsize ++;
1773 if ( notskip && skipsize >= remove_threshold )
1775 skipped = 1;
1778 else
1780 ostr << static_cast<char>(ch);
1782 if ( ch == '>' )
1784 inTag = 0;
1787 if ( skipped )
1789 ostr << "..." << std::endl << "The rest of the test output was removed "
1790 "since it exceeds the threshold of "
1791 << remove_threshold << " characters." << std::endl;
1793 output = ostr.str();
1794 return true;
1797 //----------------------------------------------------------------------
1798 bool cmCTestTestHandler::SetTestsProperties(
1799 const std::vector<std::string>& args)
1801 std::vector<std::string>::const_iterator it;
1802 std::vector<cmStdString> tests;
1803 bool found = false;
1804 for ( it = args.begin(); it != args.end(); ++ it )
1806 if ( *it == "PROPERTIES" )
1808 found = true;
1809 break;
1811 tests.push_back(*it);
1813 if ( !found )
1815 return false;
1817 ++ it; // skip PROPERTIES
1818 for ( ; it != args.end(); ++ it )
1820 std::string key = *it;
1821 ++ it;
1822 if ( it == args.end() )
1824 break;
1826 std::string val = *it;
1827 std::vector<cmStdString>::const_iterator tit;
1828 for ( tit = tests.begin(); tit != tests.end(); ++ tit )
1830 cmCTestTestHandler::ListOfTests::iterator rtit;
1831 for ( rtit = this->TestList.begin();
1832 rtit != this->TestList.end();
1833 ++ rtit )
1835 if ( *tit == rtit->Name )
1837 if ( key == "WILL_FAIL" )
1839 rtit->WillFail = cmSystemTools::IsOn(val.c_str());
1841 if ( key == "TIMEOUT" )
1843 rtit->Timeout = atof(val.c_str());
1845 if ( key == "FAIL_REGULAR_EXPRESSION" )
1847 std::vector<std::string> lval;
1848 cmSystemTools::ExpandListArgument(val.c_str(), lval);
1849 std::vector<std::string>::iterator crit;
1850 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
1852 rtit->ErrorRegularExpressions.push_back(
1853 std::pair<cmsys::RegularExpression, std::string>(
1854 cmsys::RegularExpression(crit->c_str()),
1855 std::string(crit->c_str())));
1858 if ( key == "MEASUREMENT" )
1860 size_t pos = val.find_first_of("=");
1861 if ( pos != val.npos )
1863 std::string mKey = val.substr(0, pos);
1864 const char* mVal = val.c_str() + pos + 1;
1865 rtit->Measurements[mKey] = mVal;
1867 else
1869 rtit->Measurements[val] = "1";
1872 if ( key == "PASS_REGULAR_EXPRESSION" )
1874 std::vector<std::string> lval;
1875 cmSystemTools::ExpandListArgument(val.c_str(), lval);
1876 std::vector<std::string>::iterator crit;
1877 for ( crit = lval.begin(); crit != lval.end(); ++ crit )
1879 rtit->RequiredRegularExpressions.push_back(
1880 std::pair<cmsys::RegularExpression, std::string>(
1881 cmsys::RegularExpression(crit->c_str()),
1882 std::string(crit->c_str())));
1889 return true;
1892 //----------------------------------------------------------------------
1893 bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
1895 const std::string& testname = args[0];
1896 cmCTestLog(this->CTest, DEBUG, "Add test: " << args[0] << std::endl);
1897 if (this->UseExcludeRegExpFlag &&
1898 this->UseExcludeRegExpFirst &&
1899 this->ExcludeTestsRegularExpression.find(testname.c_str()))
1901 return true;
1903 if ( this->MemCheck )
1905 std::vector<cmStdString>::iterator it;
1906 bool found = false;
1907 for ( it = this->CustomTestsIgnore.begin();
1908 it != this->CustomTestsIgnore.end(); ++ it )
1910 if ( *it == testname )
1912 found = true;
1913 break;
1916 if ( found )
1918 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore memcheck: "
1919 << *it << std::endl);
1920 return true;
1923 else
1925 std::vector<cmStdString>::iterator it;
1926 bool found = false;
1927 for ( it = this->CustomTestsIgnore.begin();
1928 it != this->CustomTestsIgnore.end(); ++ it )
1930 if ( *it == testname )
1932 found = true;
1933 break;
1936 if ( found )
1938 cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Ignore test: "
1939 << *it << std::endl);
1940 return true;
1944 cmCTestTestProperties test;
1945 test.Name = testname;
1946 test.Args = args;
1947 test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
1948 cmCTestLog(this->CTest, DEBUG, "Set test directory: "
1949 << test.Directory << std::endl);
1951 test.IsInBasedOnREOptions = true;
1952 test.WillFail = false;
1953 test.Timeout = 0;
1954 if (this->UseIncludeRegExpFlag &&
1955 !this->IncludeTestsRegularExpression.find(testname.c_str()))
1957 test.IsInBasedOnREOptions = false;
1959 else if (this->UseExcludeRegExpFlag &&
1960 !this->UseExcludeRegExpFirst &&
1961 this->ExcludeTestsRegularExpression.find(testname.c_str()))
1963 test.IsInBasedOnREOptions = false;
1965 this->TestList.push_back(test);
1966 return true;