ctest.cxx 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  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 "ctest.h"
  14. #include "cmRegularExpression.h"
  15. #include "cmSystemTools.h"
  16. #include <stdio.h>
  17. #include <time.h>
  18. static std::string CleanString(std::string str)
  19. {
  20. std::string::size_type spos = str.find_first_not_of(" \n\t");
  21. std::string::size_type epos = str.find_last_not_of(" \n\t");
  22. if ( spos == str.npos )
  23. {
  24. return std::string();
  25. }
  26. if ( epos != str.npos )
  27. {
  28. epos = epos - spos + 1;
  29. }
  30. return str.substr(spos, epos);
  31. }
  32. static std::string CurrentTime()
  33. {
  34. time_t currenttime = time(0);
  35. return ::CleanString(ctime(&currenttime));
  36. }
  37. static const char* cmCTestErrorMatches[] = {
  38. "^[Bb]us [Ee]rror",
  39. "^[Ss]egmentation [Vv]iolation",
  40. "^[Ss]egmentation [Ff]ault",
  41. "([^ :]+):([0-9]+): ([^ \\t])",
  42. "([^:]+): error[ \\t]*[0-9]+[ \\t]*:",
  43. "^Error ([0-9]+):",
  44. "^Error ",
  45. "^\"[^\"]+\", line [0-9]+: [^Ww]",
  46. "^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
  47. "^ld([^:])*:([ \\t])*ERROR([^:])*:",
  48. "^ild:([ \\t])*\\(undefined symbol\\)",
  49. "([^ :]+) : (error|fatal error|catastrophic error)",
  50. "([^:]+): (Error:|error|undefined reference|multiply defined)",
  51. "([^:]+)\\(([^\\)]+)\\) : (error|fatal error|catastrophic error)",
  52. "^fatal error C[0-9]+:",
  53. ": syntax error ",
  54. "^collect2: ld returned 1 exit status",
  55. "Unsatisfied symbols:",
  56. "Undefined symbols:",
  57. "^Undefined[ \\t]+first referenced",
  58. "^CMake Error:",
  59. ":[ \\t]cannot find",
  60. 0
  61. };
  62. static const char* cmCTestErrorExceptions[] = {
  63. 0
  64. };
  65. static const char* cmCTestWarningMatches[] = {
  66. "([^ :]+):([0-9]+): warning:",
  67. "^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
  68. "^ld([^:])*:([ \\t])*WARNING([^:])*:",
  69. "([^:]+): warning ([0-9]+):",
  70. "^\"[^\"]+\", line [0-9]+: [Ww]arning",
  71. "([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
  72. "^Warning ([0-9]+):",
  73. "^Warning ",
  74. "([^ :]+) : warning",
  75. "([^:]+): warning",
  76. 0
  77. };
  78. static const char* cmCTestWarningExceptions[] = {
  79. "/usr/openwin/include/X11/Xlib\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  80. "/usr/openwin/include/X11/Xutil\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  81. "/usr/openwin/include/X11/XResource\\.h:[0-9]+: warning: ANSI C\\+\\+ forbids declaration",
  82. "WARNING 84 :",
  83. "WARNING 47 :",
  84. "makefile:",
  85. "Makefile:",
  86. "warning: Clock skew detected. Your build may be incomplete.",
  87. "/usr/openwin/include/GL/[^:]+:",
  88. "bind_at_load",
  89. "XrmQGetResource",
  90. "IceFlush",
  91. "warning LNK4089: all references to .GDI32.dll. discarded by .OPT:REF",
  92. "warning LNK4089: all references to .USER32.dll. discarded by .OPT:REF",
  93. "ld32: WARNING 85: definition of dataKey in",
  94. 0
  95. };
  96. std::string ctest::MakeXMLSafe(const std::string& str)
  97. {
  98. std::string::size_type pos = 0;
  99. cmOStringStream ost;
  100. char buffer[10];
  101. for ( pos = 0; pos < str.size(); pos ++ )
  102. {
  103. char ch = str[pos];
  104. if ( ch > 126 )
  105. {
  106. sprintf(buffer, "&%x", (int)ch);
  107. ost << buffer;
  108. }
  109. else
  110. {
  111. switch ( ch )
  112. {
  113. case '&': ost << "&amp;"; break;
  114. case '<': ost << "&lt;"; break;
  115. case '>': ost << "&gt;"; break;
  116. default: ost << ch;
  117. }
  118. }
  119. }
  120. return ost.str();
  121. }
  122. bool TryExecutable(const char *dir, const char *file,
  123. std::string *fullPath, const char *subdir)
  124. {
  125. // try current directory
  126. std::string tryPath;
  127. if (dir && strcmp(dir,""))
  128. {
  129. tryPath = dir;
  130. tryPath += "/";
  131. }
  132. if (subdir && strcmp(subdir,""))
  133. {
  134. tryPath += subdir;
  135. tryPath += "/";
  136. }
  137. tryPath += file;
  138. if(cmSystemTools::FileExists(tryPath.c_str()))
  139. {
  140. *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
  141. return true;
  142. }
  143. tryPath += cmSystemTools::GetExecutableExtension();
  144. if(cmSystemTools::FileExists(tryPath.c_str()))
  145. {
  146. *fullPath = cmSystemTools::CollapseFullPath(tryPath.c_str());
  147. return true;
  148. }
  149. return false;
  150. }
  151. ctest::ctest()
  152. {
  153. m_UseIncludeRegExp = false;
  154. m_UseExcludeRegExp = false;
  155. m_UseExcludeRegExpFirst = false;
  156. m_Verbose = false;
  157. m_DartMode = false;
  158. int cc;
  159. for ( cc=0; cc < ctest::LAST_TEST; cc ++ )
  160. {
  161. m_Tests[cc] = 0;
  162. }
  163. }
  164. void ctest::Initialize()
  165. {
  166. m_ToplevelPath = cmSystemTools::GetCurrentWorkingDirectory();
  167. // parse the dart test file
  168. std::ifstream fin("DartConfiguration.tcl");
  169. if(!fin)
  170. {
  171. return;
  172. }
  173. char buffer[1024];
  174. while ( fin )
  175. {
  176. buffer[0] = 0;
  177. fin.getline(buffer, 1023);
  178. buffer[1023] = 0;
  179. std::string line = ::CleanString(buffer);
  180. while ( fin && (line[line.size()-1] == '\\') )
  181. {
  182. line = line.substr(0, line.size()-1);
  183. buffer[0] = 0;
  184. fin.getline(buffer, 1023);
  185. buffer[1023] = 0;
  186. line += ::CleanString(buffer);
  187. }
  188. if ( line[0] == '#' )
  189. {
  190. continue;
  191. }
  192. if ( line.size() == 0 )
  193. {
  194. continue;
  195. }
  196. std::string::size_type cpos = line.find_first_of(":");
  197. if ( cpos == line.npos )
  198. {
  199. continue;
  200. }
  201. std::string key = line.substr(0, cpos);
  202. std::string value = ::CleanString(line.substr(cpos+1, line.npos));
  203. m_DartConfiguration[key] = value;
  204. }
  205. fin.close();
  206. if ( m_DartMode )
  207. {
  208. std::string testingDir = m_ToplevelPath + "/Testing/CDart";
  209. if ( cmSystemTools::FileExists(testingDir.c_str()) )
  210. {
  211. if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
  212. {
  213. std::cerr << "File " << testingDir << " is in the place of the testing directory"
  214. << std::endl;
  215. return;
  216. }
  217. }
  218. else
  219. {
  220. if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
  221. {
  222. std::cerr << "Cannot create directory " << testingDir
  223. << std::endl;
  224. return;
  225. }
  226. }
  227. std::string tagfile = testingDir + "/TAG";
  228. std::ifstream tfin(tagfile.c_str());
  229. std::string tag;
  230. time_t tctime = time(0);
  231. struct tm *lctime = gmtime(&tctime);
  232. if ( tfin )
  233. {
  234. tfin >> tag;
  235. tfin.close();
  236. int year = 0;
  237. int mon = 0;
  238. int day = 0;
  239. int hour = 0;
  240. int min = 0;
  241. sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d",
  242. &year, &mon, &day, &hour, &min);
  243. if ( year != lctime->tm_year + 1900 ||
  244. mon != lctime->tm_mon ||
  245. day != lctime->tm_mday )
  246. {
  247. tag = "";
  248. }
  249. }
  250. if ( tag.size() == 0 )
  251. {
  252. char datestring[100];
  253. sprintf(datestring, "%04d%02d%02d-%02d%02d",
  254. lctime->tm_year + 1900,
  255. lctime->tm_mon,
  256. lctime->tm_mday,
  257. lctime->tm_hour,
  258. lctime->tm_min);
  259. tag = datestring;
  260. std::ofstream ofs(tagfile.c_str());
  261. if ( ofs )
  262. {
  263. ofs << tag << std::endl;
  264. }
  265. ofs.close();
  266. std::cout << "Create new tag: " << tag << std::endl;
  267. }
  268. m_CurrentTag = tag;
  269. }
  270. }
  271. bool ctest::SetTest(const char* ttype)
  272. {
  273. if ( cmSystemTools::LowerCase(ttype) == "all" )
  274. {
  275. m_Tests[ctest::ALL_TEST] = 1;
  276. }
  277. else if ( cmSystemTools::LowerCase(ttype) == "update" )
  278. {
  279. m_Tests[ctest::UPDATE_TEST] = 1;
  280. }
  281. else if ( cmSystemTools::LowerCase(ttype) == "configure" )
  282. {
  283. m_Tests[ctest::CONFIGURE_TEST] = 1;
  284. }
  285. else if ( cmSystemTools::LowerCase(ttype) == "build" )
  286. {
  287. m_Tests[ctest::BUILD_TEST] = 1;
  288. }
  289. else if ( cmSystemTools::LowerCase(ttype) == "test" )
  290. {
  291. m_Tests[ctest::TEST_TEST] = 1;
  292. }
  293. else if ( cmSystemTools::LowerCase(ttype) == "coverage" )
  294. {
  295. m_Tests[ctest::COVERAGE_TEST] = 1;
  296. }
  297. else if ( cmSystemTools::LowerCase(ttype) == "purify" )
  298. {
  299. m_Tests[ctest::PURIFY_TEST] = 1;
  300. }
  301. else
  302. {
  303. std::cerr << "Don't know about test \"" << ttype << "\" yet..." << std::endl;
  304. return false;
  305. }
  306. return true;
  307. }
  308. void ctest::Finalize()
  309. {
  310. }
  311. std::string ctest::FindExecutable(const char *exe)
  312. {
  313. std::string fullPath = "";
  314. std::string dir;
  315. std::string file;
  316. cmSystemTools::SplitProgramPath(exe, dir, file);
  317. if(m_ConfigType != "")
  318. {
  319. if(TryExecutable(dir.c_str(), file.c_str(), &fullPath, m_ConfigType.c_str()))
  320. {
  321. return fullPath;
  322. }
  323. dir += "/";
  324. dir += m_ConfigType;
  325. dir += "/";
  326. dir += file;
  327. cmSystemTools::Error("config type specified on the command line, but test executable not found.",
  328. dir.c_str());
  329. return "";
  330. }
  331. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,"."))
  332. {
  333. return fullPath;
  334. }
  335. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,""))
  336. {
  337. return fullPath;
  338. }
  339. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Release"))
  340. {
  341. return fullPath;
  342. }
  343. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,"Debug"))
  344. {
  345. return fullPath;
  346. }
  347. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,"MinSizeRel"))
  348. {
  349. return fullPath;
  350. }
  351. if (TryExecutable(dir.c_str(),file.c_str(),&fullPath,"RelWithDebInfo"))
  352. {
  353. return fullPath;
  354. }
  355. // if everything else failed, check the users path
  356. if (dir != "")
  357. {
  358. std::string path = cmSystemTools::FindProgram(file.c_str());
  359. if (path != "")
  360. {
  361. return path;
  362. }
  363. }
  364. return fullPath;
  365. }
  366. int ctest::UpdateDirectory()
  367. {
  368. std::string cvsCommand = m_DartConfiguration["CVSCommand"];
  369. if ( cvsCommand.size() == 0 )
  370. {
  371. std::cerr << "Cannot find CVSCommand key in the DartConfiguration.tcl" << std::endl;
  372. return 1;
  373. }
  374. std::string cvsOptions = m_DartConfiguration["CVSUpdateOptions"];
  375. if ( cvsOptions.size() == 0 )
  376. {
  377. std::cerr << "Cannot find CVSUpdateOptions key in the DartConfiguration.tcl" << std::endl;
  378. return 1;
  379. }
  380. std::string sourceDirectory = m_DartConfiguration["SourceDirectory"];
  381. if ( sourceDirectory.size() == 0 )
  382. {
  383. std::cerr << "Cannot find SourceDirectory key in the DartConfiguration.tcl" << std::endl;
  384. return 1;
  385. }
  386. std::string command = cvsCommand + " update " + cvsOptions;
  387. std::string output;
  388. int retVal;
  389. bool res = cmSystemTools::RunCommand(command.c_str(), output,
  390. retVal, sourceDirectory.c_str(),
  391. m_Verbose);
  392. if (! res || retVal )
  393. {
  394. std::cerr << "Error(s) when updating the project" << std::endl;
  395. return 1;
  396. }
  397. return 0;
  398. }
  399. int ctest::ConfigureDirectory()
  400. {
  401. std::string cCommand = m_DartConfiguration["ConfigureCommand"];
  402. if ( cCommand.size() == 0 )
  403. {
  404. std::cerr << "Cannot find ConfigureCommand key in the DartConfiguration.tcl" << std::endl;
  405. return 1;
  406. }
  407. std::string buildDirectory = m_DartConfiguration["BuildDirectory"];
  408. if ( buildDirectory.size() == 0 )
  409. {
  410. std::cerr << "Cannot find BuildDirectory key in the DartConfiguration.tcl" << std::endl;
  411. return 1;
  412. }
  413. std::string output;
  414. int retVal;
  415. bool res = cmSystemTools::RunCommand(cCommand.c_str(), output,
  416. retVal, buildDirectory.c_str(),
  417. m_Verbose);
  418. if (! res || retVal )
  419. {
  420. std::cerr << "Error(s) when updating the project" << std::endl;
  421. return 1;
  422. }
  423. return 0;
  424. }
  425. int ctest::BuildDirectory()
  426. {
  427. std::string makeCommand = m_DartConfiguration["MakeCommand"];
  428. if ( makeCommand.size() == 0 )
  429. {
  430. std::cerr << "Cannot find MakeCommand key in the DartConfiguration.tcl" << std::endl;
  431. return 1;
  432. }
  433. std::string buildDirectory = m_DartConfiguration["BuildDirectory"];
  434. if ( buildDirectory.size() == 0 )
  435. {
  436. std::cerr << "Cannot find BuildDirectory key in the DartConfiguration.tcl" << std::endl;
  437. return 1;
  438. }
  439. m_StartBuild = ::CurrentTime();
  440. std::string output;
  441. int retVal;
  442. bool res = cmSystemTools::RunCommand(makeCommand.c_str(), output,
  443. retVal, buildDirectory.c_str(),
  444. m_Verbose);
  445. m_EndBuild = ::CurrentTime();
  446. if (! res || retVal )
  447. {
  448. std::cerr << "Error(s) when building project" << std::endl;
  449. }
  450. // Parsing of output for errors and warnings.
  451. std::vector<cmStdString> lines;
  452. cmSystemTools::Split(output.c_str(), lines);
  453. std::ofstream ofs;
  454. if ( this->OpenFile("Temporary", "LastBuild.log", ofs) )
  455. {
  456. ofs << output;
  457. ofs.close();
  458. }
  459. else
  460. {
  461. std::cerr << "Cannot create LastBuild.log file" << std::endl;
  462. }
  463. // Lines are marked:
  464. // 0 - nothing
  465. // 1 - error
  466. // > 1 - warning
  467. std::vector<int> markedLines(lines.size(), 0);
  468. int cc;
  469. // Errors
  470. for ( cc = 0; cmCTestErrorMatches[cc]; cc ++ )
  471. {
  472. cmRegularExpression re(cmCTestErrorMatches[cc]);
  473. std::vector<std::string>::size_type kk;
  474. for ( kk = 0; kk < lines.size(); kk ++ )
  475. {
  476. if ( re.find(lines[kk]) )
  477. {
  478. markedLines[kk] = 1;
  479. }
  480. }
  481. }
  482. // Warnings
  483. for ( cc = 0; cmCTestWarningMatches[cc]; cc ++ )
  484. {
  485. cmRegularExpression re(cmCTestWarningMatches[cc]);
  486. std::vector<std::string>::size_type kk;
  487. for ( kk = 0; kk < lines.size(); kk ++ )
  488. {
  489. if ( re.find(lines[kk]) )
  490. {
  491. markedLines[kk] += 2;
  492. }
  493. }
  494. }
  495. // Errors exceptions
  496. for ( cc = 0; cmCTestErrorExceptions[cc]; cc ++ )
  497. {
  498. cmRegularExpression re(cmCTestErrorExceptions[cc]);
  499. std::vector<int>::size_type kk;
  500. for ( kk =0; kk < markedLines.size(); kk ++ )
  501. {
  502. if ( markedLines[cc] == 1 )
  503. {
  504. if ( re.find(lines[kk]) )
  505. {
  506. markedLines[cc] = 0;
  507. }
  508. }
  509. }
  510. }
  511. // Warning exceptions
  512. for ( cc = 0; cmCTestWarningExceptions[cc]; cc ++ )
  513. {
  514. cmRegularExpression re(cmCTestWarningExceptions[cc]);
  515. std::vector<int>::size_type kk;
  516. for ( kk =0; kk < markedLines.size(); kk ++ )
  517. {
  518. if ( markedLines[cc] > 1 )
  519. {
  520. if ( re.find(lines[kk]) )
  521. {
  522. markedLines[cc] = 0;
  523. }
  524. }
  525. }
  526. }
  527. std::vector<cmCTestBuildErrorWarning> errorsWarnings;
  528. std::vector<int>::size_type kk;
  529. cmCTestBuildErrorWarning errorwarning;
  530. for ( kk =0; kk < markedLines.size(); kk ++ )
  531. {
  532. errorwarning.m_LineNumber = -1;
  533. bool found = false;
  534. if ( markedLines[kk] == 1 )
  535. {
  536. std::cout << "Error: " << lines[kk] << std::endl;
  537. errorwarning.m_Error = true;
  538. found = true;
  539. }
  540. else if ( markedLines[kk] > 1 )
  541. {
  542. std::cout << "Warning: " << lines[kk] << std::endl;
  543. errorwarning.m_Error = false;
  544. found = true;
  545. }
  546. if ( found )
  547. {
  548. errorwarning.m_LogLine = static_cast<int>(kk+1);
  549. errorwarning.m_Text = lines[kk];
  550. errorwarning.m_PreContext = "";
  551. errorwarning.m_PostContext = "";
  552. std::vector<int>::size_type jj;
  553. std::vector<int>::size_type ll = 0;
  554. if ( kk > 6 )
  555. {
  556. ll = kk - 6;
  557. }
  558. for ( jj = kk;
  559. jj > 0 && jj > ll /* && markedLines[jj] == 0 */;
  560. jj -- );
  561. for (; jj < kk; jj ++ )
  562. {
  563. errorwarning.m_PreContext += lines[jj] + "\n";
  564. }
  565. for ( jj = kk+1;
  566. jj < lines.size() && jj < kk + 7 /* && markedLines[jj] == 0*/;
  567. jj ++ )
  568. {
  569. errorwarning.m_PostContext += lines[jj] + "\n";
  570. }
  571. errorsWarnings.push_back(errorwarning);
  572. }
  573. }
  574. if( !this->OpenFile("", "Build.xml", ofs) )
  575. {
  576. std::cerr << "Cannot create build XML file" << std::endl;
  577. return 1;
  578. }
  579. this->GenerateDartBuildOutput(ofs, errorsWarnings);
  580. return 0;
  581. }
  582. bool ctest::OpenFile(const std::string& path,
  583. const std::string& name, std::ofstream& stream)
  584. {
  585. std::string testingDir = m_ToplevelPath + "/Testing/CDart";
  586. if ( path.size() > 0 )
  587. {
  588. testingDir += "/" + path;
  589. }
  590. if ( cmSystemTools::FileExists(testingDir.c_str()) )
  591. {
  592. if ( !cmSystemTools::FileIsDirectory(testingDir.c_str()) )
  593. {
  594. std::cerr << "File " << testingDir
  595. << " is in the place of the testing directory"
  596. << std::endl;
  597. return false;
  598. }
  599. }
  600. else
  601. {
  602. if ( !cmSystemTools::MakeDirectory(testingDir.c_str()) )
  603. {
  604. std::cerr << "Cannot create directory " << testingDir
  605. << std::endl;
  606. return false;
  607. }
  608. }
  609. std::string filename = testingDir + "/" + name;
  610. stream.open(filename.c_str());
  611. if( !stream )
  612. {
  613. return false;
  614. }
  615. return true;
  616. }
  617. void ctest::GenerateDartBuildOutput(std::ostream& os,
  618. std::vector<cmCTestBuildErrorWarning> ew)
  619. {
  620. os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  621. << "<Site BuildName=\"" << m_DartConfiguration["BuildName"]
  622. << "\" BuildStamp=\"" << m_CurrentTag << "-Experimental\" Name=\""
  623. << m_DartConfiguration["Site"] << "\">\n"
  624. << "<Build>\n"
  625. << "\t<StartDateTime>" << m_StartBuild << "</StartDateTime>\n"
  626. << "<BuildCommand>"
  627. << this->MakeXMLSafe(m_DartConfiguration["MakeCommand"])
  628. << "</BuildCommand>" << std::endl;
  629. std::vector<cmCTestBuildErrorWarning>::iterator it;
  630. for ( it = ew.begin(); it != ew.end(); it++ )
  631. {
  632. cmCTestBuildErrorWarning *cm = &(*it);
  633. os << "\t<" << (cm->m_Error ? "Error" : "Warning") << ">\n"
  634. << "\t\t<BuildLogLine>" << cm->m_LogLine << "</BuildLogLine>\n"
  635. << "\t\t<Text>" << this->MakeXMLSafe(cm->m_Text)
  636. << "\n</Text>" << std::endl;
  637. if ( cm->m_SourceFile.size() > 0 )
  638. {
  639. os << "\t\t<SourceFile>" << cm->m_SourceFile << "</SourceFile>"
  640. << std::endl;
  641. }
  642. if ( cm->m_SourceFileTail.size() > 0 )
  643. {
  644. os << "\t\t<SourceFileTail>" << cm->m_SourceFileTail
  645. << "</SourceFileTail>" << std::endl;
  646. }
  647. if ( cm->m_LineNumber >= 0 )
  648. {
  649. os << "\t\t<SourceLineNumber>" << cm->m_LineNumber
  650. << "</SourceLineNumber>" << std::endl;
  651. }
  652. os << "\t\t<PreContext>" << this->MakeXMLSafe(cm->m_PreContext)
  653. << "</PreContext>\n"
  654. << "\t\t<PostContext>" << this->MakeXMLSafe(cm->m_PostContext)
  655. << "</PostContext>\n"
  656. << "\t\t<RepeatCount>0</RepeatCount>\n"
  657. << "</" << (cm->m_Error ? "Error" : "Warning") << ">\n\n"
  658. << std::endl;
  659. }
  660. os << "\t<Log Encoding=\"base64\" Compression=\"/bin/gzip\">\n\t</Log>\n"
  661. << "\t<EndDateTime>" << m_EndBuild << "</EndDateTime>\n"
  662. << "</Build>\n"
  663. << "</Site>" << std::endl;
  664. }
  665. void ctest::ProcessDirectory(std::vector<std::string> &passed,
  666. std::vector<std::string> &failed)
  667. {
  668. // does the DartTestfile.txt exist ?
  669. if(!cmSystemTools::FileExists("DartTestfile.txt"))
  670. {
  671. return;
  672. }
  673. // parse the file
  674. std::ifstream fin("DartTestfile.txt");
  675. if(!fin)
  676. {
  677. return;
  678. }
  679. int firstTest = 1;
  680. std::string name;
  681. std::vector<std::string> args;
  682. cmRegularExpression ireg(this->m_IncludeRegExp.c_str());
  683. cmRegularExpression ereg(this->m_ExcludeRegExp.c_str());
  684. cmRegularExpression dartStuff("([\t\n ]*<DartMeasurement.*/DartMeasurement[a-zA-Z]*>[\t ]*[\n]*)");
  685. bool parseError;
  686. while ( fin )
  687. {
  688. if(cmSystemTools::ParseFunction(fin, name, args, "DartTestfile.txt",
  689. parseError))
  690. {
  691. if (name == "SUBDIRS")
  692. {
  693. std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
  694. for(std::vector<std::string>::iterator j = args.begin();
  695. j != args.end(); ++j)
  696. {
  697. std::string nwd = cwd + "/";
  698. nwd += *j;
  699. if (cmSystemTools::FileIsDirectory(nwd.c_str()))
  700. {
  701. cmSystemTools::ChangeDirectory(nwd.c_str());
  702. this->ProcessDirectory(passed, failed);
  703. }
  704. }
  705. // return to the original directory
  706. cmSystemTools::ChangeDirectory(cwd.c_str());
  707. }
  708. if (name == "ADD_TEST")
  709. {
  710. if (this->m_UseExcludeRegExp &&
  711. this->m_UseExcludeRegExpFirst &&
  712. ereg.find(args[0].c_str()))
  713. {
  714. continue;
  715. }
  716. if (this->m_UseIncludeRegExp && !ireg.find(args[0].c_str()))
  717. {
  718. continue;
  719. }
  720. if (this->m_UseExcludeRegExp &&
  721. !this->m_UseExcludeRegExpFirst &&
  722. ereg.find(args[0].c_str()))
  723. {
  724. continue;
  725. }
  726. cmCTestTestResult cres;
  727. if (firstTest)
  728. {
  729. std::string nwd = cmSystemTools::GetCurrentWorkingDirectory();
  730. std::cerr << "Changing directory into " << nwd.c_str() << "\n";
  731. firstTest = 0;
  732. }
  733. cres.m_Name = args[0];
  734. fprintf(stderr,"Testing %-30s ",args[0].c_str());
  735. fflush(stderr);
  736. //std::cerr << "Testing " << args[0] << " ... ";
  737. // find the test executable
  738. std::string testCommand =
  739. cmSystemTools::EscapeSpaces(this->FindExecutable(args[1].c_str()).c_str());
  740. // continue if we did not find the executable
  741. if (testCommand == "")
  742. {
  743. std::cerr << "Unable to find executable: " <<
  744. args[1].c_str() << "\n";
  745. continue;
  746. }
  747. testCommand = cmSystemTools::ConvertToOutputPath(testCommand.c_str());
  748. // add the arguments
  749. std::vector<std::string>::iterator j = args.begin();
  750. ++j;
  751. ++j;
  752. for(;j != args.end(); ++j)
  753. {
  754. testCommand += " ";
  755. testCommand += cmSystemTools::EscapeSpaces(j->c_str());
  756. }
  757. /**
  758. * Run an executable command and put the stdout in output.
  759. */
  760. std::string output;
  761. int retVal;
  762. double clock_start, clock_finish;
  763. clock_start = cmSystemTools::GetTime();
  764. if ( m_Verbose )
  765. {
  766. std::cout << std::endl << "Test command: " << testCommand << std::endl;
  767. }
  768. bool res = cmSystemTools::RunCommand(testCommand.c_str(), output,
  769. retVal, 0, false);
  770. clock_finish = cmSystemTools::GetTime();
  771. cres.m_ExecutionTime = (double)(clock_finish - clock_start);
  772. cres.m_FullCommandLine = testCommand;
  773. if (!res || retVal != 0)
  774. {
  775. fprintf(stderr,"***Failed\n");
  776. if (output != "")
  777. {
  778. if (dartStuff.find(output.c_str()))
  779. {
  780. cmSystemTools::ReplaceString(output,
  781. dartStuff.match(1).c_str(),"");
  782. }
  783. if (output != "" && m_Verbose)
  784. {
  785. std::cerr << output.c_str() << "\n";
  786. }
  787. }
  788. failed.push_back(args[0]);
  789. }
  790. else
  791. {
  792. fprintf(stderr," Passed\n");
  793. if (output != "")
  794. {
  795. if (dartStuff.find(output.c_str()))
  796. {
  797. cmSystemTools::ReplaceString(output,
  798. dartStuff.match(1).c_str(),"");
  799. }
  800. if (output != "" && m_Verbose)
  801. {
  802. std::cerr << output.c_str() << "\n";
  803. }
  804. }
  805. passed.push_back(args[0]);
  806. }
  807. cres.m_Output = output;
  808. cres.m_ReturnValue = retVal;
  809. std::string nwd = cmSystemTools::GetCurrentWorkingDirectory();
  810. if ( nwd.size() > m_ToplevelPath.size() )
  811. {
  812. nwd = "." + nwd.substr(m_ToplevelPath.size(), nwd.npos);
  813. }
  814. cres.m_Path = nwd;
  815. cres.m_CompletionStatus = "Completed";
  816. m_TestResults.push_back( cres );
  817. }
  818. }
  819. }
  820. }
  821. int ctest::TestDirectory()
  822. {
  823. std::vector<std::string> passed;
  824. std::vector<std::string> failed;
  825. int total;
  826. m_StartTest = ::CurrentTime();
  827. this->ProcessDirectory(passed, failed);
  828. m_EndTest = ::CurrentTime();
  829. total = int(passed.size()) + int(failed.size());
  830. if (total == 0)
  831. {
  832. std::cerr << "No tests were found!!!\n";
  833. }
  834. else
  835. {
  836. if (passed.size() && (m_UseIncludeRegExp || m_UseExcludeRegExp))
  837. {
  838. std::cerr << "\nThe following tests passed:\n";
  839. for(std::vector<std::string>::iterator j = passed.begin();
  840. j != passed.end(); ++j)
  841. {
  842. std::cerr << "\t" << *j << "\n";
  843. }
  844. }
  845. float percent = float(passed.size()) * 100.0f / total;
  846. fprintf(stderr,"\n%.0f%% tests passed, %i tests failed out of %i\n",
  847. percent, int(failed.size()), total);
  848. if (failed.size())
  849. {
  850. std::cerr << "\nThe following tests FAILED:\n";
  851. for(std::vector<std::string>::iterator j = failed.begin();
  852. j != failed.end(); ++j)
  853. {
  854. std::cerr << "\t" << *j << "\n";
  855. }
  856. }
  857. }
  858. if ( m_DartMode )
  859. {
  860. std::ofstream ofs;
  861. if( !this->OpenFile("", "Test.xml", ofs) )
  862. {
  863. std::cerr << "Cannot create testing XML file" << std::endl;
  864. return 1;
  865. }
  866. this->GenerateDartOutput(ofs);
  867. }
  868. return int(failed.size());
  869. }
  870. void ctest::GenerateDartOutput(std::ostream& os)
  871. {
  872. if ( !m_DartMode )
  873. {
  874. return;
  875. }
  876. if ( m_TestResults.size() == 0 )
  877. {
  878. return;
  879. }
  880. os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  881. << "<Site BuildName=\"" << m_DartConfiguration["BuildName"]
  882. << "\" BuildStamp=\"" << m_CurrentTag << "-Experimental\" Name=\""
  883. << m_DartConfiguration["Site"] << "\">\n"
  884. << "<Testing>\n"
  885. << "\t<StartDateTime>" << m_StartTest << "</StartDateTime>\n"
  886. << "\t<TestList>\n";
  887. tm_TestResultsVector::size_type cc;
  888. for ( cc = 0; cc < m_TestResults.size(); cc ++ )
  889. {
  890. cmCTestTestResult *result = &m_TestResults[cc];
  891. os << "\t\t<Test>" << this->MakeXMLSafe(result->m_Path)
  892. << "/" << this->MakeXMLSafe(result->m_Name)
  893. << "</Test>" << std::endl;
  894. }
  895. os << "\t</TestList>\n";
  896. for ( cc = 0; cc < m_TestResults.size(); cc ++ )
  897. {
  898. cmCTestTestResult *result = &m_TestResults[cc];
  899. os << "\t<Test Status=\"" << (result->m_ReturnValue?"failed":"passed")
  900. << "\">\n"
  901. << "\t\t<Name>" << this->MakeXMLSafe(result->m_Name) << "</Name>\n"
  902. << "\t\t<Path>" << this->MakeXMLSafe(result->m_Path) << "</Path>\n"
  903. << "\t\t<FullName>" << this->MakeXMLSafe(result->m_Path)
  904. << "/" << this->MakeXMLSafe(result->m_Name) << "</FullName>\n"
  905. << "\t\t<FullCommandLine>"
  906. << this->MakeXMLSafe(result->m_FullCommandLine)
  907. << "</FullCommandLine>\n"
  908. << "\t\t<Results>" << std::endl;
  909. if ( result->m_ReturnValue )
  910. {
  911. os << "\t\t\t<NamedMeasurement type=\"text/string\" name=\"Exit Code\"><Value>"
  912. << "CHILDSTATUS" << "</Value></NamedMeasurement>\n"
  913. << "\t\t\t<NamedMeasurement type=\"text/string\" name=\"Exit Value\"><Value>"
  914. << result->m_ReturnValue << "</Value></NamedMeasurement>" << std::endl;
  915. }
  916. os << "\t\t\t<NamedMeasurement type=\"numeric/double\" "
  917. << "name=\"Execution Time\"><Value>"
  918. << result->m_ExecutionTime << "</Value></NamedMeasurement>\n"
  919. << "\t\t\t<NamedMeasurement type=\"text/string\" "
  920. << "name=\"Completion Status\"><Value>"
  921. << result->m_CompletionStatus << "</Value></NamedMeasurement>\n"
  922. << "\t\t\t<Measurement>\n"
  923. << "\t\t\t\t<Value>" << this->MakeXMLSafe(result->m_Output)
  924. << "</Value>\n"
  925. << "\t\t\t</Measurement>\n"
  926. << "\t\t</Results>\n"
  927. << "\t</Test>" << std::endl;
  928. }
  929. os << "\t<EndDateTime>" << m_EndTest << "</EndDateTime>\n"
  930. << "</Testing>\n"
  931. << "</Site>" << std::endl;
  932. }
  933. int ctest::ProcessTests()
  934. {
  935. int res = 0;
  936. bool notest = true;
  937. int cc;
  938. for ( cc = 0; cc < LAST_TEST; cc ++ )
  939. {
  940. if ( m_Tests[cc] )
  941. {
  942. notest = false;
  943. break;
  944. }
  945. }
  946. if ( m_Tests[UPDATE_TEST] || m_Tests[ALL_TEST] )
  947. {
  948. this->UpdateDirectory();
  949. }
  950. if ( m_Tests[CONFIGURE_TEST] || m_Tests[ALL_TEST] )
  951. {
  952. this->ConfigureDirectory();
  953. }
  954. if ( m_Tests[BUILD_TEST] || m_Tests[ALL_TEST] )
  955. {
  956. this->BuildDirectory();
  957. }
  958. if ( m_Tests[TEST_TEST] || m_Tests[ALL_TEST] || notest )
  959. {
  960. res += this->TestDirectory();
  961. }
  962. if ( m_Tests[COVERAGE_TEST] || m_Tests[ALL_TEST] )
  963. {
  964. std::cerr << "Coverage test is not yet implemented" << std::endl;
  965. }
  966. if ( m_Tests[PURIFY_TEST] || m_Tests[ALL_TEST] )
  967. {
  968. std::cerr << "Purify test is not yet implemented" << std::endl;
  969. }
  970. return res;
  971. }
  972. // this is a test driver program for cmake.
  973. int main (int argc, char *argv[])
  974. {
  975. ctest inst;
  976. // look at the args
  977. std::vector<std::string> args;
  978. for(int i =0; i < argc; ++i)
  979. {
  980. args.push_back(argv[i]);
  981. }
  982. #ifdef _WIN32
  983. std::string comspec = "cmw9xcom.exe";
  984. cmSystemTools::SetWindows9xComspecSubstitute(comspec.c_str());
  985. #endif
  986. for(unsigned int i=1; i < args.size(); ++i)
  987. {
  988. std::string arg = args[i];
  989. if(arg.find("-D",0) == 0 && i < args.size() - 1)
  990. {
  991. inst.m_ConfigType = args[i+1];
  992. }
  993. if( arg.find("-V",0) == 0 || arg.find("--verbose",0) == 0 )
  994. {
  995. inst.m_Verbose = true;
  996. }
  997. if( ( arg.find("-T",0) == 0 || arg.find("--dart-mode",0) == 0 ) && (i < args.size() -1) )
  998. {
  999. inst.m_DartMode = true;
  1000. inst.SetTest(args[i+1].c_str());
  1001. }
  1002. if(arg.find("-R",0) == 0 && i < args.size() - 1)
  1003. {
  1004. inst.m_UseIncludeRegExp = true;
  1005. inst.m_IncludeRegExp = args[i+1];
  1006. }
  1007. if(arg.find("-E",0) == 0 && i < args.size() - 1)
  1008. {
  1009. inst.m_UseExcludeRegExp = true;
  1010. inst.m_ExcludeRegExp = args[i+1];
  1011. inst.m_UseExcludeRegExpFirst = inst.m_UseIncludeRegExp ? false : true;
  1012. }
  1013. if(arg.find("-h") == 0 ||
  1014. arg.find("-help") == 0 ||
  1015. arg.find("-H") == 0 ||
  1016. arg.find("--help") == 0 ||
  1017. arg.find("/H") == 0 ||
  1018. arg.find("/HELP") == 0 ||
  1019. arg.find("/?") == 0)
  1020. {
  1021. std::cerr << "Usage: " << argv[0] << " <options>" << std::endl
  1022. << "\t -D type Specify config type" << std::endl
  1023. << "\t -E test Specify regular expression for tests to exclude"
  1024. << std::endl
  1025. << "\t -R test Specify regular expression for tests to include"
  1026. << std::endl
  1027. << "\t -V Verbose testing" << std::endl
  1028. << "\t -H Help page" << std::endl;
  1029. return 1;
  1030. }
  1031. }
  1032. // call process directory
  1033. inst.Initialize();
  1034. int res = inst.ProcessTests();
  1035. inst.Finalize();
  1036. return res;
  1037. }