cmCTestTestHandler.cxx 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCTestTestHandler.h"
  14. #include "cmCTest.h"
  15. #include "cmake.h"
  16. #include "cmGeneratedFileStream.h"
  17. #include <cmsys/Process.h>
  18. #include <cmsys/RegularExpression.hxx>
  19. #include <cmsys/Base64.h>
  20. #include "cmMakefile.h"
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #include <float.h>
  24. //----------------------------------------------------------------------
  25. bool TryExecutable(const char *dir, const char *file,
  26. std::string *fullPath, const char *subdir)
  27. {
  28. // try current directory
  29. std::string tryPath;
  30. if (dir && strcmp(dir,""))
  31. {
  32. tryPath = dir;
  33. tryPath += "/";
  34. }
  35. if (subdir && strcmp(subdir,""))
  36. {
  37. tryPath += subdir;
  38. tryPath += "/";
  39. }
  40. tryPath += file;
  41. if(cmSystemTools::FileExists(tryPath.c_str()))
  42. {
  43. *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
  44. return true;
  45. }
  46. tryPath += cmSystemTools::GetExecutableExtension();
  47. if(cmSystemTools::FileExists(tryPath.c_str()))
  48. {
  49. *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
  50. return true;
  51. }
  52. return false;
  53. }
  54. //----------------------------------------------------------------------
  55. // get the next number in a string with numbers separated by ,
  56. // pos is the start of the search and pos2 is the end of the search
  57. // pos becomes pos2 after a call to GetNextNumber.
  58. // -1 is returned at the end of the list.
  59. inline int GetNextNumber(std::string const& in,
  60. int& val,
  61. std::string::size_type& pos,
  62. std::string::size_type& pos2)
  63. {
  64. pos2 = in.find(',', pos);
  65. if(pos2 != in.npos)
  66. {
  67. if(pos2-pos == 0)
  68. {
  69. val = -1;
  70. }
  71. else
  72. {
  73. val = atoi(in.substr(pos, pos2-pos).c_str());
  74. }
  75. pos = pos2+1;
  76. return 1;
  77. }
  78. else
  79. {
  80. if(in.size()-pos == 0)
  81. {
  82. val = -1;
  83. }
  84. else
  85. {
  86. val = atoi(in.substr(pos, in.size()-pos).c_str());
  87. }
  88. return 0;
  89. }
  90. }
  91. //----------------------------------------------------------------------
  92. // get the next number in a string with numbers separated by ,
  93. // pos is the start of the search and pos2 is the end of the search
  94. // pos becomes pos2 after a call to GetNextNumber.
  95. // -1 is returned at the end of the list.
  96. inline int GetNextRealNumber(std::string const& in,
  97. double& val,
  98. std::string::size_type& pos,
  99. std::string::size_type& pos2)
  100. {
  101. pos2 = in.find(',', pos);
  102. if(pos2 != in.npos)
  103. {
  104. if(pos2-pos == 0)
  105. {
  106. val = -1;
  107. }
  108. else
  109. {
  110. val = atof(in.substr(pos, pos2-pos).c_str());
  111. }
  112. pos = pos2+1;
  113. return 1;
  114. }
  115. else
  116. {
  117. if(in.size()-pos == 0)
  118. {
  119. val = -1;
  120. }
  121. else
  122. {
  123. val = atof(in.substr(pos, in.size()-pos).c_str());
  124. }
  125. return 0;
  126. }
  127. }
  128. //----------------------------------------------------------------------
  129. cmCTestTestHandler::cmCTestTestHandler()
  130. {
  131. m_UseUnion = false;
  132. m_UseIncludeRegExp = false;
  133. m_UseExcludeRegExp = false;
  134. m_UseExcludeRegExpFirst = false;
  135. m_CustomMaximumPassedTestOutputSize = 1 * 1024;
  136. m_CustomMaximumFailedTestOutputSize = 300 * 1024;
  137. m_MemCheck = false;
  138. }
  139. //----------------------------------------------------------------------
  140. void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
  141. {
  142. cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
  143. m_CustomPreTest);
  144. cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST",
  145. m_CustomPostTest);
  146. cmCTest::PopulateCustomVector(mf,
  147. "CTEST_CUSTOM_TESTS_IGNORE",
  148. m_CustomTestsIgnore);
  149. cmCTest::PopulateCustomInteger(mf,
  150. "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
  151. m_CustomMaximumPassedTestOutputSize);
  152. cmCTest::PopulateCustomInteger(mf,
  153. "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
  154. m_CustomMaximumFailedTestOutputSize);
  155. }
  156. //----------------------------------------------------------------------
  157. int cmCTestTestHandler::PreProcessHandler()
  158. {
  159. if ( !this->ExecuteCommands(m_CustomPreTest) )
  160. {
  161. std::cerr << "Problem executing pre-test command(s)." << std::endl;
  162. return 0;
  163. }
  164. return 1;
  165. }
  166. //----------------------------------------------------------------------
  167. int cmCTestTestHandler::PostProcessHandler()
  168. {
  169. if ( !this->ExecuteCommands(m_CustomPostTest) )
  170. {
  171. std::cerr << "Problem executing post-test command(s)." << std::endl;
  172. return 0;
  173. }
  174. return 1;
  175. }
  176. //----------------------------------------------------------------------
  177. //clearly it would be nice if this were broken up into a few smaller
  178. //functions and commented...
  179. int cmCTestTestHandler::ProcessHandler()
  180. {
  181. m_TestResults.clear();
  182. std::cout << (m_MemCheck ? "Memory check" : "Test") << " project" << std::endl;
  183. if ( ! this->PreProcessHandler() )
  184. {
  185. return -1;
  186. }
  187. std::vector<cmStdString> passed;
  188. std::vector<cmStdString> failed;
  189. int total;
  190. this->ProcessDirectory(passed, failed);
  191. total = int(passed.size()) + int(failed.size());
  192. if (total == 0)
  193. {
  194. if ( !m_CTest->GetShowOnly() )
  195. {
  196. std::cerr << "No tests were found!!!\n";
  197. }
  198. }
  199. else
  200. {
  201. if (m_Verbose && passed.size() &&
  202. (m_UseIncludeRegExp || m_UseExcludeRegExp))
  203. {
  204. std::cerr << "\nThe following tests passed:\n";
  205. for(std::vector<cmStdString>::iterator j = passed.begin();
  206. j != passed.end(); ++j)
  207. {
  208. std::cerr << "\t" << *j << "\n";
  209. }
  210. }
  211. float percent = float(passed.size()) * 100.0f / total;
  212. if ( failed.size() > 0 && percent > 99)
  213. {
  214. percent = 99;
  215. }
  216. fprintf(stderr,"\n%.0f%% tests passed, %i tests failed out of %i\n",
  217. percent, int(failed.size()), total);
  218. if (failed.size())
  219. {
  220. cmGeneratedFileStream ofs;
  221. std::cerr << "\nThe following tests FAILED:\n";
  222. m_CTest->OpenOutputFile("Temporary", "LastTestsFailed.log", ofs);
  223. std::vector<cmCTestTestHandler::cmCTestTestResult>::iterator ftit;
  224. for(ftit = m_TestResults.begin();
  225. ftit != m_TestResults.end(); ++ftit)
  226. {
  227. if ( ftit->m_Status != cmCTestTestHandler::COMPLETED )
  228. {
  229. ofs << ftit->m_TestCount << ":" << ftit->m_Name << std::endl;
  230. fprintf(stderr, "\t%3d - %s (%s)\n", ftit->m_TestCount, ftit->m_Name.c_str(),
  231. this->GetTestStatus(ftit->m_Status));
  232. }
  233. }
  234. }
  235. }
  236. if ( m_CTest->GetProduceXML() )
  237. {
  238. cmGeneratedFileStream xmlfile;
  239. if( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(),
  240. (m_MemCheck ? "DynamicAnalysis.xml" : "Test.xml"), xmlfile, true) )
  241. {
  242. std::cerr << "Cannot create " << (m_MemCheck ? "memory check" : "testing")
  243. << " XML file" << std::endl;
  244. return 1;
  245. }
  246. this->GenerateDartOutput(xmlfile);
  247. }
  248. if ( ! this->PostProcessHandler() )
  249. {
  250. return -1;
  251. }
  252. if ( !failed.empty() )
  253. {
  254. return -1;
  255. }
  256. return 0;
  257. }
  258. //----------------------------------------------------------------------
  259. void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
  260. std::vector<cmStdString> &failed)
  261. {
  262. std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
  263. cmsys::RegularExpression dartStuff("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
  264. tm_ListOfTests testlist;
  265. this->GetListOfTests(&testlist);
  266. tm_ListOfTests::size_type tmsize = testlist.size();
  267. cmGeneratedFileStream ofs;
  268. cmGeneratedFileStream *olog = 0;
  269. if ( !m_CTest->GetShowOnly() && tmsize > 0 &&
  270. m_CTest->OpenOutputFile("Temporary",
  271. (m_MemCheck?"LastMemCheck.log":"LastTest.log"), ofs) )
  272. {
  273. olog = &ofs;
  274. }
  275. m_StartTest = m_CTest->CurrentTime();
  276. double elapsed_time_start = cmSystemTools::GetTime();
  277. if ( olog )
  278. {
  279. *olog << "Start testing: " << m_StartTest << std::endl
  280. << "----------------------------------------------------------"
  281. << std::endl;
  282. }
  283. // how many tests are in based on RegExp?
  284. int inREcnt = 0;
  285. tm_ListOfTests::iterator it;
  286. for ( it = testlist.begin(); it != testlist.end(); it ++ )
  287. {
  288. if (it->m_IsInBasedOnREOptions)
  289. {
  290. inREcnt ++;
  291. }
  292. }
  293. // expand the test list based on the union flag
  294. if (m_UseUnion)
  295. {
  296. this->ExpandTestsToRunInformation((int)tmsize);
  297. }
  298. else
  299. {
  300. this->ExpandTestsToRunInformation(inREcnt);
  301. }
  302. int cnt = 0;
  303. inREcnt = 0;
  304. std::string last_directory = "";
  305. for ( it = testlist.begin(); it != testlist.end(); it ++ )
  306. {
  307. cnt ++;
  308. if (it->m_IsInBasedOnREOptions)
  309. {
  310. inREcnt++;
  311. }
  312. const std::string& testname = it->m_Name;
  313. tm_VectorOfListFileArgs& args = it->m_Args;
  314. cmCTestTestResult cres;
  315. cres.m_Status = cmCTestTestHandler::NOT_RUN;
  316. cres.m_TestCount = cnt;
  317. if (!(last_directory == it->m_Directory))
  318. {
  319. if ( m_Verbose )
  320. {
  321. std::cerr << "Changing directory into "
  322. << it->m_Directory.c_str() << "\n";
  323. }
  324. last_directory = it->m_Directory;
  325. cmSystemTools::ChangeDirectory(it->m_Directory.c_str());
  326. }
  327. cres.m_Name = testname;
  328. cres.m_Path = it->m_Directory.c_str();
  329. if (m_UseUnion)
  330. {
  331. // if it is not in the list and not in the regexp then skip
  332. if ((m_TestsToRun.size() &&
  333. std::find(m_TestsToRun.begin(), m_TestsToRun.end(), cnt)
  334. == m_TestsToRun.end()) && !it->m_IsInBasedOnREOptions)
  335. {
  336. continue;
  337. }
  338. }
  339. else
  340. {
  341. // is this test in the list of tests to run? If not then skip it
  342. if ((m_TestsToRun.size() &&
  343. std::find(m_TestsToRun.begin(), m_TestsToRun.end(), inREcnt)
  344. == m_TestsToRun.end()) || !it->m_IsInBasedOnREOptions)
  345. {
  346. continue;
  347. }
  348. }
  349. std::cerr.width(3);
  350. std::cerr << cnt << "/";
  351. std::cerr.width(3);
  352. std::cerr << tmsize << " Testing ";
  353. std::string outname = testname;
  354. outname.resize(30, ' ');
  355. if ( m_CTest->GetShowOnly() )
  356. {
  357. std::cerr << outname.c_str() << "\n";
  358. }
  359. else
  360. {
  361. std::cerr << outname.c_str();
  362. std::cerr.flush();
  363. }
  364. //std::cerr << "Testing " << args[0] << " ... ";
  365. // find the test executable
  366. std::string actualCommand = this->FindTheExecutable(args[1].Value.c_str());
  367. std::string testCommand = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
  368. // continue if we did not find the executable
  369. if (testCommand == "")
  370. {
  371. std::cerr << "Unable to find executable: " <<
  372. args[1].Value.c_str() << "\n";
  373. if ( !m_CTest->GetShowOnly() )
  374. {
  375. cres.m_FullCommandLine = actualCommand;
  376. m_TestResults.push_back( cres );
  377. failed.push_back(testname);
  378. continue;
  379. }
  380. }
  381. // add the arguments
  382. tm_VectorOfListFileArgs::const_iterator j = args.begin();
  383. ++j;
  384. ++j;
  385. std::vector<const char*> arguments;
  386. this->GenerateTestCommand(arguments);
  387. arguments.push_back(actualCommand.c_str());
  388. for(;j != args.end(); ++j)
  389. {
  390. testCommand += " ";
  391. testCommand += cmSystemTools::EscapeSpaces(j->Value.c_str());
  392. arguments.push_back(j->Value.c_str());
  393. }
  394. arguments.push_back(0);
  395. /**
  396. * Run an executable command and put the stdout in output.
  397. */
  398. std::string output;
  399. int retVal = 0;
  400. if ( m_Verbose )
  401. {
  402. std::cout << std::endl << (m_MemCheck?"MemCheck":"Test") << " command: " << testCommand << std::endl;
  403. }
  404. if ( olog )
  405. {
  406. *olog << cnt << "/" << tmsize
  407. << " Test: " << testname.c_str() << std::endl;
  408. *olog << "Command: ";
  409. std::vector<cmStdString>::size_type ll;
  410. for ( ll = 0; ll < arguments.size()-1; ll ++ )
  411. {
  412. *olog << "\"" << arguments[ll] << "\" ";
  413. }
  414. *olog
  415. << std::endl
  416. << "Directory: " << it->m_Directory << std::endl
  417. << "\"" << testname.c_str() << "\" start time: "
  418. << m_CTest->CurrentTime() << std::endl
  419. << "Output:" << std::endl
  420. << "----------------------------------------------------------"
  421. << std::endl;
  422. }
  423. int res = 0;
  424. double clock_start, clock_finish;
  425. clock_start = cmSystemTools::GetTime();
  426. if ( !m_CTest->GetShowOnly() )
  427. {
  428. res = m_CTest->RunTest(arguments, &output, &retVal, olog);
  429. }
  430. clock_finish = cmSystemTools::GetTime();
  431. if ( olog )
  432. {
  433. double ttime = clock_finish - clock_start;
  434. int hours = static_cast<int>(ttime / (60 * 60));
  435. int minutes = static_cast<int>(ttime / 60) % 60;
  436. int seconds = static_cast<int>(ttime) % 60;
  437. char buffer[100];
  438. sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
  439. *olog
  440. << "----------------------------------------------------------"
  441. << std::endl
  442. << "\"" << testname.c_str() << "\" end time: "
  443. << m_CTest->CurrentTime() << std::endl
  444. << "\"" << testname.c_str() << "\" time elapsed: "
  445. << buffer << std::endl
  446. << "----------------------------------------------------------"
  447. << std::endl << std::endl;
  448. }
  449. cres.m_ExecutionTime = (double)(clock_finish - clock_start);
  450. cres.m_FullCommandLine = testCommand;
  451. if ( !m_CTest->GetShowOnly() )
  452. {
  453. if (res == cmsysProcess_State_Exited && retVal == 0)
  454. {
  455. std::cerr << " Passed\n";
  456. passed.push_back(testname);
  457. cres.m_Status = cmCTestTestHandler::COMPLETED;
  458. }
  459. else
  460. {
  461. cres.m_Status = cmCTestTestHandler::FAILED;
  462. if ( res == cmsysProcess_State_Expired )
  463. {
  464. std::cerr << "***Timeout\n";
  465. cres.m_Status = cmCTestTestHandler::TIMEOUT;
  466. }
  467. else if ( res == cmsysProcess_State_Exception )
  468. {
  469. std::cerr << "***Exception: ";
  470. switch ( retVal )
  471. {
  472. case cmsysProcess_Exception_Fault:
  473. std::cerr << "SegFault";
  474. cres.m_Status = cmCTestTestHandler::SEGFAULT;
  475. break;
  476. case cmsysProcess_Exception_Illegal:
  477. std::cerr << "Illegal";
  478. cres.m_Status = cmCTestTestHandler::ILLEGAL;
  479. break;
  480. case cmsysProcess_Exception_Interrupt:
  481. std::cerr << "Interrupt";
  482. cres.m_Status = cmCTestTestHandler::INTERRUPT;
  483. break;
  484. case cmsysProcess_Exception_Numerical:
  485. std::cerr << "Numerical";
  486. cres.m_Status = cmCTestTestHandler::NUMERICAL;
  487. break;
  488. default:
  489. std::cerr << "Other";
  490. cres.m_Status = cmCTestTestHandler::OTHER_FAULT;
  491. }
  492. std::cerr << "\n";
  493. }
  494. else if ( res == cmsysProcess_State_Error )
  495. {
  496. std::cerr << "***Bad command " << res << "\n";
  497. cres.m_Status = cmCTestTestHandler::BAD_COMMAND;
  498. }
  499. else
  500. {
  501. std::cerr << "***Failed\n";
  502. }
  503. failed.push_back(testname);
  504. }
  505. if (output != "")
  506. {
  507. if (dartStuff.find(output.c_str()))
  508. {
  509. std::string dartString = dartStuff.match(1);
  510. cmSystemTools::ReplaceString(output, dartString.c_str(),"");
  511. cres.m_RegressionImages = this->GenerateRegressionImages(dartString);
  512. }
  513. }
  514. }
  515. if ( cres.m_Status == cmCTestTestHandler::COMPLETED )
  516. {
  517. this->CleanTestOutput(output, static_cast<size_t>(m_CustomMaximumPassedTestOutputSize));
  518. }
  519. else
  520. {
  521. this->CleanTestOutput(output, static_cast<size_t>(m_CustomMaximumFailedTestOutputSize));
  522. }
  523. cres.m_Output = output;
  524. cres.m_ReturnValue = retVal;
  525. cres.m_CompletionStatus = "Completed";
  526. m_TestResults.push_back( cres );
  527. }
  528. m_EndTest = m_CTest->CurrentTime();
  529. m_ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
  530. if ( olog )
  531. {
  532. *olog << "End testing: " << m_EndTest << std::endl;
  533. }
  534. cmSystemTools::ChangeDirectory(current_dir.c_str());
  535. }
  536. //----------------------------------------------------------------------
  537. void cmCTestTestHandler::GenerateTestCommand(std::vector<const char*>&)
  538. {
  539. }
  540. //----------------------------------------------------------------------
  541. void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
  542. {
  543. if ( !m_CTest->GetProduceXML() )
  544. {
  545. return;
  546. }
  547. m_CTest->StartXML(os);
  548. os << "<Testing>\n"
  549. << "\t<StartDateTime>" << m_StartTest << "</StartDateTime>\n"
  550. << "\t<TestList>\n";
  551. tm_TestResultsVector::size_type cc;
  552. for ( cc = 0; cc < m_TestResults.size(); cc ++ )
  553. {
  554. cmCTestTestResult *result = &m_TestResults[cc];
  555. std::string testPath = result->m_Path + "/" + result->m_Name;
  556. os << "\t\t<Test>" << cmCTest::MakeXMLSafe(
  557. m_CTest->GetShortPathToFile(testPath.c_str()))
  558. << "</Test>" << std::endl;
  559. }
  560. os << "\t</TestList>\n";
  561. for ( cc = 0; cc < m_TestResults.size(); cc ++ )
  562. {
  563. cmCTestTestResult *result = &m_TestResults[cc];
  564. os << "\t<Test Status=\"";
  565. if ( result->m_Status == cmCTestTestHandler::COMPLETED )
  566. {
  567. os << "passed";
  568. }
  569. else if ( result->m_Status == cmCTestTestHandler::NOT_RUN )
  570. {
  571. os << "notrun";
  572. }
  573. else
  574. {
  575. os << "failed";
  576. }
  577. std::string testPath = result->m_Path + "/" + result->m_Name;
  578. os << "\">\n"
  579. << "\t\t<Name>" << cmCTest::MakeXMLSafe(result->m_Name) << "</Name>\n"
  580. << "\t\t<Path>" << cmCTest::MakeXMLSafe(
  581. m_CTest->GetShortPathToFile(result->m_Path.c_str())) << "</Path>\n"
  582. << "\t\t<FullName>" << cmCTest::MakeXMLSafe(
  583. m_CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
  584. << "\t\t<FullCommandLine>"
  585. << cmCTest::MakeXMLSafe(result->m_FullCommandLine)
  586. << "</FullCommandLine>\n"
  587. << "\t\t<Results>" << std::endl;
  588. if ( result->m_Status != cmCTestTestHandler::NOT_RUN )
  589. {
  590. if ( result->m_Status != cmCTestTestHandler::COMPLETED || result->m_ReturnValue )
  591. {
  592. os << "\t\t\t<NamedMeasurement type=\"text/string\" name=\"Exit Code\"><Value>"
  593. << this->GetTestStatus(result->m_Status) << "</Value></NamedMeasurement>\n"
  594. << "\t\t\t<NamedMeasurement type=\"text/string\" name=\"Exit Value\"><Value>"
  595. << result->m_ReturnValue << "</Value></NamedMeasurement>" << std::endl;
  596. }
  597. os << result->m_RegressionImages;
  598. os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
  599. << "name=\"Execution Time\"><Value>"
  600. << result->m_ExecutionTime << "</Value></NamedMeasurement>\n";
  601. os
  602. << "\t\t\t<NamedMeasurement type=\"text/string\" "
  603. << "name=\"Completion Status\"><Value>"
  604. << result->m_CompletionStatus << "</Value></NamedMeasurement>\n";
  605. }
  606. os
  607. << "\t\t\t<Measurement>\n"
  608. << "\t\t\t\t<Value>";
  609. os << cmCTest::MakeXMLSafe(result->m_Output);
  610. os
  611. << "</Value>\n"
  612. << "\t\t\t</Measurement>\n"
  613. << "\t\t</Results>\n"
  614. << "\t</Test>" << std::endl;
  615. }
  616. os << "\t<EndDateTime>" << m_EndTest << "</EndDateTime>\n"
  617. << "<ElapsedMinutes>"
  618. << static_cast<int>(m_ElapsedTestingTime/6)/10.0
  619. << "</ElapsedMinutes>"
  620. << "</Testing>" << std::endl;
  621. m_CTest->EndXML(os);
  622. }
  623. //----------------------------------------------------------------------
  624. int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
  625. {
  626. std::vector<cmStdString>::iterator it;
  627. for ( it = vec.begin(); it != vec.end(); ++it )
  628. {
  629. int retVal = 0;
  630. if ( m_Verbose )
  631. {
  632. std::cout << "Run command: " << *it << std::endl;
  633. }
  634. if ( !cmSystemTools::RunSingleCommand(it->c_str(), 0, &retVal, 0, true /*m_Verbose*/) ||
  635. retVal != 0 )
  636. {
  637. std::cerr << "Problem running command: " << *it << std::endl;
  638. return 0;
  639. }
  640. }
  641. return 1;
  642. }
  643. //----------------------------------------------------------------------
  644. std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
  645. {
  646. std::string fullPath = "";
  647. std::string dir;
  648. std::string file;
  649. cmSystemTools::SplitProgramPath(exe, dir, file);
  650. if(m_CTest->GetConfigType() != "" &&
  651. ::TryExecutable(dir.c_str(), file.c_str(), &fullPath,
  652. m_CTest->GetConfigType().c_str()))
  653. {
  654. return fullPath;
  655. }
  656. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"."))
  657. {
  658. return fullPath;
  659. }
  660. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,""))
  661. {
  662. return fullPath;
  663. }
  664. if ( m_CTest->GetConfigType() == "" )
  665. {
  666. // No config type, so try to guess it
  667. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Release"))
  668. {
  669. return fullPath;
  670. }
  671. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Debug"))
  672. {
  673. return fullPath;
  674. }
  675. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"MinSizeRel"))
  676. {
  677. return fullPath;
  678. }
  679. if (::TryExecutable(dir.c_str(),file.c_str(),&fullPath,"RelWithDebInfo"))
  680. {
  681. return fullPath;
  682. }
  683. }
  684. // if everything else failed, check the users path
  685. if (dir != "")
  686. {
  687. std::string path = cmSystemTools::FindProgram(file.c_str());
  688. if (path != "")
  689. {
  690. return path;
  691. }
  692. }
  693. if ( m_CTest->GetConfigType() != "" )
  694. {
  695. dir += "/";
  696. dir += m_CTest->GetConfigType();
  697. dir += "/";
  698. dir += file;
  699. cmSystemTools::Error("config type specified on the command line, but test executable not found.",
  700. dir.c_str());
  701. return "";
  702. }
  703. return fullPath;
  704. }
  705. //----------------------------------------------------------------------
  706. void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist)
  707. {
  708. // does the DartTestfile.txt exist ?
  709. if(!cmSystemTools::FileExists("DartTestfile.txt"))
  710. {
  711. return;
  712. }
  713. // parse the file
  714. std::ifstream fin("DartTestfile.txt");
  715. if(!fin)
  716. {
  717. return;
  718. }
  719. cmsys::RegularExpression ireg(this->m_IncludeRegExp.c_str());
  720. cmsys::RegularExpression ereg(this->m_ExcludeRegExp.c_str());
  721. cmListFileCache cache;
  722. cmListFile* listFile = cache.GetFileCache("DartTestfile.txt", false);
  723. for(std::vector<cmListFileFunction>::const_iterator f =
  724. listFile->m_Functions.begin(); f != listFile->m_Functions.end(); ++f)
  725. {
  726. const cmListFileFunction& lff = *f;
  727. const std::string& name = lff.m_Name;
  728. const tm_VectorOfListFileArgs& args = lff.m_Arguments;
  729. if (name == "SUBDIRS")
  730. {
  731. std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  732. for(tm_VectorOfListFileArgs::const_iterator j = args.begin();
  733. j != args.end(); ++j)
  734. {
  735. std::string nwd = cwd + "/";
  736. nwd += j->Value;
  737. if (cmSystemTools::FileIsDirectory(nwd.c_str()))
  738. {
  739. cmSystemTools::ChangeDirectory(nwd.c_str());
  740. this->GetListOfTests(testlist);
  741. }
  742. }
  743. // return to the original directory
  744. cmSystemTools::ChangeDirectory(cwd.c_str());
  745. }
  746. if (name == "ADD_TEST")
  747. {
  748. const std::string& testname = args[0].Value;
  749. if (this->m_UseExcludeRegExp &&
  750. this->m_UseExcludeRegExpFirst &&
  751. ereg.find(testname.c_str()))
  752. {
  753. continue;
  754. }
  755. if ( m_MemCheck )
  756. {
  757. std::vector<cmStdString>::iterator it;
  758. bool found = false;
  759. for ( it = m_CustomTestsIgnore.begin();
  760. it != m_CustomTestsIgnore.end(); ++ it )
  761. {
  762. if ( *it == testname )
  763. {
  764. found = true;
  765. break;
  766. }
  767. }
  768. if ( found )
  769. {
  770. if ( m_Verbose )
  771. {
  772. std::cout << "Ignore memcheck: " << *it << std::endl;
  773. }
  774. continue;
  775. }
  776. }
  777. else
  778. {
  779. std::vector<cmStdString>::iterator it;
  780. bool found = false;
  781. for ( it = m_CustomTestsIgnore.begin();
  782. it != m_CustomTestsIgnore.end(); ++ it )
  783. {
  784. if ( *it == testname )
  785. {
  786. found = true;
  787. break;
  788. }
  789. }
  790. if ( found )
  791. {
  792. if ( m_Verbose )
  793. {
  794. std::cout << "Ignore test: " << *it << std::endl;
  795. }
  796. continue;
  797. }
  798. }
  799. cmCTestTestProperties test;
  800. test.m_Name = testname;
  801. test.m_Args = args;
  802. test.m_Directory = cmSystemTools::GetCurrentWorkingDirectory();
  803. test.m_IsInBasedOnREOptions = true;
  804. if (this->m_UseIncludeRegExp && !ireg.find(testname.c_str()))
  805. {
  806. test.m_IsInBasedOnREOptions = false;
  807. }
  808. else if (this->m_UseExcludeRegExp &&
  809. !this->m_UseExcludeRegExpFirst &&
  810. ereg.find(testname.c_str()))
  811. {
  812. test.m_IsInBasedOnREOptions = false;
  813. }
  814. testlist->push_back(test);
  815. }
  816. }
  817. }
  818. //----------------------------------------------------------------------
  819. void cmCTestTestHandler::UseIncludeRegExp()
  820. {
  821. this->m_UseIncludeRegExp = true;
  822. }
  823. //----------------------------------------------------------------------
  824. void cmCTestTestHandler::UseExcludeRegExp()
  825. {
  826. this->m_UseExcludeRegExp = true;
  827. this->m_UseExcludeRegExpFirst = this->m_UseIncludeRegExp ? false : true;
  828. }
  829. //----------------------------------------------------------------------
  830. const char* cmCTestTestHandler::GetTestStatus(int status)
  831. {
  832. static const char statuses[][100] = {
  833. "Not Run",
  834. "Timeout",
  835. "SEGFAULT",
  836. "ILLEGAL",
  837. "INTERRUPT",
  838. "NUMERICAL",
  839. "OTHER_FAULT",
  840. "Failed",
  841. "BAD_COMMAND",
  842. "Completed"
  843. };
  844. if ( status < cmCTestTestHandler::NOT_RUN ||
  845. status > cmCTestTestHandler::COMPLETED )
  846. {
  847. return "No Status";
  848. }
  849. return statuses[status];
  850. }
  851. //----------------------------------------------------------------------
  852. void cmCTestTestHandler::ExpandTestsToRunInformation(int numTests)
  853. {
  854. if (this->TestsToRunString.empty())
  855. {
  856. return;
  857. }
  858. int start;
  859. int end = -1;
  860. double stride = -1;
  861. std::string::size_type pos = 0;
  862. std::string::size_type pos2;
  863. // read start
  864. if(GetNextNumber(this->TestsToRunString, start, pos, pos2))
  865. {
  866. // read end
  867. if(GetNextNumber(this->TestsToRunString, end, pos, pos2))
  868. {
  869. // read stride
  870. if(GetNextRealNumber(this->TestsToRunString, stride, pos, pos2))
  871. {
  872. int val =0;
  873. // now read specific numbers
  874. while(GetNextNumber(this->TestsToRunString, val, pos, pos2))
  875. {
  876. m_TestsToRun.push_back(val);
  877. }
  878. m_TestsToRun.push_back(val);
  879. }
  880. }
  881. }
  882. // if start is not specified then we assume we start at 1
  883. if(start == -1)
  884. {
  885. start = 1;
  886. }
  887. // if end isnot specified then we assume we end with the last test
  888. if(end == -1)
  889. {
  890. end = numTests;
  891. }
  892. // if the stride wasn't specified then it defaults to 1
  893. if(stride == -1)
  894. {
  895. stride = 1;
  896. }
  897. // if we have a range then add it
  898. if(end != -1 && start != -1 && stride > 0)
  899. {
  900. int i = 0;
  901. while (i*stride + start <= end)
  902. {
  903. m_TestsToRun.push_back(static_cast<int>(i*stride+start));
  904. ++i;
  905. }
  906. }
  907. // sort the array
  908. std::sort(m_TestsToRun.begin(), m_TestsToRun.end(), std::less<int>());
  909. // remove duplicates
  910. std::vector<int>::iterator new_end =
  911. std::unique(m_TestsToRun.begin(), m_TestsToRun.end());
  912. m_TestsToRun.erase(new_end, m_TestsToRun.end());
  913. }
  914. //----------------------------------------------------------------------
  915. // Just for convenience
  916. #define SPACE_REGEX "[ \t\r\n]"
  917. //----------------------------------------------------------------------
  918. std::string cmCTestTestHandler::GenerateRegressionImages(
  919. const std::string& xml)
  920. {
  921. cmsys::RegularExpression twoattributes(
  922. "<DartMeasurement"
  923. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  924. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  925. SPACE_REGEX "*>([^<]*)</DartMeasurement>");
  926. cmsys::RegularExpression threeattributes(
  927. "<DartMeasurement"
  928. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  929. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  930. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  931. SPACE_REGEX "*>([^<]*)</DartMeasurement>");
  932. cmsys::RegularExpression fourattributes(
  933. "<DartMeasurement"
  934. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  935. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  936. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  937. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  938. SPACE_REGEX "*>([^<]*)</DartMeasurement>");
  939. cmsys::RegularExpression measurementfile(
  940. "<DartMeasurementFile"
  941. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  942. SPACE_REGEX "*(name|type|encoding|compression)=\"([^\"]*)\""
  943. SPACE_REGEX "*>([^<]*)</DartMeasurementFile>");
  944. cmOStringStream ostr;
  945. bool done = false;
  946. std::string cxml = xml;
  947. while ( ! done )
  948. {
  949. if ( twoattributes.find(cxml) )
  950. {
  951. ostr
  952. << "\t\t\t<NamedMeasurement"
  953. << " " << twoattributes.match(1) << "=\"" << twoattributes.match(2) << "\""
  954. << " " << twoattributes.match(3) << "=\"" << twoattributes.match(4) << "\""
  955. << "><Value>" << twoattributes.match(5)
  956. << "</Value></NamedMeasurement>"
  957. << std::endl;
  958. cxml.erase(twoattributes.start(), twoattributes.end() - twoattributes.start());
  959. }
  960. else if ( threeattributes.find(cxml) )
  961. {
  962. ostr
  963. << "\t\t\t<NamedMeasurement"
  964. << " " << threeattributes.match(1) << "=\"" << threeattributes.match(2) << "\""
  965. << " " << threeattributes.match(3) << "=\"" << threeattributes.match(4) << "\""
  966. << " " << threeattributes.match(5) << "=\"" << threeattributes.match(6) << "\""
  967. << "><Value>" << threeattributes.match(7)
  968. << "</Value></NamedMeasurement>"
  969. << std::endl;
  970. cxml.erase(threeattributes.start(), threeattributes.end() - threeattributes.start());
  971. }
  972. else if ( fourattributes.find(cxml) )
  973. {
  974. ostr
  975. << "\t\t\t<NamedMeasurement"
  976. << " " << fourattributes.match(1) << "=\"" << fourattributes.match(2) << "\""
  977. << " " << fourattributes.match(3) << "=\"" << fourattributes.match(4) << "\""
  978. << " " << fourattributes.match(5) << "=\"" << fourattributes.match(6) << "\""
  979. << " " << fourattributes.match(7) << "=\"" << fourattributes.match(8) << "\""
  980. << "><Value>" << fourattributes.match(9)
  981. << "</Value></NamedMeasurement>"
  982. << std::endl;
  983. cxml.erase(fourattributes.start(), fourattributes.end() - fourattributes.start());
  984. }
  985. else if ( measurementfile.find(cxml) )
  986. {
  987. const std::string& filename =
  988. cmCTest::CleanString(measurementfile.match(5));
  989. if ( cmSystemTools::FileExists(filename.c_str()) )
  990. {
  991. long len = cmSystemTools::FileLength(filename.c_str());
  992. if ( len == 0 )
  993. {
  994. std::string k1 = measurementfile.match(1);
  995. std::string v1 = measurementfile.match(2);
  996. std::string k2 = measurementfile.match(3);
  997. std::string v2 = measurementfile.match(4);
  998. if ( cmSystemTools::LowerCase(k1) == "type" )
  999. {
  1000. v1 = "text/string";
  1001. }
  1002. if ( cmSystemTools::LowerCase(k2) == "type" )
  1003. {
  1004. v2 = "text/string";
  1005. }
  1006. ostr
  1007. << "\t\t\t<NamedMeasurement"
  1008. << " " << k1 << "=\"" << v1 << "\""
  1009. << " " << k2 << "=\"" << v2 << "\""
  1010. << " encoding=\"none\""
  1011. << "><Value>Image " << filename.c_str()
  1012. << " is empty</Value></NamedMeasurement>";
  1013. }
  1014. else
  1015. {
  1016. std::ifstream ifs(filename.c_str(), std::ios::in
  1017. #ifdef _WIN32
  1018. | std::ios::binary
  1019. #endif
  1020. );
  1021. unsigned char *file_buffer = new unsigned char [ len + 1 ];
  1022. ifs.read(reinterpret_cast<char*>(file_buffer), len);
  1023. unsigned char *encoded_buffer = new unsigned char [ static_cast<int>(len * 1.5 + 5) ];
  1024. unsigned long rlen = cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1);
  1025. unsigned long cc;
  1026. ostr
  1027. << "\t\t\t<NamedMeasurement"
  1028. << " " << measurementfile.match(1) << "=\"" << measurementfile.match(2) << "\""
  1029. << " " << measurementfile.match(3) << "=\"" << measurementfile.match(4) << "\""
  1030. << " encoding=\"base64\""
  1031. << ">" << std::endl << "\t\t\t\t<Value>";
  1032. for ( cc = 0; cc < rlen; cc ++ )
  1033. {
  1034. ostr << encoded_buffer[cc];
  1035. if ( cc % 60 == 0 && cc )
  1036. {
  1037. ostr << std::endl;
  1038. }
  1039. }
  1040. ostr
  1041. << "</Value>" << std::endl << "\t\t\t</NamedMeasurement>"
  1042. << std::endl;
  1043. delete [] file_buffer;
  1044. delete [] encoded_buffer;
  1045. }
  1046. }
  1047. else
  1048. {
  1049. int idx = 4;
  1050. if ( measurementfile.match(1) == "name" )
  1051. {
  1052. idx = 2;
  1053. }
  1054. ostr
  1055. << "\t\t\t<NamedMeasurement"
  1056. << " name=\"" << measurementfile.match(idx) << "\""
  1057. << " text=\"text/string\""
  1058. << "><Value>File " << filename.c_str() << " not found</Value></NamedMeasurement>"
  1059. << std::endl;
  1060. std::cout << "File \"" << filename.c_str() << "\" not found." << std::endl;
  1061. }
  1062. cxml.erase(measurementfile.start(), measurementfile.end() - measurementfile.start());
  1063. }
  1064. else
  1065. {
  1066. done = true;
  1067. }
  1068. }
  1069. return ostr.str();
  1070. }
  1071. //----------------------------------------------------------------------
  1072. void cmCTestTestHandler::SetIncludeRegExp(const char *arg)
  1073. {
  1074. m_IncludeRegExp = arg;
  1075. }
  1076. //----------------------------------------------------------------------
  1077. void cmCTestTestHandler::SetExcludeRegExp(const char *arg)
  1078. {
  1079. m_ExcludeRegExp = arg;
  1080. }
  1081. //----------------------------------------------------------------------
  1082. void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
  1083. {
  1084. this->TestsToRunString = in;
  1085. // if the argument is a file, then read it and use the contents as the string
  1086. if(cmSystemTools::FileExists(in))
  1087. {
  1088. std::ifstream fin(in);
  1089. unsigned long filelen = cmSystemTools::FileLength(in);
  1090. char* buff = new char[filelen+1];
  1091. fin.getline(buff, filelen);
  1092. buff[fin.gcount()] = 0;
  1093. this->TestsToRunString = buff;
  1094. }
  1095. }
  1096. //----------------------------------------------------------------------
  1097. bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t remove_threshold)
  1098. {
  1099. if ( remove_threshold == 0 )
  1100. {
  1101. return true;
  1102. }
  1103. if ( output.find("CTEST_FULL_OUTPUT") != output.npos )
  1104. {
  1105. return true;
  1106. }
  1107. cmOStringStream ostr;
  1108. std::string::size_type cc;
  1109. std::string::size_type skipsize = 0;
  1110. int inTag = 0;
  1111. int skipped = 0;
  1112. for ( cc = 0; cc < output.size(); cc ++ )
  1113. {
  1114. int ch = output[cc];
  1115. if ( ch < 0 || ch > 255 )
  1116. {
  1117. break;
  1118. }
  1119. if ( ch == '<' )
  1120. {
  1121. inTag = 1;
  1122. }
  1123. if ( !inTag )
  1124. {
  1125. int notskip = 0;
  1126. // Skip
  1127. if ( skipsize < remove_threshold )
  1128. {
  1129. ostr << static_cast<char>(ch);
  1130. notskip = 1;
  1131. }
  1132. skipsize ++;
  1133. if ( notskip && skipsize >= remove_threshold )
  1134. {
  1135. skipped = 1;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. ostr << static_cast<char>(ch);
  1141. }
  1142. if ( ch == '>' )
  1143. {
  1144. inTag = 0;
  1145. }
  1146. }
  1147. if ( skipped )
  1148. {
  1149. ostr << "..." << std::endl << "The rest of the test output was removed since it exceeds the threshold of "
  1150. << remove_threshold << " characters." << std::endl;
  1151. }
  1152. output = ostr.str();
  1153. return true;
  1154. }