cmCTestCoverageHandler.cxx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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 "cmCTestCoverageHandler.h"
  14. #include "cmCTest.h"
  15. #include "cmake.h"
  16. #include "cmSystemTools.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmGlob.h"
  19. #include <cmsys/Process.h>
  20. #include <cmsys/RegularExpression.hxx>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #include <float.h>
  24. #define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
  25. //----------------------------------------------------------------------
  26. cmCTestCoverageHandler::cmCTestCoverageHandler()
  27. {
  28. }
  29. //----------------------------------------------------------------------
  30. void cmCTestCoverageHandler::Initialize()
  31. {
  32. this->Superclass::Initialize();
  33. m_CustomCoverageExclude.empty();
  34. }
  35. //----------------------------------------------------------------------
  36. bool cmCTestCoverageHandler::StartCoverageLogFile(cmGeneratedFileStream& covLogFile, int logFileCount)
  37. {
  38. char covLogFilename[1024];
  39. sprintf(covLogFilename, "CoverageLog-%d", logFileCount);
  40. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Open file: " << covLogFilename << std::endl);
  41. if (!this->StartResultingXML(covLogFilename, covLogFile) )
  42. {
  43. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot open log file: " << covLogFilename << std::endl);
  44. return false;
  45. }
  46. std::string local_start_time = m_CTest->CurrentTime();
  47. m_CTest->StartXML(covLogFile);
  48. covLogFile << "<CoverageLog>" << std::endl
  49. << "\t<StartDateTime>" << local_start_time << "</StartDateTime>" << std::endl;
  50. return true;
  51. }
  52. //----------------------------------------------------------------------
  53. void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount)
  54. {
  55. std::string local_end_time = m_CTest->CurrentTime();
  56. ostr << "\t<EndDateTime>" << local_end_time << "</EndDateTime>" << std::endl
  57. << "</CoverageLog>" << std::endl;
  58. m_CTest->EndXML(ostr);
  59. char covLogFilename[1024];
  60. sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);
  61. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Close file: " << covLogFilename << std::endl);
  62. ostr.Close();
  63. }
  64. //----------------------------------------------------------------------
  65. bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file, const char* srcDir,
  66. const char* binDir)
  67. {
  68. std::vector<cmsys::RegularExpression>::iterator sit;
  69. for ( sit = m_CustomCoverageExcludeRegex.begin();
  70. sit != m_CustomCoverageExcludeRegex.end(); ++ sit )
  71. {
  72. if ( sit->find(file) )
  73. {
  74. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " File " << file
  75. << " is excluded in CTestCustom.ctest" << std::endl;);
  76. return false;
  77. }
  78. }
  79. std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);
  80. std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);
  81. std::string fFile = cmSystemTools::CollapseFullPath(file);
  82. bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(), fSrcDir.c_str());
  83. bool buildSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(), fBinDir.c_str());
  84. // Always check parent directory of the file.
  85. std::string fileDir = cmSystemTools::GetFilenamePath(fFile.c_str());
  86. std::string checkDir;
  87. // We also need to check the binary/source directory pair.
  88. if ( sourceSubDir && buildSubDir )
  89. {
  90. if ( fSrcDir.size() > fBinDir.size() )
  91. {
  92. checkDir = fSrcDir;
  93. }
  94. else
  95. {
  96. checkDir = fBinDir;
  97. }
  98. }
  99. else if ( sourceSubDir )
  100. {
  101. checkDir = fSrcDir;
  102. }
  103. else if ( buildSubDir )
  104. {
  105. checkDir = fBinDir;
  106. }
  107. std::string ndc
  108. = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
  109. fFile.c_str(), checkDir.c_str());
  110. if ( ndc.size() )
  111. {
  112. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str() << " so skip coverage of " << file << std::endl);
  113. return false;
  114. }
  115. // By now checkDir should be set to parent directory of the file.
  116. // Get the relative path to the file an apply it to the opposite directory.
  117. // If it is the same as fileDir, then ignore, otherwise check.
  118. std::string relPath = cmSystemTools::RelativePath(checkDir.c_str(),
  119. fFile.c_str());
  120. if ( checkDir == fSrcDir )
  121. {
  122. checkDir = fBinDir;
  123. }
  124. else
  125. {
  126. checkDir = fSrcDir;
  127. }
  128. fFile = checkDir + "/" + relPath;
  129. fFile = cmSystemTools::GetFilenamePath(fFile.c_str());
  130. if ( fileDir == fFile )
  131. {
  132. // This is in-source build, so we trust the previous check.
  133. return true;
  134. }
  135. ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
  136. fFile.c_str(), checkDir.c_str());
  137. if ( ndc.size() )
  138. {
  139. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str() << " so skip coverage of: " << file << std::endl);
  140. return false;
  141. }
  142. // Ok, nothing in source tree, nothing in binary tree
  143. return true;
  144. }
  145. //----------------------------------------------------------------------
  146. //clearly it would be nice if this were broken up into a few smaller
  147. //functions and commented...
  148. int cmCTestCoverageHandler::ProcessHandler()
  149. {
  150. int error = 0;
  151. std::string sourceDir = m_CTest->GetCTestConfiguration("SourceDirectory");
  152. std::string binaryDir = m_CTest->GetCTestConfiguration("BuildDirectory");
  153. std::string gcovCommand = m_CTest->GetCTestConfiguration("CoverageCommand");
  154. cmGeneratedFileStream ofs;
  155. double elapsed_time_start = cmSystemTools::GetTime();
  156. if ( !this->StartLogFile("Coverage", ofs) )
  157. {
  158. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot create LastCoverage.log file" << std::endl);
  159. }
  160. ofs << "Performing coverage: " << elapsed_time_start << std::endl;
  161. cmSystemTools::ConvertToUnixSlashes(sourceDir);
  162. cmSystemTools::ConvertToUnixSlashes(binaryDir);
  163. std::string asfGlob = sourceDir + "/*";
  164. std::string abfGlob = binaryDir + "/*";
  165. std::string daGlob = binaryDir + "/*.da";
  166. // Style 1
  167. std::string st1gcovOutputRex1 = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
  168. std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
  169. cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());
  170. cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());
  171. // Style 2
  172. std::string st2gcovOutputRex1 = "^File *`(.*)'$";
  173. std::string st2gcovOutputRex2 = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
  174. std::string st2gcovOutputRex3 = "^(.*):creating `(.*\\.gcov)'";
  175. std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";
  176. std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";
  177. std::string st2gcovOutputRex6 = "^(.*):source file is newer than graph file `(.*)'$";
  178. cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());
  179. cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());
  180. cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());
  181. cmsys::RegularExpression st2re4(st2gcovOutputRex4.c_str());
  182. cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());
  183. cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());
  184. cmCTestLog(m_CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
  185. std::string coverage_start_time = m_CTest->CurrentTime();
  186. std::string testingDir = m_CTest->GetBinaryDir() + "/Testing";
  187. std::string tempDir = testingDir + "/CoverageInfo";
  188. std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
  189. cmSystemTools::MakeDirectory(tempDir.c_str());
  190. cmSystemTools::ChangeDirectory(tempDir.c_str());
  191. cmGlob gl;
  192. gl.RecurseOn();
  193. gl.FindFiles(daGlob);
  194. std::vector<std::string> files = gl.GetFiles();
  195. std::vector<std::string>::iterator it;
  196. if ( files.size() == 0 )
  197. {
  198. cmCTestLog(m_CTest, ERROR_MESSAGE, " Cannot find any coverage files." << std::endl);
  199. // No coverage files is a valid thing, so the exit code is 0
  200. return 0;
  201. }
  202. m_CustomCoverageExcludeRegex.empty();
  203. std::vector<cmStdString>::iterator rexIt;
  204. for ( rexIt = m_CustomCoverageExclude.begin();
  205. rexIt != m_CustomCoverageExclude.end();
  206. ++ rexIt )
  207. {
  208. m_CustomCoverageExcludeRegex.push_back(cmsys::RegularExpression(rexIt->c_str()));
  209. }
  210. typedef std::vector<int> singleFileCoverageVector;
  211. typedef std::map<std::string, singleFileCoverageVector> totalCoverageMap;
  212. totalCoverageMap totalCoverage;
  213. int gcovStyle = 0;
  214. std::set<std::string> missingFiles;
  215. std::string actualSourceFile = "";
  216. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Processing coverage (each . represents one file):" << std::endl);
  217. cmCTestLog(m_CTest, HANDLER_OUTPUT, " ");
  218. int file_count = 0;
  219. for ( it = files.begin(); it != files.end(); ++ it )
  220. {
  221. cmCTestLog(m_CTest, HANDLER_OUTPUT, "." << std::flush);
  222. std::string fileDir = cmSystemTools::GetFilenamePath(it->c_str());
  223. std::string command = "\"" + gcovCommand + "\" -l -o \"" + fileDir + "\" \"" + *it + "\"";
  224. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, command.c_str() << std::endl);
  225. std::string output = "";
  226. std::string errors = "";
  227. int retVal = 0;
  228. ofs << "* Run coverage for: " << fileDir.c_str() << std::endl;
  229. ofs << " Command: " << command.c_str() << std::endl;
  230. int res = m_CTest->RunCommand(command.c_str(), &output, &errors,
  231. &retVal, tempDir.c_str(), 0 /*m_TimeOut*/);
  232. ofs << " Output: " << output.c_str() << std::endl;
  233. ofs << " Errors: " << errors.c_str() << std::endl;
  234. if ( ! res )
  235. {
  236. cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem running coverage on file: " << it->c_str() << std::endl);
  237. cmCTestLog(m_CTest, ERROR_MESSAGE, "Command produced error: " << errors << std::endl);
  238. error ++;
  239. continue;
  240. }
  241. if ( retVal != 0 )
  242. {
  243. cmCTestLog(m_CTest, ERROR_MESSAGE, "Coverage command returned: " << retVal << " while processing: " << it->c_str() << std::endl);
  244. cmCTestLog(m_CTest, ERROR_MESSAGE, "Command produced error: " << error << std::endl);
  245. }
  246. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT,
  247. "--------------------------------------------------------------" << std::endl
  248. << output << std::endl
  249. << "--------------------------------------------------------------" << std::endl);
  250. std::vector<cmStdString> lines;
  251. std::vector<cmStdString>::iterator line;
  252. // Globals for storing current source file and current gcov file;
  253. cmSystemTools::Split(output.c_str(), lines);
  254. for ( line = lines.begin(); line != lines.end(); ++line)
  255. {
  256. std::string sourceFile;
  257. std::string gcovFile;
  258. cmCTestLog(m_CTest, DEBUG, "Line: [" << line->c_str() << "]" << std::endl);
  259. if ( line->size() == 0 )
  260. {
  261. // Ignore empty line; probably style 2
  262. }
  263. else if ( st1re1.find(line->c_str()) )
  264. {
  265. if ( gcovStyle != 0 )
  266. {
  267. if ( gcovStyle != 1 )
  268. {
  269. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  270. error ++;
  271. break;
  272. }
  273. gcovStyle = 1;
  274. }
  275. actualSourceFile = "";
  276. sourceFile = st1re1.match(2);
  277. }
  278. else if ( st1re2.find(line->c_str() ) )
  279. {
  280. if ( gcovStyle != 0 )
  281. {
  282. if ( gcovStyle != 1 )
  283. {
  284. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  285. error ++;
  286. break;
  287. }
  288. gcovStyle = 1;
  289. }
  290. gcovFile = st1re2.match(1);
  291. }
  292. else if ( st2re1.find(line->c_str() ) )
  293. {
  294. if ( gcovStyle != 0 )
  295. {
  296. if ( gcovStyle != 2 )
  297. {
  298. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  299. error ++;
  300. break;
  301. }
  302. gcovStyle = 2;
  303. }
  304. actualSourceFile = "";
  305. sourceFile = st2re1.match(1);
  306. }
  307. else if ( st2re2.find(line->c_str() ) )
  308. {
  309. if ( gcovStyle != 0 )
  310. {
  311. if ( gcovStyle != 2 )
  312. {
  313. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  314. error ++;
  315. break;
  316. }
  317. gcovStyle = 2;
  318. }
  319. }
  320. else if ( st2re3.find(line->c_str() ) )
  321. {
  322. if ( gcovStyle != 0 )
  323. {
  324. if ( gcovStyle != 2 )
  325. {
  326. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  327. error ++;
  328. break;
  329. }
  330. gcovStyle = 2;
  331. }
  332. gcovFile = st2re3.match(2);
  333. }
  334. else if ( st2re4.find(line->c_str() ) )
  335. {
  336. if ( gcovStyle != 0 )
  337. {
  338. if ( gcovStyle != 2 )
  339. {
  340. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  341. error ++;
  342. break;
  343. }
  344. gcovStyle = 2;
  345. }
  346. cmCTestLog(m_CTest, WARNING, "Warning: " << st2re4.match(1) << " had unexpected EOF" << std::endl);
  347. }
  348. else if ( st2re5.find(line->c_str() ) )
  349. {
  350. if ( gcovStyle != 0 )
  351. {
  352. if ( gcovStyle != 2 )
  353. {
  354. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  355. error ++;
  356. break;
  357. }
  358. gcovStyle = 2;
  359. }
  360. cmCTestLog(m_CTest, WARNING, "Warning: Cannot open file: " << st2re5.match(1) << std::endl);
  361. }
  362. else if ( st2re6.find(line->c_str() ) )
  363. {
  364. if ( gcovStyle != 0 )
  365. {
  366. if ( gcovStyle != 2 )
  367. {
  368. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl);
  369. error ++;
  370. break;
  371. }
  372. gcovStyle = 2;
  373. }
  374. cmCTestLog(m_CTest, WARNING, "Warning: File: " << st2re6.match(1)
  375. << " is newer than " << st2re6.match(2) << std::endl);
  376. }
  377. else
  378. {
  379. cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown line: [" << line->c_str() << "]" << std::endl);
  380. error ++;
  381. //abort();
  382. }
  383. if ( !gcovFile.empty() && actualSourceFile.size() )
  384. {
  385. singleFileCoverageVector* vec = &totalCoverage[actualSourceFile];
  386. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " in file: " << gcovFile << std::endl);
  387. std::ifstream ifile(gcovFile.c_str());
  388. if ( ! ifile )
  389. {
  390. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot open file: " << gcovFile << std::endl);
  391. }
  392. else
  393. {
  394. long cnt = -1;
  395. std::string nl;
  396. while ( cmSystemTools::GetLineFromStream(ifile, nl) )
  397. {
  398. cnt ++;
  399. //TODO: Handle gcov 3.0 non-coverage lines
  400. // Skip empty lines
  401. if ( !nl.size() )
  402. {
  403. continue;
  404. }
  405. // Skip unused lines
  406. if ( nl.size() < 12 )
  407. {
  408. continue;
  409. }
  410. // Read the coverage count from the beginning of the gcov output line
  411. std::string prefix = nl.substr(0, 12);
  412. int cov = atoi(prefix.c_str());
  413. // Read the line number starting at the 10th character of the gcov output line
  414. std::string lineNumber = nl.substr(10, 5);
  415. int lineIdx = atoi(lineNumber.c_str())-1;
  416. if ( lineIdx >= 0 )
  417. {
  418. while ( vec->size() <= static_cast<singleFileCoverageVector::size_type>(lineIdx) )
  419. {
  420. vec->push_back(-1);
  421. }
  422. // Initially all entries are -1 (not used). If we get coverage
  423. // information, increment it to 0 first.
  424. if ( (*vec)[lineIdx] < 0 )
  425. {
  426. if ( cov > 0 || prefix.find("#") != prefix.npos )
  427. {
  428. (*vec)[lineIdx] = 0;
  429. }
  430. }
  431. (*vec)[lineIdx] += cov;
  432. }
  433. }
  434. }
  435. actualSourceFile = "";
  436. }
  437. if ( !sourceFile.empty() && actualSourceFile.empty() )
  438. {
  439. gcovFile = "";
  440. // Is it in the source dir?
  441. if ( sourceFile.size() > sourceDir.size() &&
  442. sourceFile.substr(0, sourceDir.size()) == sourceDir &&
  443. sourceFile[sourceDir.size()] == '/' )
  444. {
  445. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produced s: " << sourceFile.c_str() << std::endl);
  446. ofs << " produced in source dir: " << sourceFile.c_str() << std::endl;
  447. actualSourceFile = sourceFile;
  448. }
  449. // Binary dir?
  450. if ( sourceFile.size() > binaryDir.size() &&
  451. sourceFile.substr(0, binaryDir.size()) == binaryDir &&
  452. sourceFile[binaryDir.size()] == '/' )
  453. {
  454. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " produced b: " << sourceFile.c_str() << std::endl);
  455. ofs << " produced in binary dir: " << sourceFile.c_str() << std::endl;
  456. actualSourceFile = sourceFile;
  457. }
  458. if ( actualSourceFile.empty() )
  459. {
  460. if ( missingFiles.find(actualSourceFile) == missingFiles.end() )
  461. {
  462. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Something went wrong" << std::endl);
  463. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "File: [" << sourceFile.c_str() << "]" << std::endl);
  464. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "s: [" << sourceFile.substr(0, sourceDir.size()) << "]" << std::endl);
  465. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "b: [" << sourceFile.substr(0, binaryDir.size()) << "]" << std::endl);
  466. ofs << " Something went wrong. Cannot find: " << sourceFile.c_str()
  467. << " in source dir: " << sourceDir.c_str()
  468. << " or binary dir: " << binaryDir.c_str() << std::endl;
  469. missingFiles.insert(actualSourceFile);
  470. }
  471. }
  472. }
  473. }
  474. file_count ++;
  475. if ( file_count % 50 == 0 )
  476. {
  477. cmCTestLog(m_CTest, HANDLER_OUTPUT, " processed: " << file_count << " out of " << files.size() << std::endl);
  478. cmCTestLog(m_CTest, HANDLER_OUTPUT, " ");
  479. }
  480. }
  481. cmGeneratedFileStream covSumFile;
  482. cmGeneratedFileStream covLogFile;
  483. if (!this->StartResultingXML("Coverage", covSumFile))
  484. {
  485. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot open coverage summary file." << std::endl);
  486. return -1;
  487. }
  488. m_CTest->StartXML(covSumFile);
  489. // Produce output xml files
  490. covSumFile << "<Coverage>" << std::endl
  491. << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>" << std::endl;
  492. int logFileCount = 0;
  493. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  494. {
  495. return -1;
  496. }
  497. totalCoverageMap::iterator fileIterator;
  498. int cnt = 0;
  499. long total_tested = 0;
  500. long total_untested = 0;
  501. //std::string fullSourceDir = sourceDir + "/";
  502. //std::string fullBinaryDir = binaryDir + "/";
  503. cmCTestLog(m_CTest, HANDLER_OUTPUT, std::endl);
  504. cmCTestLog(m_CTest, HANDLER_OUTPUT, " Acumulating results (each . represents one file):" << std::endl);
  505. cmCTestLog(m_CTest, HANDLER_OUTPUT, " ");
  506. std::vector<std::string> errorsWhileAccumulating;
  507. file_count = 0;
  508. for ( fileIterator = totalCoverage.begin();
  509. fileIterator != totalCoverage.end();
  510. ++fileIterator )
  511. {
  512. cmCTestLog(m_CTest, HANDLER_OUTPUT, "." << std::flush);
  513. file_count ++;
  514. if ( file_count % 50 == 0 )
  515. {
  516. cmCTestLog(m_CTest, HANDLER_OUTPUT, " processed: " << file_count << " out of "
  517. << totalCoverage.size() << std::endl);
  518. cmCTestLog(m_CTest, HANDLER_OUTPUT, " ");
  519. }
  520. if ( cnt % 100 == 0 )
  521. {
  522. this->EndCoverageLogFile(covLogFile, logFileCount);
  523. logFileCount ++;
  524. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  525. {
  526. return -1;
  527. }
  528. }
  529. const std::string fullFileName = fileIterator->first;
  530. const std::string fileName = cmSystemTools::GetFilenameName(fullFileName.c_str());
  531. std::string fullFilePath = cmSystemTools::GetFilenamePath(fullFileName.c_str());
  532. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Process file: " << fullFileName << std::endl);
  533. cmSystemTools::ConvertToUnixSlashes(fullFilePath);
  534. if ( !cmSystemTools::FileExists(fullFileName.c_str()) )
  535. {
  536. cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot find file: " << fullFileName.c_str() << std::endl);
  537. continue;
  538. }
  539. bool shouldIDoCoverage
  540. = this->ShouldIDoCoverage(fullFileName.c_str(),
  541. sourceDir.c_str(), binaryDir.c_str());
  542. if ( !shouldIDoCoverage )
  543. {
  544. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, ".NoDartCoverage found, so skip coverage check for: "
  545. << fullFileName.c_str()
  546. << std::endl);
  547. continue;
  548. }
  549. const singleFileCoverageVector& fcov = fileIterator->second;
  550. covLogFile << "\t<File Name=\""
  551. << m_CTest->MakeXMLSafe(fileName.c_str())
  552. << "\" FullPath=\"" << m_CTest->MakeXMLSafe(m_CTest->GetShortPathToFile(
  553. fileIterator->first.c_str())) << "\">" << std::endl
  554. << "\t\t<Report>" << std::endl;
  555. std::ifstream ifs(fullFileName.c_str());
  556. if ( !ifs)
  557. {
  558. cmOStringStream ostr;
  559. ostr << "Cannot open source file: " << fullFileName.c_str();
  560. errorsWhileAccumulating.push_back(ostr.str());
  561. error ++;
  562. continue;
  563. }
  564. int tested = 0;
  565. int untested = 0;
  566. singleFileCoverageVector::size_type cc;
  567. std::string line;
  568. for ( cc= 0; cc < fcov.size(); cc ++ )
  569. {
  570. if ( !cmSystemTools::GetLineFromStream(ifs, line) )
  571. {
  572. cmOStringStream ostr;
  573. ostr << "Problem reading source file: " << fullFileName.c_str() << " line:" << cc;
  574. errorsWhileAccumulating.push_back(ostr.str());
  575. error ++;
  576. break;
  577. }
  578. covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc] << "\">"
  579. << m_CTest->MakeXMLSafe(line.c_str()) << "</Line>" << std::endl;
  580. if ( fcov[cc] == 0 )
  581. {
  582. untested ++;
  583. }
  584. else if ( fcov[cc] > 0 )
  585. {
  586. tested ++;
  587. }
  588. }
  589. if ( cmSystemTools::GetLineFromStream(ifs, line) )
  590. {
  591. cmOStringStream ostr;
  592. ostr << "Looks like there are more lines in the file: " << line;
  593. errorsWhileAccumulating.push_back(ostr.str());
  594. }
  595. float cper = 0;
  596. float cmet = 0;
  597. if ( tested + untested > 0 )
  598. {
  599. cper = (100 * SAFEDIV(static_cast<float>(tested),
  600. static_cast<float>(tested + untested)));
  601. cmet = ( SAFEDIV(static_cast<float>(tested + 10),
  602. static_cast<float>(tested + untested + 10)));
  603. }
  604. total_tested += tested;
  605. total_untested += untested;
  606. covLogFile << "\t\t</Report>" << std::endl
  607. << "\t</File>" << std::endl;
  608. covSumFile << "\t<File Name=\"" << m_CTest->MakeXMLSafe(fileName)
  609. << "\" FullPath=\"" << m_CTest->MakeXMLSafe(
  610. m_CTest->GetShortPathToFile(fullFileName.c_str()))
  611. << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"
  612. << "\t\t<LOCTested>" << tested << "</LOCTested>\n"
  613. << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
  614. << "\t\t<PercentCoverage>";
  615. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  616. covSumFile.precision(2);
  617. covSumFile << (cper) << "</PercentCoverage>\n"
  618. << "\t\t<CoverageMetric>";
  619. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  620. covSumFile.precision(2);
  621. covSumFile << (cmet) << "</CoverageMetric>\n"
  622. << "\t</File>" << std::endl;
  623. cnt ++;
  624. }
  625. this->EndCoverageLogFile(covLogFile, logFileCount);
  626. if ( errorsWhileAccumulating.size() > 0 )
  627. {
  628. cmCTestLog(m_CTest, ERROR_MESSAGE, std::endl);
  629. cmCTestLog(m_CTest, ERROR_MESSAGE, "Error(s) while acumulating results:" << std::endl);
  630. std::vector<std::string>::iterator erIt;
  631. for ( erIt = errorsWhileAccumulating.begin();
  632. erIt != errorsWhileAccumulating.end();
  633. ++ erIt )
  634. {
  635. cmCTestLog(m_CTest, ERROR_MESSAGE, " " << erIt->c_str() << std::endl);
  636. }
  637. }
  638. int total_lines = total_tested + total_untested;
  639. float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),
  640. static_cast<float>(total_lines));
  641. if ( total_lines == 0 )
  642. {
  643. percent_coverage = 0;
  644. }
  645. std::string end_time = m_CTest->CurrentTime();
  646. covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
  647. << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
  648. << "\t<LOC>" << total_lines << "</LOC>\n"
  649. << "\t<PercentCoverage>";
  650. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  651. covSumFile.precision(2);
  652. covSumFile << (percent_coverage)<< "</PercentCoverage>\n"
  653. << "\t<EndDateTime>" << end_time << "</EndDateTime>\n";
  654. covSumFile << "<ElapsedMinutes>" <<
  655. static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
  656. << "</ElapsedMinutes>"
  657. << "</Coverage>" << std::endl;
  658. m_CTest->EndXML(covSumFile);
  659. cmCTestLog(m_CTest, HANDLER_OUTPUT, "\tCovered LOC: " << total_tested << std::endl
  660. << "\tNot covered LOC: " << total_untested << std::endl
  661. << "\tTotal LOC: " << total_lines << std::endl
  662. << "\tPercentage Coverage: "
  663. << std::setiosflags(std::ios::fixed)
  664. << std::setprecision(2)
  665. << (percent_coverage) << "%" << std::endl);
  666. ofs << "\tCovered LOC: " << total_tested << std::endl
  667. << "\tNot covered LOC: " << total_untested << std::endl
  668. << "\tTotal LOC: " << total_lines << std::endl
  669. << "\tPercentage Coverage: "
  670. << std::setiosflags(std::ios::fixed)
  671. << std::setprecision(2)
  672. << (percent_coverage) << "%" << std::endl;
  673. cmSystemTools::ChangeDirectory(currentDirectory.c_str());
  674. if ( error )
  675. {
  676. return -1;
  677. }
  678. return 0;
  679. }
  680. //----------------------------------------------------------------------
  681. void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
  682. {
  683. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude regular expressions." << std::endl);
  684. cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
  685. m_CustomCoverageExclude);
  686. std::vector<cmStdString>::iterator it;
  687. for ( it = m_CustomCoverageExclude.begin();
  688. it != m_CustomCoverageExclude.end();
  689. ++ it )
  690. {
  691. cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: " << it->c_str() << std::endl);
  692. }
  693. }