cmCTestCoverageHandler.cxx 23 KB

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