cmCTestCoverageHandler.cxx 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCTestCoverageHandler.h"
  11. #include "cmParsePHPCoverage.h"
  12. #include "cmParseCoberturaCoverage.h"
  13. #include "cmParseGTMCoverage.h"
  14. #include "cmParseCacheCoverage.h"
  15. #include "cmParseJacocoCoverage.h"
  16. #include "cmCTest.h"
  17. #include "cmake.h"
  18. #include "cmMakefile.h"
  19. #include "cmSystemTools.h"
  20. #include "cmGeneratedFileStream.h"
  21. #include "cmXMLSafe.h"
  22. #include <cmsys/Process.h>
  23. #include <cmsys/RegularExpression.hxx>
  24. #include <cmsys/Glob.hxx>
  25. #include <cmsys/stl/iterator>
  26. #include <cmsys/stl/algorithm>
  27. #include <cmsys/FStream.hxx>
  28. #include <stdlib.h>
  29. #include <math.h>
  30. #include <float.h>
  31. #define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
  32. class cmCTestRunProcess
  33. {
  34. public:
  35. cmCTestRunProcess()
  36. {
  37. this->Process = cmsysProcess_New();
  38. this->PipeState = -1;
  39. this->TimeOut = -1;
  40. }
  41. ~cmCTestRunProcess()
  42. {
  43. if(!(this->PipeState == -1)
  44. && !(this->PipeState == cmsysProcess_Pipe_None )
  45. && !(this->PipeState == cmsysProcess_Pipe_Timeout))
  46. {
  47. this->WaitForExit();
  48. }
  49. cmsysProcess_Delete(this->Process);
  50. }
  51. void SetCommand(const char* command)
  52. {
  53. this->CommandLineStrings.clear();
  54. this->CommandLineStrings.push_back(command);;
  55. }
  56. void AddArgument(const char* arg)
  57. {
  58. if(arg)
  59. {
  60. this->CommandLineStrings.push_back(arg);
  61. }
  62. }
  63. void SetWorkingDirectory(const char* dir)
  64. {
  65. this->WorkingDirectory = dir;
  66. }
  67. void SetTimeout(double t)
  68. {
  69. this->TimeOut = t;
  70. }
  71. bool StartProcess()
  72. {
  73. std::vector<const char*> args;
  74. for(std::vector<std::string>::iterator i =
  75. this->CommandLineStrings.begin();
  76. i != this->CommandLineStrings.end(); ++i)
  77. {
  78. args.push_back(i->c_str());
  79. }
  80. args.push_back(0); // null terminate
  81. cmsysProcess_SetCommand(this->Process, &*args.begin());
  82. if(this->WorkingDirectory.size())
  83. {
  84. cmsysProcess_SetWorkingDirectory(this->Process,
  85. this->WorkingDirectory.c_str());
  86. }
  87. cmsysProcess_SetOption(this->Process,
  88. cmsysProcess_Option_HideWindow, 1);
  89. if(this->TimeOut != -1)
  90. {
  91. cmsysProcess_SetTimeout(this->Process, this->TimeOut);
  92. }
  93. cmsysProcess_Execute(this->Process);
  94. this->PipeState = cmsysProcess_GetState(this->Process);
  95. // if the process is running or exited return true
  96. if(this->PipeState == cmsysProcess_State_Executing
  97. || this->PipeState == cmsysProcess_State_Exited)
  98. {
  99. return true;
  100. }
  101. return false;
  102. }
  103. void SetStdoutFile(const char* fname)
  104. {
  105. cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);
  106. }
  107. void SetStderrFile(const char* fname)
  108. {
  109. cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);
  110. }
  111. int WaitForExit(double* timeout =0)
  112. {
  113. this->PipeState = cmsysProcess_WaitForExit(this->Process,
  114. timeout);
  115. return this->PipeState;
  116. }
  117. int GetProcessState() { return this->PipeState;}
  118. private:
  119. int PipeState;
  120. cmsysProcess* Process;
  121. std::vector<std::string> CommandLineStrings;
  122. std::string WorkingDirectory;
  123. double TimeOut;
  124. };
  125. //----------------------------------------------------------------------
  126. //----------------------------------------------------------------------
  127. cmCTestCoverageHandler::cmCTestCoverageHandler()
  128. {
  129. }
  130. //----------------------------------------------------------------------
  131. void cmCTestCoverageHandler::Initialize()
  132. {
  133. this->Superclass::Initialize();
  134. this->CustomCoverageExclude.clear();
  135. this->SourceLabels.clear();
  136. this->TargetDirs.clear();
  137. this->LabelIdMap.clear();
  138. this->Labels.clear();
  139. this->LabelFilter.clear();
  140. }
  141. //----------------------------------------------------------------------------
  142. void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
  143. {
  144. std::string logGlob = this->CTest->GetCTestConfiguration("BuildDirectory");
  145. logGlob += "/Testing/";
  146. logGlob += this->CTest->GetCurrentTag();
  147. logGlob += "/CoverageLog*";
  148. cmsys::Glob gl;
  149. gl.FindFiles(logGlob);
  150. std::vector<std::string> const& files = gl.GetFiles();
  151. for(std::vector<std::string>::const_iterator fi = files.begin();
  152. fi != files.end(); ++fi)
  153. {
  154. log << "Removing old coverage log: " << *fi << "\n";
  155. cmSystemTools::RemoveFile(*fi);
  156. }
  157. }
  158. //----------------------------------------------------------------------
  159. bool cmCTestCoverageHandler::StartCoverageLogFile(
  160. cmGeneratedFileStream& covLogFile, int logFileCount)
  161. {
  162. char covLogFilename[1024];
  163. sprintf(covLogFilename, "CoverageLog-%d", logFileCount);
  164. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Open file: "
  165. << covLogFilename << std::endl);
  166. if(!this->StartResultingXML(cmCTest::PartCoverage,
  167. covLogFilename, covLogFile))
  168. {
  169. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file: "
  170. << covLogFilename << std::endl);
  171. return false;
  172. }
  173. std::string local_start_time = this->CTest->CurrentTime();
  174. this->CTest->StartXML(covLogFile, this->AppendXML);
  175. covLogFile << "<CoverageLog>" << std::endl
  176. << "\t<StartDateTime>" << local_start_time << "</StartDateTime>"
  177. << "\t<StartTime>"
  178. << static_cast<unsigned int>(cmSystemTools::GetTime())
  179. << "</StartTime>"
  180. << std::endl;
  181. return true;
  182. }
  183. //----------------------------------------------------------------------
  184. void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr,
  185. int logFileCount)
  186. {
  187. std::string local_end_time = this->CTest->CurrentTime();
  188. ostr << "\t<EndDateTime>" << local_end_time << "</EndDateTime>" << std::endl
  189. << "\t<EndTime>" <<
  190. static_cast<unsigned int>(cmSystemTools::GetTime())
  191. << "</EndTime>" << std::endl
  192. << "</CoverageLog>" << std::endl;
  193. this->CTest->EndXML(ostr);
  194. char covLogFilename[1024];
  195. sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);
  196. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Close file: "
  197. << covLogFilename << std::endl);
  198. ostr.Close();
  199. }
  200. //----------------------------------------------------------------------
  201. bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file,
  202. const char* srcDir,
  203. const char* binDir)
  204. {
  205. if(this->IsFilteredOut(file))
  206. {
  207. return false;
  208. }
  209. std::vector<cmsys::RegularExpression>::iterator sit;
  210. for ( sit = this->CustomCoverageExcludeRegex.begin();
  211. sit != this->CustomCoverageExcludeRegex.end(); ++ sit )
  212. {
  213. if ( sit->find(file) )
  214. {
  215. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " File " << file
  216. << " is excluded in CTestCustom.ctest" << std::endl;);
  217. return false;
  218. }
  219. }
  220. std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);
  221. std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);
  222. std::string fFile = cmSystemTools::CollapseFullPath(file);
  223. bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile,
  224. fSrcDir);
  225. bool buildSubDir = cmSystemTools::IsSubDirectory(fFile,
  226. fBinDir);
  227. // Always check parent directory of the file.
  228. std::string fileDir = cmSystemTools::GetFilenamePath(fFile);
  229. std::string checkDir;
  230. // We also need to check the binary/source directory pair.
  231. if ( sourceSubDir && buildSubDir )
  232. {
  233. if ( fSrcDir.size() > fBinDir.size() )
  234. {
  235. checkDir = fSrcDir;
  236. }
  237. else
  238. {
  239. checkDir = fBinDir;
  240. }
  241. }
  242. else if ( sourceSubDir )
  243. {
  244. checkDir = fSrcDir;
  245. }
  246. else if ( buildSubDir )
  247. {
  248. checkDir = fBinDir;
  249. }
  250. std::string ndc
  251. = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
  252. fFile.c_str(), checkDir.c_str());
  253. if ( ndc.size() )
  254. {
  255. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc
  256. << " so skip coverage of " << file << std::endl);
  257. return false;
  258. }
  259. // By now checkDir should be set to parent directory of the file.
  260. // Get the relative path to the file an apply it to the opposite directory.
  261. // If it is the same as fileDir, then ignore, otherwise check.
  262. std::string relPath;
  263. if(checkDir.size() )
  264. {
  265. relPath = cmSystemTools::RelativePath(checkDir.c_str(),
  266. fFile.c_str());
  267. }
  268. else
  269. {
  270. relPath = fFile;
  271. }
  272. if ( checkDir == fSrcDir )
  273. {
  274. checkDir = fBinDir;
  275. }
  276. else
  277. {
  278. checkDir = fSrcDir;
  279. }
  280. fFile = checkDir + "/" + relPath;
  281. fFile = cmSystemTools::GetFilenamePath(fFile);
  282. if ( fileDir == fFile )
  283. {
  284. // This is in-source build, so we trust the previous check.
  285. return true;
  286. }
  287. ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
  288. fFile.c_str(), checkDir.c_str());
  289. if ( ndc.size() )
  290. {
  291. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc
  292. << " so skip coverage of: " << file << std::endl);
  293. return false;
  294. }
  295. // Ok, nothing in source tree, nothing in binary tree
  296. return true;
  297. }
  298. //----------------------------------------------------------------------
  299. //clearly it would be nice if this were broken up into a few smaller
  300. //functions and commented...
  301. int cmCTestCoverageHandler::ProcessHandler()
  302. {
  303. this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);
  304. int error = 0;
  305. // do we have time for this
  306. if (this->CTest->GetRemainingTimeAllowed() < 120)
  307. {
  308. return error;
  309. }
  310. std::string coverage_start_time = this->CTest->CurrentTime();
  311. unsigned int coverage_start_time_time = static_cast<unsigned int>(
  312. cmSystemTools::GetTime());
  313. std::string sourceDir
  314. = this->CTest->GetCTestConfiguration("SourceDirectory");
  315. std::string binaryDir
  316. = this->CTest->GetCTestConfiguration("BuildDirectory");
  317. this->LoadLabels();
  318. cmGeneratedFileStream ofs;
  319. double elapsed_time_start = cmSystemTools::GetTime();
  320. if ( !this->StartLogFile("Coverage", ofs) )
  321. {
  322. cmCTestLog(this->CTest, ERROR_MESSAGE,
  323. "Cannot create LastCoverage.log file" << std::endl);
  324. }
  325. ofs << "Performing coverage: " << elapsed_time_start << std::endl;
  326. this->CleanCoverageLogFiles(ofs);
  327. cmSystemTools::ConvertToUnixSlashes(sourceDir);
  328. cmSystemTools::ConvertToUnixSlashes(binaryDir);
  329. cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
  330. cmCTestCoverageHandlerContainer cont;
  331. cont.Error = error;
  332. cont.SourceDir = sourceDir;
  333. cont.BinaryDir = binaryDir;
  334. cont.OFS = &ofs;
  335. // setup the regex exclude stuff
  336. this->CustomCoverageExcludeRegex.clear();
  337. std::vector<std::string>::iterator rexIt;
  338. for ( rexIt = this->CustomCoverageExclude.begin();
  339. rexIt != this->CustomCoverageExclude.end();
  340. ++ rexIt )
  341. {
  342. this->CustomCoverageExcludeRegex.push_back(
  343. cmsys::RegularExpression(rexIt->c_str()));
  344. }
  345. if(this->HandleBullseyeCoverage(&cont))
  346. {
  347. return cont.Error;
  348. }
  349. int file_count = 0;
  350. file_count += this->HandleGCovCoverage(&cont);
  351. error = cont.Error;
  352. if ( file_count < 0 )
  353. {
  354. return error;
  355. }
  356. file_count += this->HandleLCovCoverage(&cont);
  357. error = cont.Error;
  358. if ( file_count < 0 )
  359. {
  360. return error;
  361. }
  362. file_count += this->HandleTracePyCoverage(&cont);
  363. error = cont.Error;
  364. if ( file_count < 0 )
  365. {
  366. return error;
  367. }
  368. file_count += this->HandlePHPCoverage(&cont);
  369. error = cont.Error;
  370. if ( file_count < 0 )
  371. {
  372. return error;
  373. }
  374. file_count += this->HandleCoberturaCoverage(&cont);
  375. error = cont.Error;
  376. if ( file_count < 0 )
  377. {
  378. return error;
  379. }
  380. file_count += this->HandleMumpsCoverage(&cont);
  381. error = cont.Error;
  382. if ( file_count < 0 )
  383. {
  384. return error;
  385. }
  386. file_count += this->HandleJacocoCoverage(&cont);
  387. error = cont.Error;
  388. if ( file_count < 0 )
  389. {
  390. return error;
  391. }
  392. std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
  393. if ( file_count == 0 )
  394. {
  395. cmCTestLog(this->CTest, WARNING,
  396. " Cannot find any coverage files. Ignoring Coverage request."
  397. << std::endl);
  398. return error;
  399. }
  400. cmGeneratedFileStream covSumFile;
  401. cmGeneratedFileStream covLogFile;
  402. if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))
  403. {
  404. cmCTestLog(this->CTest, ERROR_MESSAGE,
  405. "Cannot open coverage summary file." << std::endl);
  406. return -1;
  407. }
  408. this->CTest->StartXML(covSumFile, this->AppendXML);
  409. // Produce output xml files
  410. covSumFile << "<Coverage>" << std::endl
  411. << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>"
  412. << std::endl
  413. << "\t<StartTime>" << coverage_start_time_time << "</StartTime>"
  414. << std::endl;
  415. int logFileCount = 0;
  416. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  417. {
  418. return -1;
  419. }
  420. cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator;
  421. int cnt = 0;
  422. long total_tested = 0;
  423. long total_untested = 0;
  424. //std::string fullSourceDir = sourceDir + "/";
  425. //std::string fullBinaryDir = binaryDir + "/";
  426. cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
  427. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  428. " Accumulating results (each . represents one file):" << std::endl);
  429. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  430. std::vector<std::string> errorsWhileAccumulating;
  431. file_count = 0;
  432. for ( fileIterator = cont.TotalCoverage.begin();
  433. fileIterator != cont.TotalCoverage.end();
  434. ++fileIterator )
  435. {
  436. cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
  437. file_count ++;
  438. if ( file_count % 50 == 0 )
  439. {
  440. cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
  441. << " out of "
  442. << cont.TotalCoverage.size() << std::endl);
  443. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  444. }
  445. const std::string fullFileName = fileIterator->first;
  446. bool shouldIDoCoverage
  447. = this->ShouldIDoCoverage(fullFileName.c_str(),
  448. sourceDir.c_str(), binaryDir.c_str());
  449. if ( !shouldIDoCoverage )
  450. {
  451. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  452. ".NoDartCoverage found, so skip coverage check for: "
  453. << fullFileName
  454. << std::endl);
  455. continue;
  456. }
  457. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  458. "Process file: " << fullFileName << std::endl);
  459. if ( !cmSystemTools::FileExists(fullFileName.c_str()) )
  460. {
  461. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
  462. << fullFileName << std::endl);
  463. continue;
  464. }
  465. if ( ++cnt % 100 == 0 )
  466. {
  467. this->EndCoverageLogFile(covLogFile, logFileCount);
  468. logFileCount ++;
  469. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  470. {
  471. return -1;
  472. }
  473. }
  474. const std::string fileName
  475. = cmSystemTools::GetFilenameName(fullFileName);
  476. std::string shortFileName =
  477. this->CTest->GetShortPathToFile(fullFileName.c_str());
  478. const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov
  479. = fileIterator->second;
  480. covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)
  481. << "\" FullPath=\"" << cmXMLSafe(shortFileName) << "\">\n"
  482. << "\t\t<Report>" << std::endl;
  483. cmsys::ifstream ifs(fullFileName.c_str());
  484. if ( !ifs)
  485. {
  486. cmOStringStream ostr;
  487. ostr << "Cannot open source file: " << fullFileName;
  488. errorsWhileAccumulating.push_back(ostr.str());
  489. error ++;
  490. continue;
  491. }
  492. int tested = 0;
  493. int untested = 0;
  494. cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
  495. std::string line;
  496. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  497. "Actually performing coverage for: " << fullFileName << std::endl);
  498. for ( cc= 0; cc < fcov.size(); cc ++ )
  499. {
  500. if ( !cmSystemTools::GetLineFromStream(ifs, line) &&
  501. cc != fcov.size() -1 )
  502. {
  503. cmOStringStream ostr;
  504. ostr << "Problem reading source file: " << fullFileName
  505. << " line:" << cc << " out total: " << fcov.size()-1;
  506. errorsWhileAccumulating.push_back(ostr.str());
  507. error ++;
  508. break;
  509. }
  510. covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc]
  511. << "\">"
  512. << cmXMLSafe(line) << "</Line>" << std::endl;
  513. if ( fcov[cc] == 0 )
  514. {
  515. untested ++;
  516. }
  517. else if ( fcov[cc] > 0 )
  518. {
  519. tested ++;
  520. }
  521. }
  522. if ( cmSystemTools::GetLineFromStream(ifs, line) )
  523. {
  524. cmOStringStream ostr;
  525. ostr << "Looks like there are more lines in the file: " << line;
  526. errorsWhileAccumulating.push_back(ostr.str());
  527. }
  528. float cper = 0;
  529. float cmet = 0;
  530. if ( tested + untested > 0 )
  531. {
  532. cper = (100 * SAFEDIV(static_cast<float>(tested),
  533. static_cast<float>(tested + untested)));
  534. cmet = ( SAFEDIV(static_cast<float>(tested + 10),
  535. static_cast<float>(tested + untested + 10)));
  536. }
  537. total_tested += tested;
  538. total_untested += untested;
  539. covLogFile << "\t\t</Report>" << std::endl
  540. << "\t</File>" << std::endl;
  541. covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)
  542. << "\" FullPath=\"" << cmXMLSafe(
  543. this->CTest->GetShortPathToFile(fullFileName.c_str()))
  544. << "\" Covered=\"" << (tested+untested > 0 ? "true":"false") << "\">\n"
  545. << "\t\t<LOCTested>" << tested << "</LOCTested>\n"
  546. << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
  547. << "\t\t<PercentCoverage>";
  548. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  549. covSumFile.precision(2);
  550. covSumFile << (cper) << "</PercentCoverage>\n"
  551. << "\t\t<CoverageMetric>";
  552. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  553. covSumFile.precision(2);
  554. covSumFile << (cmet) << "</CoverageMetric>\n";
  555. this->WriteXMLLabels(covSumFile, shortFileName);
  556. covSumFile << "\t</File>" << std::endl;
  557. }
  558. //Handle all the files in the extra coverage globs that have no cov data
  559. for(std::set<std::string>::iterator i = uncovered.begin();
  560. i != uncovered.end(); ++i)
  561. {
  562. std::string fileName = cmSystemTools::GetFilenameName(*i);
  563. std::string fullPath = cont.SourceDir + "/" + *i;
  564. covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)
  565. << "\" FullPath=\"" << cmXMLSafe(*i) << "\">\n"
  566. << "\t\t<Report>" << std::endl;
  567. cmsys::ifstream ifs(fullPath.c_str());
  568. if (!ifs)
  569. {
  570. cmOStringStream ostr;
  571. ostr << "Cannot open source file: " << fullPath;
  572. errorsWhileAccumulating.push_back(ostr.str());
  573. error ++;
  574. continue;
  575. }
  576. int untested = 0;
  577. std::string line;
  578. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  579. "Actually performing coverage for: " << *i << std::endl);
  580. while (cmSystemTools::GetLineFromStream(ifs, line))
  581. {
  582. covLogFile << "\t\t<Line Number=\"" << untested << "\" Count=\"0\">"
  583. << cmXMLSafe(line) << "</Line>" << std::endl;
  584. untested ++;
  585. }
  586. covLogFile << "\t\t</Report>\n\t</File>" << std::endl;
  587. total_untested += untested;
  588. covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)
  589. << "\" FullPath=\"" << cmXMLSafe(i->c_str())
  590. << "\" Covered=\"true\">\n"
  591. << "\t\t<LOCTested>0</LOCTested>\n"
  592. << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
  593. << "\t\t<PercentCoverage>0</PercentCoverage>\n"
  594. << "\t\t<CoverageMetric>0</CoverageMetric>\n";
  595. this->WriteXMLLabels(covSumFile, *i);
  596. covSumFile << "\t</File>" << std::endl;
  597. }
  598. this->EndCoverageLogFile(covLogFile, logFileCount);
  599. if ( errorsWhileAccumulating.size() > 0 )
  600. {
  601. cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
  602. cmCTestLog(this->CTest, ERROR_MESSAGE,
  603. "Error(s) while accumulating results:" << std::endl);
  604. std::vector<std::string>::iterator erIt;
  605. for ( erIt = errorsWhileAccumulating.begin();
  606. erIt != errorsWhileAccumulating.end();
  607. ++ erIt )
  608. {
  609. cmCTestLog(this->CTest, ERROR_MESSAGE,
  610. " " << *erIt << std::endl);
  611. }
  612. }
  613. long total_lines = total_tested + total_untested;
  614. float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),
  615. static_cast<float>(total_lines));
  616. if ( total_lines == 0 )
  617. {
  618. percent_coverage = 0;
  619. }
  620. std::string end_time = this->CTest->CurrentTime();
  621. covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
  622. << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
  623. << "\t<LOC>" << total_lines << "</LOC>\n"
  624. << "\t<PercentCoverage>";
  625. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  626. covSumFile.precision(2);
  627. covSumFile << (percent_coverage)<< "</PercentCoverage>\n"
  628. << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
  629. << "\t<EndTime>" <<
  630. static_cast<unsigned int>(cmSystemTools::GetTime())
  631. << "</EndTime>\n";
  632. covSumFile << "<ElapsedMinutes>" <<
  633. static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
  634. << "</ElapsedMinutes>"
  635. << "</Coverage>" << std::endl;
  636. this->CTest->EndXML(covSumFile);
  637. cmCTestLog(this->CTest, HANDLER_OUTPUT, "" << std::endl
  638. << "\tCovered LOC: "
  639. << total_tested << std::endl
  640. << "\tNot covered LOC: " << total_untested << std::endl
  641. << "\tTotal LOC: " << total_lines << std::endl
  642. << "\tPercentage Coverage: "
  643. << std::setiosflags(std::ios::fixed)
  644. << std::setprecision(2)
  645. << (percent_coverage) << "%" << std::endl);
  646. ofs << "\tCovered LOC: " << total_tested << std::endl
  647. << "\tNot covered LOC: " << total_untested << std::endl
  648. << "\tTotal LOC: " << total_lines << std::endl
  649. << "\tPercentage Coverage: "
  650. << std::setiosflags(std::ios::fixed)
  651. << std::setprecision(2)
  652. << (percent_coverage) << "%" << std::endl;
  653. if ( error )
  654. {
  655. return -1;
  656. }
  657. return 0;
  658. }
  659. //----------------------------------------------------------------------
  660. void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
  661. {
  662. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  663. " Add coverage exclude regular expressions." << std::endl);
  664. this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
  665. this->CustomCoverageExclude);
  666. this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",
  667. this->ExtraCoverageGlobs);
  668. std::vector<std::string>::iterator it;
  669. for ( it = this->CustomCoverageExclude.begin();
  670. it != this->CustomCoverageExclude.end();
  671. ++ it )
  672. {
  673. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "
  674. << *it << std::endl);
  675. }
  676. for ( it = this->ExtraCoverageGlobs.begin();
  677. it != this->ExtraCoverageGlobs.end(); ++it)
  678. {
  679. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage glob: "
  680. << *it << std::endl);
  681. }
  682. }
  683. //----------------------------------------------------------------------
  684. // Fix for issue #4971 where the case of the drive letter component of
  685. // the filenames might be different when analyzing gcov output.
  686. //
  687. // Compare file names: fnc(fn1) == fnc(fn2) // fnc == file name compare
  688. //
  689. #ifdef _WIN32
  690. #define fnc(s) cmSystemTools::LowerCase(s)
  691. #else
  692. #define fnc(s) s
  693. #endif
  694. //----------------------------------------------------------------------
  695. bool IsFileInDir(const std::string &infile, const std::string &indir)
  696. {
  697. std::string file = cmSystemTools::CollapseFullPath(infile);
  698. std::string dir = cmSystemTools::CollapseFullPath(indir);
  699. if (
  700. file.size() > dir.size() &&
  701. (fnc(file.substr(0, dir.size())) == fnc(dir)) &&
  702. file[dir.size()] == '/'
  703. )
  704. {
  705. return true;
  706. }
  707. return false;
  708. }
  709. //----------------------------------------------------------------------
  710. int cmCTestCoverageHandler::HandlePHPCoverage(
  711. cmCTestCoverageHandlerContainer* cont)
  712. {
  713. cmParsePHPCoverage cov(*cont, this->CTest);
  714. std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
  715. if(cmSystemTools::FileIsDirectory(coverageDir))
  716. {
  717. cov.ReadPHPCoverageDirectory(coverageDir.c_str());
  718. }
  719. return static_cast<int>(cont->TotalCoverage.size());
  720. }
  721. //----------------------------------------------------------------------
  722. int cmCTestCoverageHandler::HandleCoberturaCoverage(
  723. cmCTestCoverageHandlerContainer* cont)
  724. {
  725. cmParseCoberturaCoverage cov(*cont, this->CTest);
  726. // Assume the coverage.xml is in the source directory
  727. std::string coverageXMLFile = this->CTest->GetBinaryDir() + "/coverage.xml";
  728. if(cmSystemTools::FileExists(coverageXMLFile.c_str()))
  729. {
  730. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  731. "Parsing Cobertura XML file: " << coverageXMLFile
  732. << std::endl);
  733. cov.ReadCoverageXML(coverageXMLFile.c_str());
  734. }
  735. else
  736. {
  737. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  738. "Cannot find Cobertura XML file: " << coverageXMLFile
  739. << std::endl);
  740. }
  741. return static_cast<int>(cont->TotalCoverage.size());
  742. }
  743. //----------------------------------------------------------------------
  744. int cmCTestCoverageHandler::HandleMumpsCoverage(
  745. cmCTestCoverageHandlerContainer* cont)
  746. {
  747. // try gtm coverage
  748. cmParseGTMCoverage cov(*cont, this->CTest);
  749. std::string coverageFile = this->CTest->GetBinaryDir() +
  750. "/gtm_coverage.mcov";
  751. if(cmSystemTools::FileExists(coverageFile.c_str()))
  752. {
  753. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  754. "Parsing Cache Coverage: " << coverageFile
  755. << std::endl);
  756. cov.ReadCoverageFile(coverageFile.c_str());
  757. return static_cast<int>(cont->TotalCoverage.size());
  758. }
  759. else
  760. {
  761. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  762. " Cannot find foobar GTM coverage file: " << coverageFile
  763. << std::endl);
  764. }
  765. cmParseCacheCoverage ccov(*cont, this->CTest);
  766. coverageFile = this->CTest->GetBinaryDir() +
  767. "/cache_coverage.cmcov";
  768. if(cmSystemTools::FileExists(coverageFile.c_str()))
  769. {
  770. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  771. "Parsing Cache Coverage: " << coverageFile
  772. << std::endl);
  773. ccov.ReadCoverageFile(coverageFile.c_str());
  774. }
  775. else
  776. {
  777. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  778. " Cannot find Cache coverage file: " << coverageFile
  779. << std::endl);
  780. }
  781. return static_cast<int>(cont->TotalCoverage.size());
  782. }
  783. struct cmCTestCoverageHandlerLocale
  784. {
  785. cmCTestCoverageHandlerLocale()
  786. {
  787. if(const char* l = cmSystemTools::GetEnv("LC_ALL"))
  788. {
  789. lc_all = l;
  790. }
  791. if(lc_all != "C")
  792. {
  793. cmSystemTools::PutEnv("LC_ALL=C");
  794. }
  795. }
  796. ~cmCTestCoverageHandlerLocale()
  797. {
  798. if(!lc_all.empty())
  799. {
  800. cmSystemTools::PutEnv(("LC_ALL=" + lc_all).c_str());
  801. }
  802. else
  803. {
  804. cmSystemTools::UnsetEnv("LC_ALL");
  805. }
  806. }
  807. std::string lc_all;
  808. };
  809. //----------------------------------------------------------------------
  810. int cmCTestCoverageHandler::HandleJacocoCoverage(
  811. cmCTestCoverageHandlerContainer* cont)
  812. {
  813. cmParseJacocoCoverage cov =
  814. cmParseJacocoCoverage(*cont, this->CTest);
  815. cmsys::Glob g;
  816. std::vector<std::string> files;
  817. g.SetRecurse(true);
  818. std::string SourceDir
  819. = this->CTest->GetCTestConfiguration("SourceDirectory");
  820. std::string coverageFile = SourceDir+ "/*jacoco.xml";
  821. g.FindFiles(coverageFile);
  822. files=g.GetFiles();
  823. if (files.size() > 0)
  824. {
  825. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  826. "Found Jacoco Files, Performing Coverage" << std::endl);
  827. cov.LoadCoverageData(files);
  828. }
  829. else
  830. {
  831. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  832. " Cannot find Jacoco coverage files: " << coverageFile
  833. << std::endl);
  834. }
  835. return static_cast<int>(cont->TotalCoverage.size());
  836. }
  837. //----------------------------------------------------------------------
  838. int cmCTestCoverageHandler::HandleGCovCoverage(
  839. cmCTestCoverageHandlerContainer* cont)
  840. {
  841. std::string gcovCommand
  842. = this->CTest->GetCTestConfiguration("CoverageCommand");
  843. if (gcovCommand.empty())
  844. {
  845. cmCTestLog(this->CTest, ERROR_MESSAGE,
  846. "Could not find gcov." << std::endl);
  847. return 0;
  848. }
  849. std::string gcovExtraFlags
  850. = this->CTest->GetCTestConfiguration("CoverageExtraFlags");
  851. // Immediately skip to next coverage option since codecov is only for Intel
  852. // compiler
  853. if ( gcovCommand == "codecov" )
  854. {
  855. return 0;
  856. }
  857. // Style 1
  858. std::string st1gcovOutputRex1
  859. = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
  860. std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";
  861. cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());
  862. cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());
  863. // Style 2
  864. std::string st2gcovOutputRex1 = "^File *[`'](.*)'$";
  865. std::string st2gcovOutputRex2
  866. = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
  867. std::string st2gcovOutputRex3 = "^(.*)reating [`'](.*\\.gcov)'";
  868. std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";
  869. std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";
  870. std::string st2gcovOutputRex6
  871. = "^(.*):source file is newer than graph file `(.*)'$";
  872. cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());
  873. cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());
  874. cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());
  875. cmsys::RegularExpression st2re4(st2gcovOutputRex4.c_str());
  876. cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());
  877. cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());
  878. std::vector<std::string> files;
  879. this->FindGCovFiles(files);
  880. std::vector<std::string>::iterator it;
  881. if ( files.size() == 0 )
  882. {
  883. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  884. " Cannot find any GCov coverage files."
  885. << std::endl);
  886. // No coverage files is a valid thing, so the exit code is 0
  887. return 0;
  888. }
  889. std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
  890. std::string tempDir = testingDir + "/CoverageInfo";
  891. std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
  892. cmSystemTools::MakeDirectory(tempDir.c_str());
  893. cmSystemTools::ChangeDirectory(tempDir);
  894. int gcovStyle = 0;
  895. std::set<std::string> missingFiles;
  896. std::string actualSourceFile = "";
  897. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  898. " Processing coverage (each . represents one file):" << std::endl);
  899. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  900. int file_count = 0;
  901. // make sure output from gcov is in English!
  902. cmCTestCoverageHandlerLocale locale_C;
  903. static_cast<void>(locale_C);
  904. // files is a list of *.da and *.gcda files with coverage data in them.
  905. // These are binary files that you give as input to gcov so that it will
  906. // give us text output we can analyze to summarize coverage.
  907. //
  908. for ( it = files.begin(); it != files.end(); ++ it )
  909. {
  910. cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
  911. // Call gcov to get coverage data for this *.gcda file:
  912. //
  913. std::string fileDir = cmSystemTools::GetFilenamePath(*it);
  914. std::string command = "\"" + gcovCommand + "\" " +
  915. gcovExtraFlags + " " +
  916. "-o \"" + fileDir + "\" " +
  917. "\"" + *it + "\"";
  918. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, command.c_str()
  919. << std::endl);
  920. std::string output = "";
  921. std::string errors = "";
  922. int retVal = 0;
  923. *cont->OFS << "* Run coverage for: " << fileDir << std::endl;
  924. *cont->OFS << " Command: " << command << std::endl;
  925. int res = this->CTest->RunCommand(command.c_str(), &output, &errors,
  926. &retVal, tempDir.c_str(), 0 /*this->TimeOut*/);
  927. *cont->OFS << " Output: " << output << std::endl;
  928. *cont->OFS << " Errors: " << errors << std::endl;
  929. if ( ! res )
  930. {
  931. cmCTestLog(this->CTest, ERROR_MESSAGE,
  932. "Problem running coverage on file: " << *it << std::endl);
  933. cmCTestLog(this->CTest, ERROR_MESSAGE,
  934. "Command produced error: " << errors << std::endl);
  935. cont->Error ++;
  936. continue;
  937. }
  938. if ( retVal != 0 )
  939. {
  940. cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
  941. << retVal << " while processing: " << *it << std::endl);
  942. cmCTestLog(this->CTest, ERROR_MESSAGE,
  943. "Command produced error: " << cont->Error << std::endl);
  944. }
  945. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  946. "--------------------------------------------------------------"
  947. << std::endl
  948. << output << std::endl
  949. << "--------------------------------------------------------------"
  950. << std::endl);
  951. std::vector<std::string> lines;
  952. std::vector<std::string>::iterator line;
  953. cmSystemTools::Split(output.c_str(), lines);
  954. for ( line = lines.begin(); line != lines.end(); ++line)
  955. {
  956. std::string sourceFile;
  957. std::string gcovFile;
  958. cmCTestLog(this->CTest, DEBUG, "Line: [" << *line << "]"
  959. << std::endl);
  960. if ( line->size() == 0 )
  961. {
  962. // Ignore empty line; probably style 2
  963. }
  964. else if ( st1re1.find(line->c_str()) )
  965. {
  966. if ( gcovStyle == 0 )
  967. {
  968. gcovStyle = 1;
  969. }
  970. if ( gcovStyle != 1 )
  971. {
  972. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e1"
  973. << std::endl);
  974. cont->Error ++;
  975. break;
  976. }
  977. actualSourceFile = "";
  978. sourceFile = st1re1.match(2);
  979. }
  980. else if ( st1re2.find(line->c_str() ) )
  981. {
  982. if ( gcovStyle == 0 )
  983. {
  984. gcovStyle = 1;
  985. }
  986. if ( gcovStyle != 1 )
  987. {
  988. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e2"
  989. << std::endl);
  990. cont->Error ++;
  991. break;
  992. }
  993. gcovFile = st1re2.match(1);
  994. }
  995. else if ( st2re1.find(line->c_str() ) )
  996. {
  997. if ( gcovStyle == 0 )
  998. {
  999. gcovStyle = 2;
  1000. }
  1001. if ( gcovStyle != 2 )
  1002. {
  1003. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e3"
  1004. << std::endl);
  1005. cont->Error ++;
  1006. break;
  1007. }
  1008. actualSourceFile = "";
  1009. sourceFile = st2re1.match(1);
  1010. }
  1011. else if ( st2re2.find(line->c_str() ) )
  1012. {
  1013. if ( gcovStyle == 0 )
  1014. {
  1015. gcovStyle = 2;
  1016. }
  1017. if ( gcovStyle != 2 )
  1018. {
  1019. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e4"
  1020. << std::endl);
  1021. cont->Error ++;
  1022. break;
  1023. }
  1024. }
  1025. else if ( st2re3.find(line->c_str() ) )
  1026. {
  1027. if ( gcovStyle == 0 )
  1028. {
  1029. gcovStyle = 2;
  1030. }
  1031. if ( gcovStyle != 2 )
  1032. {
  1033. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e5"
  1034. << std::endl);
  1035. cont->Error ++;
  1036. break;
  1037. }
  1038. gcovFile = st2re3.match(2);
  1039. }
  1040. else if ( st2re4.find(line->c_str() ) )
  1041. {
  1042. if ( gcovStyle == 0 )
  1043. {
  1044. gcovStyle = 2;
  1045. }
  1046. if ( gcovStyle != 2 )
  1047. {
  1048. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e6"
  1049. << std::endl);
  1050. cont->Error ++;
  1051. break;
  1052. }
  1053. cmCTestLog(this->CTest, WARNING, "Warning: " << st2re4.match(1)
  1054. << " had unexpected EOF" << std::endl);
  1055. }
  1056. else if ( st2re5.find(line->c_str() ) )
  1057. {
  1058. if ( gcovStyle == 0 )
  1059. {
  1060. gcovStyle = 2;
  1061. }
  1062. if ( gcovStyle != 2 )
  1063. {
  1064. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e7"
  1065. << std::endl);
  1066. cont->Error ++;
  1067. break;
  1068. }
  1069. cmCTestLog(this->CTest, WARNING, "Warning: Cannot open file: "
  1070. << st2re5.match(1) << std::endl);
  1071. }
  1072. else if ( st2re6.find(line->c_str() ) )
  1073. {
  1074. if ( gcovStyle == 0 )
  1075. {
  1076. gcovStyle = 2;
  1077. }
  1078. if ( gcovStyle != 2 )
  1079. {
  1080. cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e8"
  1081. << std::endl);
  1082. cont->Error ++;
  1083. break;
  1084. }
  1085. cmCTestLog(this->CTest, WARNING, "Warning: File: " << st2re6.match(1)
  1086. << " is newer than " << st2re6.match(2) << std::endl);
  1087. }
  1088. else
  1089. {
  1090. // gcov 4.7 can have output lines saying "No executable lines" and
  1091. // "Removing 'filename.gcov'"... Don't log those as "errors."
  1092. if(*line != "No executable lines" &&
  1093. !cmSystemTools::StringStartsWith(line->c_str(), "Removing "))
  1094. {
  1095. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1096. "Unknown gcov output line: [" << *line << "]"
  1097. << std::endl);
  1098. cont->Error ++;
  1099. //abort();
  1100. }
  1101. }
  1102. // If the last line of gcov output gave us a valid value for gcovFile,
  1103. // and we have an actualSourceFile, then insert a (or add to existing)
  1104. // SingleFileCoverageVector for actualSourceFile:
  1105. //
  1106. if ( !gcovFile.empty() && !actualSourceFile.empty() )
  1107. {
  1108. cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec
  1109. = cont->TotalCoverage[actualSourceFile];
  1110. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in gcovFile: "
  1111. << gcovFile << std::endl);
  1112. cmsys::ifstream ifile(gcovFile.c_str());
  1113. if ( ! ifile )
  1114. {
  1115. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
  1116. << gcovFile << std::endl);
  1117. }
  1118. else
  1119. {
  1120. long cnt = -1;
  1121. std::string nl;
  1122. while ( cmSystemTools::GetLineFromStream(ifile, nl) )
  1123. {
  1124. cnt ++;
  1125. //TODO: Handle gcov 3.0 non-coverage lines
  1126. // Skip empty lines
  1127. if ( !nl.size() )
  1128. {
  1129. continue;
  1130. }
  1131. // Skip unused lines
  1132. if ( nl.size() < 12 )
  1133. {
  1134. continue;
  1135. }
  1136. // Read the coverage count from the beginning of the gcov output
  1137. // line
  1138. std::string prefix = nl.substr(0, 12);
  1139. int cov = atoi(prefix.c_str());
  1140. // Read the line number starting at the 10th character of the gcov
  1141. // output line
  1142. std::string lineNumber = nl.substr(10, 5);
  1143. int lineIdx = atoi(lineNumber.c_str())-1;
  1144. if ( lineIdx >= 0 )
  1145. {
  1146. while ( vec.size() <= static_cast<size_t>(lineIdx) )
  1147. {
  1148. vec.push_back(-1);
  1149. }
  1150. // Initially all entries are -1 (not used). If we get coverage
  1151. // information, increment it to 0 first.
  1152. if ( vec[lineIdx] < 0 )
  1153. {
  1154. if ( cov > 0 || prefix.find("#") != prefix.npos )
  1155. {
  1156. vec[lineIdx] = 0;
  1157. }
  1158. }
  1159. vec[lineIdx] += cov;
  1160. }
  1161. }
  1162. }
  1163. actualSourceFile = "";
  1164. }
  1165. if ( !sourceFile.empty() && actualSourceFile.empty() )
  1166. {
  1167. gcovFile = "";
  1168. // Is it in the source dir or the binary dir?
  1169. //
  1170. if ( IsFileInDir(sourceFile, cont->SourceDir) )
  1171. {
  1172. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced s: "
  1173. << sourceFile << std::endl);
  1174. *cont->OFS << " produced in source dir: " << sourceFile
  1175. << std::endl;
  1176. actualSourceFile
  1177. = cmSystemTools::CollapseFullPath(sourceFile);
  1178. }
  1179. else if ( IsFileInDir(sourceFile, cont->BinaryDir) )
  1180. {
  1181. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced b: "
  1182. << sourceFile << std::endl);
  1183. *cont->OFS << " produced in binary dir: " << sourceFile
  1184. << std::endl;
  1185. actualSourceFile
  1186. = cmSystemTools::CollapseFullPath(sourceFile);
  1187. }
  1188. if ( actualSourceFile.empty() )
  1189. {
  1190. if ( missingFiles.find(sourceFile) == missingFiles.end() )
  1191. {
  1192. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1193. "Something went wrong" << std::endl);
  1194. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1195. "Cannot find file: ["
  1196. << sourceFile << "]" << std::endl);
  1197. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1198. " in source dir: ["
  1199. << cont->SourceDir << "]"
  1200. << std::endl);
  1201. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1202. " or binary dir: ["
  1203. << cont->BinaryDir.size() << "]"
  1204. << std::endl);
  1205. *cont->OFS << " Something went wrong. Cannot find file: "
  1206. << sourceFile
  1207. << " in source dir: " << cont->SourceDir
  1208. << " or binary dir: " << cont->BinaryDir << std::endl;
  1209. missingFiles.insert(sourceFile);
  1210. }
  1211. }
  1212. }
  1213. }
  1214. file_count++;
  1215. if ( file_count % 50 == 0 )
  1216. {
  1217. cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
  1218. << " out of " << files.size() << std::endl);
  1219. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  1220. }
  1221. }
  1222. cmSystemTools::ChangeDirectory(currentDirectory);
  1223. return file_count;
  1224. }
  1225. //----------------------------------------------------------------------
  1226. int cmCTestCoverageHandler::HandleLCovCoverage(
  1227. cmCTestCoverageHandlerContainer* cont)
  1228. {
  1229. std::string lcovCommand
  1230. = this->CTest->GetCTestConfiguration("CoverageCommand");
  1231. std::string lcovExtraFlags
  1232. = this->CTest->GetCTestConfiguration("CoverageExtraFlags");
  1233. if ( lcovCommand != "codecov" )
  1234. {
  1235. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1236. " Not a valid Intel Coverage command."
  1237. << std::endl);
  1238. return 0;
  1239. }
  1240. // There is only percentage completed output from LCOV
  1241. std::string st2lcovOutputRex3 = "[0-9]+%";
  1242. cmsys::RegularExpression st2re3(st2lcovOutputRex3.c_str());
  1243. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1244. " This is coverage command: " << lcovCommand
  1245. << std::endl);
  1246. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1247. " These are coverage command flags: " << lcovExtraFlags
  1248. << std::endl);
  1249. std::vector<std::string> files;
  1250. this->FindLCovFiles(files);
  1251. std::vector<std::string>::iterator it;
  1252. if ( files.size() == 0 )
  1253. {
  1254. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1255. " Cannot find any LCov coverage files."
  1256. << std::endl);
  1257. // No coverage files is a valid thing, so the exit code is 0
  1258. return 0;
  1259. }
  1260. std::string testingDir = this->CTest->GetBinaryDir();
  1261. std::string tempDir = testingDir;
  1262. std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
  1263. std::set<std::string> missingFiles;
  1264. std::string actualSourceFile = "";
  1265. cmCTestLog(this->CTest, HANDLER_OUTPUT,
  1266. " Processing coverage (each . represents one file):" << std::endl);
  1267. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  1268. int file_count = 0;
  1269. // make sure output from lcov is in English!
  1270. cmCTestCoverageHandlerLocale locale_C;
  1271. static_cast<void>(locale_C);
  1272. // In intel compiler we have to call codecov only once in each executable
  1273. // directory. It collects all *.dyn files to generate .dpi file.
  1274. for ( it = files.begin(); it != files.end(); ++ it )
  1275. {
  1276. cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
  1277. std::string fileDir = cmSystemTools::GetFilenamePath(*it);
  1278. cmSystemTools::ChangeDirectory(fileDir);
  1279. std::string command = "\"" + lcovCommand + "\" " +
  1280. lcovExtraFlags + " ";
  1281. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Current coverage dir: "
  1282. << fileDir.c_str() << std::endl);
  1283. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, command.c_str()
  1284. << std::endl);
  1285. std::string output = "";
  1286. std::string errors = "";
  1287. int retVal = 0;
  1288. *cont->OFS << "* Run coverage for: " << fileDir.c_str() << std::endl;
  1289. *cont->OFS << " Command: " << command.c_str() << std::endl;
  1290. int res = this->CTest->RunCommand(command.c_str(), &output, &errors,
  1291. &retVal, fileDir.c_str(), 0 /*this->TimeOut*/);
  1292. *cont->OFS << " Output: " << output.c_str() << std::endl;
  1293. *cont->OFS << " Errors: " << errors.c_str() << std::endl;
  1294. if ( ! res )
  1295. {
  1296. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1297. "Problem running coverage on file: " << it->c_str() << std::endl);
  1298. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1299. "Command produced error: " << errors << std::endl);
  1300. cont->Error ++;
  1301. continue;
  1302. }
  1303. if ( retVal != 0 )
  1304. {
  1305. cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
  1306. << retVal << " while processing: " << it->c_str() << std::endl);
  1307. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1308. "Command produced error: " << cont->Error << std::endl);
  1309. }
  1310. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1311. "--------------------------------------------------------------"
  1312. << std::endl
  1313. << output << std::endl
  1314. << "--------------------------------------------------------------"
  1315. << std::endl);
  1316. std::vector<std::string> lines;
  1317. std::vector<std::string>::iterator line;
  1318. cmSystemTools::Split(output.c_str(), lines);
  1319. for ( line = lines.begin(); line != lines.end(); ++line)
  1320. {
  1321. std::string sourceFile;
  1322. std::string lcovFile;
  1323. if ( line->size() == 0 )
  1324. {
  1325. // Ignore empty line
  1326. }
  1327. // Look for LCOV files in binary directory
  1328. // Intel Compiler creates a CodeCoverage dir for each subfolder and
  1329. // each subfolder has LCOV files
  1330. cmsys::Glob gl;
  1331. gl.RecurseOn();
  1332. gl.RecurseThroughSymlinksOff();
  1333. std::string dir;
  1334. std::vector<std::string> lcovFiles;
  1335. dir = this->CTest->GetBinaryDir();
  1336. std::string daGlob;
  1337. daGlob = dir;
  1338. daGlob += "/*.LCOV";
  1339. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1340. " looking for LCOV files in: " << daGlob << std::endl);
  1341. gl.FindFiles(daGlob);
  1342. // Keep a list of all LCOV files
  1343. lcovFiles.insert(lcovFiles.end(), gl.GetFiles().begin(),
  1344. gl.GetFiles().end());
  1345. for(std::vector<std::string>::iterator a = lcovFiles.begin();
  1346. a != lcovFiles.end(); ++a)
  1347. {
  1348. lcovFile = *a;
  1349. cmsys::ifstream srcead(lcovFile.c_str());
  1350. if ( ! srcead )
  1351. {
  1352. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
  1353. << lcovFile << std::endl);
  1354. }
  1355. std::string srcname;
  1356. int success = cmSystemTools::GetLineFromStream(srcead, srcname);
  1357. if ( !success )
  1358. {
  1359. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1360. "Error while parsing lcov file '" << lcovFile << "':"
  1361. << " No source file name found!" << std::endl);
  1362. return 0;
  1363. }
  1364. srcname = srcname.substr(18);
  1365. // We can directly read found LCOV files to determine the source
  1366. // files
  1367. sourceFile = srcname;
  1368. actualSourceFile = srcname;
  1369. for(std::vector<std::string>::iterator t = lcovFiles.begin();
  1370. t != lcovFiles.end(); ++t)
  1371. {
  1372. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found LCOV File: "
  1373. << *t << std::endl);
  1374. }
  1375. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "SourceFile: "
  1376. << sourceFile << std::endl);
  1377. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "lCovFile: "
  1378. << lcovFile << std::endl);
  1379. // If we have some LCOV files to process
  1380. if ( !lcovFile.empty() && !actualSourceFile.empty() )
  1381. {
  1382. cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec
  1383. = cont->TotalCoverage[actualSourceFile];
  1384. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in lcovFile: "
  1385. << lcovFile << std::endl);
  1386. cmsys::ifstream ifile(lcovFile.c_str());
  1387. if ( ! ifile )
  1388. {
  1389. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
  1390. << lcovFile << std::endl);
  1391. }
  1392. else
  1393. {
  1394. long cnt = -1;
  1395. std::string nl;
  1396. // Skip the first line
  1397. cmSystemTools::GetLineFromStream(ifile, nl);
  1398. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1399. "File is ready, start reading." << std::endl);
  1400. while ( cmSystemTools::GetLineFromStream(ifile, nl) )
  1401. {
  1402. cnt ++;
  1403. // Skip empty lines
  1404. if ( !nl.size() )
  1405. {
  1406. continue;
  1407. }
  1408. // Skip unused lines
  1409. if ( nl.size() < 12 )
  1410. {
  1411. continue;
  1412. }
  1413. // Read the coverage count from the beginning of the lcov
  1414. // output line
  1415. std::string prefix = nl.substr(0, 17);
  1416. int cov = atoi(prefix.c_str());
  1417. // Read the line number starting at the 17th character of the
  1418. // lcov output line
  1419. std::string lineNumber = nl.substr(17, 7);
  1420. int lineIdx = atoi(lineNumber.c_str())-1;
  1421. if ( lineIdx >= 0 )
  1422. {
  1423. while ( vec.size() <= static_cast<size_t>(lineIdx) )
  1424. {
  1425. vec.push_back(-1);
  1426. }
  1427. // Initially all entries are -1 (not used). If we get coverage
  1428. // information, increment it to 0 first.
  1429. if ( vec[lineIdx] < 0 )
  1430. {
  1431. if ( cov > 0 || prefix.find("#") != prefix.npos )
  1432. {
  1433. vec[lineIdx] = 0;
  1434. }
  1435. }
  1436. vec[lineIdx] += cov;
  1437. }
  1438. }
  1439. }
  1440. actualSourceFile = "";
  1441. }
  1442. }
  1443. }
  1444. file_count++;
  1445. if ( file_count % 50 == 0 )
  1446. {
  1447. cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
  1448. << " out of " << files.size() << std::endl);
  1449. cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
  1450. }
  1451. }
  1452. cmSystemTools::ChangeDirectory(currentDirectory);
  1453. return file_count;
  1454. }
  1455. //----------------------------------------------------------------------------
  1456. void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
  1457. {
  1458. cmsys::Glob gl;
  1459. gl.RecurseOn();
  1460. gl.RecurseThroughSymlinksOff();
  1461. for(LabelMapType::const_iterator lmi = this->TargetDirs.begin();
  1462. lmi != this->TargetDirs.end(); ++lmi)
  1463. {
  1464. // Skip targets containing no interesting labels.
  1465. if(!this->IntersectsFilter(lmi->second))
  1466. {
  1467. continue;
  1468. }
  1469. // Coverage files appear next to their object files in the target
  1470. // support directory.
  1471. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1472. " globbing for coverage in: " << lmi->first << std::endl);
  1473. std::string daGlob = lmi->first;
  1474. daGlob += "/*.da";
  1475. gl.FindFiles(daGlob);
  1476. files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
  1477. daGlob = lmi->first;
  1478. daGlob += "/*.gcda";
  1479. gl.FindFiles(daGlob);
  1480. files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
  1481. }
  1482. }
  1483. //----------------------------------------------------------------------------
  1484. void cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
  1485. {
  1486. cmsys::Glob gl;
  1487. gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is
  1488. // used while compiling.
  1489. gl.RecurseThroughSymlinksOff();
  1490. std::string prevBinaryDir;
  1491. cmSystemTools::ChangeDirectory(
  1492. this->CTest->GetCTestConfiguration("BuildDirectory"));
  1493. // Run profmerge to merge all *.dyn files into dpi files
  1494. cmSystemTools::RunSingleCommand("profmerge");
  1495. prevBinaryDir = cmSystemTools::GetCurrentWorkingDirectory().c_str();
  1496. // DPI file should appear in build directory
  1497. std::string daGlob;
  1498. daGlob = prevBinaryDir;
  1499. daGlob += "/*.dpi";
  1500. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1501. " looking for dpi files in: " << daGlob << std::endl);
  1502. gl.FindFiles(daGlob);
  1503. files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
  1504. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1505. "Now searching in: " << daGlob << std::endl);
  1506. }
  1507. //----------------------------------------------------------------------
  1508. int cmCTestCoverageHandler::HandleTracePyCoverage(
  1509. cmCTestCoverageHandlerContainer* cont)
  1510. {
  1511. cmsys::Glob gl;
  1512. gl.RecurseOn();
  1513. gl.RecurseThroughSymlinksOff();
  1514. std::string daGlob = cont->BinaryDir + "/*.cover";
  1515. gl.FindFiles(daGlob);
  1516. std::vector<std::string> files = gl.GetFiles();
  1517. if ( files.size() == 0 )
  1518. {
  1519. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1520. " Cannot find any Python Trace.py coverage files."
  1521. << std::endl);
  1522. // No coverage files is a valid thing, so the exit code is 0
  1523. return 0;
  1524. }
  1525. std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
  1526. std::string tempDir = testingDir + "/CoverageInfo";
  1527. std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
  1528. cmSystemTools::MakeDirectory(tempDir.c_str());
  1529. cmSystemTools::ChangeDirectory(tempDir);
  1530. cmSystemTools::ChangeDirectory(currentDirectory);
  1531. std::vector<std::string>::iterator fileIt;
  1532. int file_count = 0;
  1533. for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
  1534. {
  1535. std::string fileName = this->FindFile(cont, *fileIt);
  1536. if ( fileName.empty() )
  1537. {
  1538. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1539. "Cannot find source Python file corresponding to: "
  1540. << *fileIt << std::endl);
  1541. continue;
  1542. }
  1543. std::string actualSourceFile
  1544. = cmSystemTools::CollapseFullPath(fileName);
  1545. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1546. " Check coverage for file: " << actualSourceFile
  1547. << std::endl);
  1548. cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec
  1549. = &cont->TotalCoverage[actualSourceFile];
  1550. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1551. " in file: " << *fileIt << std::endl);
  1552. cmsys::ifstream ifile(fileIt->c_str());
  1553. if ( ! ifile )
  1554. {
  1555. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
  1556. << *fileIt << std::endl);
  1557. }
  1558. else
  1559. {
  1560. long cnt = -1;
  1561. std::string nl;
  1562. while ( cmSystemTools::GetLineFromStream(ifile, nl) )
  1563. {
  1564. cnt ++;
  1565. // Skip empty lines
  1566. if ( !nl.size() )
  1567. {
  1568. continue;
  1569. }
  1570. // Skip unused lines
  1571. if ( nl.size() < 12 )
  1572. {
  1573. continue;
  1574. }
  1575. // Read the coverage count from the beginning of the Trace.py output
  1576. // line
  1577. std::string prefix = nl.substr(0, 6);
  1578. if ( prefix[5] != ' ' && prefix[5] != ':' )
  1579. {
  1580. // This is a hack. We should really do something more elaborate
  1581. prefix = nl.substr(0, 7);
  1582. if ( prefix[6] != ' ' && prefix[6] != ':' )
  1583. {
  1584. prefix = nl.substr(0, 8);
  1585. if ( prefix[7] != ' ' && prefix[7] != ':' )
  1586. {
  1587. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1588. "Currently the limit is maximum coverage of 999999"
  1589. << std::endl);
  1590. }
  1591. }
  1592. }
  1593. int cov = atoi(prefix.c_str());
  1594. if ( prefix[prefix.size()-1] != ':' )
  1595. {
  1596. // This line does not have ':' so no coverage here. That said,
  1597. // Trace.py does not handle not covered lines versus comments etc.
  1598. // So, this will be set to 0.
  1599. cov = 0;
  1600. }
  1601. cmCTestLog(this->CTest, DEBUG, "Prefix: " << prefix
  1602. << " cov: " << cov
  1603. << std::endl);
  1604. // Read the line number starting at the 10th character of the gcov
  1605. // output line
  1606. long lineIdx = cnt;
  1607. if ( lineIdx >= 0 )
  1608. {
  1609. while ( vec->size() <=
  1610. static_cast<size_t>(lineIdx) )
  1611. {
  1612. vec->push_back(-1);
  1613. }
  1614. // Initially all entries are -1 (not used). If we get coverage
  1615. // information, increment it to 0 first.
  1616. if ( (*vec)[lineIdx] < 0 )
  1617. {
  1618. if ( cov >= 0 )
  1619. {
  1620. (*vec)[lineIdx] = 0;
  1621. }
  1622. }
  1623. (*vec)[lineIdx] += cov;
  1624. }
  1625. }
  1626. }
  1627. ++ file_count;
  1628. }
  1629. cmSystemTools::ChangeDirectory(currentDirectory);
  1630. return file_count;
  1631. }
  1632. //----------------------------------------------------------------------
  1633. std::string cmCTestCoverageHandler::FindFile(
  1634. cmCTestCoverageHandlerContainer* cont,
  1635. std::string fileName)
  1636. {
  1637. std::string fileNameNoE
  1638. = cmSystemTools::GetFilenameWithoutLastExtension(fileName);
  1639. // First check in source and binary directory
  1640. std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";
  1641. if ( cmSystemTools::FileExists(fullName.c_str()) )
  1642. {
  1643. return fullName;
  1644. }
  1645. fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";
  1646. if ( cmSystemTools::FileExists(fullName.c_str()) )
  1647. {
  1648. return fullName;
  1649. }
  1650. return "";
  1651. }
  1652. // This is a header put on each marked up source file
  1653. namespace
  1654. {
  1655. const char* bullseyeHelp[] =
  1656. {" Coverage produced by bullseye covbr tool: ",
  1657. " www.bullseye.com/help/ref_covbr.html",
  1658. " * An arrow --> indicates incomplete coverage.",
  1659. " * An X indicates a function that was invoked, a switch label that ",
  1660. " was exercised, a try-block that finished, or an exception handler ",
  1661. " that was invoked.",
  1662. " * A T or F indicates a boolean decision that evaluated true or false,",
  1663. " respectively.",
  1664. " * A t or f indicates a boolean condition within a decision if the ",
  1665. " condition evaluated true or false, respectively.",
  1666. " * A k indicates a constant decision or condition.",
  1667. " * The slash / means this probe is excluded from summary results. ",
  1668. 0};
  1669. }
  1670. //----------------------------------------------------------------------
  1671. int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
  1672. cmCTestCoverageHandlerContainer* cont,
  1673. std::set<std::string>& coveredFileNames,
  1674. std::vector<std::string>& files,
  1675. std::vector<std::string>& filesFullPath)
  1676. {
  1677. if(files.size() != filesFullPath.size())
  1678. {
  1679. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1680. "Files and full path files not the same size?:\n");
  1681. return 0;
  1682. }
  1683. // create the output stream for the CoverageLog-N.xml file
  1684. cmGeneratedFileStream covLogFile;
  1685. int logFileCount = 0;
  1686. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  1687. {
  1688. return -1;
  1689. }
  1690. // for each file run covbr on that file to get the coverage
  1691. // information for that file
  1692. std::string outputFile;
  1693. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1694. "run covbr: "
  1695. << std::endl);
  1696. if(!this->RunBullseyeCommand(cont, "covbr", 0, outputFile))
  1697. {
  1698. cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covbr for." << "\n");
  1699. return -1;
  1700. }
  1701. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1702. "covbr output in " << outputFile
  1703. << std::endl);
  1704. // open the output file
  1705. cmsys::ifstream fin(outputFile.c_str());
  1706. if(!fin)
  1707. {
  1708. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1709. "Cannot open coverage file: " <<
  1710. outputFile << std::endl);
  1711. return 0;
  1712. }
  1713. std::map<std::string, std::string> fileMap;
  1714. std::vector<std::string>::iterator fp = filesFullPath.begin();
  1715. for(std::vector<std::string>::iterator f = files.begin();
  1716. f != files.end(); ++f, ++fp)
  1717. {
  1718. fileMap[*f] = *fp;
  1719. }
  1720. int count =0; // keep count of the number of files
  1721. // Now parse each line from the bullseye cov log file
  1722. std::string lineIn;
  1723. bool valid = false; // are we in a valid output file
  1724. int line = 0; // line of the current file
  1725. std::string file;
  1726. while(cmSystemTools::GetLineFromStream(fin, lineIn))
  1727. {
  1728. bool startFile = false;
  1729. if(lineIn.size() > 1 && lineIn[lineIn.size()-1] == ':')
  1730. {
  1731. file = lineIn.substr(0, lineIn.size()-1);
  1732. if(coveredFileNames.find(file) != coveredFileNames.end())
  1733. {
  1734. startFile = true;
  1735. }
  1736. }
  1737. if(startFile)
  1738. {
  1739. // if we are in a valid file close it because a new one started
  1740. if(valid)
  1741. {
  1742. covLogFile << "\t\t</Report>" << std::endl
  1743. << "\t</File>" << std::endl;
  1744. }
  1745. // only allow 100 files in each log file
  1746. if ( count != 0 && count % 100 == 0 )
  1747. {
  1748. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1749. "start a new log file: "
  1750. << count
  1751. << std::endl);
  1752. this->EndCoverageLogFile(covLogFile, logFileCount);
  1753. logFileCount ++;
  1754. if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
  1755. {
  1756. return -1;
  1757. }
  1758. count++; // move on one
  1759. }
  1760. std::map<std::string, std::string>::iterator
  1761. i = fileMap.find(file);
  1762. // if the file should be covered write out the header for that file
  1763. if(i != fileMap.end())
  1764. {
  1765. // we have a new file so count it in the output
  1766. count++;
  1767. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1768. "Produce coverage for file: "
  1769. << file << " " << count
  1770. << std::endl);
  1771. // start the file output
  1772. covLogFile << "\t<File Name=\""
  1773. << cmXMLSafe(i->first)
  1774. << "\" FullPath=\"" << cmXMLSafe(
  1775. this->CTest->GetShortPathToFile(
  1776. i->second.c_str())) << "\">" << std::endl
  1777. << "\t\t<Report>" << std::endl;
  1778. // write the bullseye header
  1779. line =0;
  1780. for(int k =0; bullseyeHelp[k] != 0; ++k)
  1781. {
  1782. covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"
  1783. << cmXMLSafe(bullseyeHelp[k])
  1784. << "</Line>" << std::endl;
  1785. line++;
  1786. }
  1787. valid = true; // we are in a valid file section
  1788. }
  1789. else
  1790. {
  1791. // this is not a file that we want coverage for
  1792. valid = false;
  1793. }
  1794. }
  1795. // we are not at a start file, and we are in a valid file output the line
  1796. else if(valid)
  1797. {
  1798. covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"
  1799. << cmXMLSafe(lineIn)
  1800. << "</Line>" << std::endl;
  1801. line++;
  1802. }
  1803. }
  1804. // if we ran out of lines a valid file then close that file
  1805. if(valid)
  1806. {
  1807. covLogFile << "\t\t</Report>" << std::endl
  1808. << "\t</File>" << std::endl;
  1809. }
  1810. this->EndCoverageLogFile(covLogFile, logFileCount);
  1811. return 1;
  1812. }
  1813. //----------------------------------------------------------------------
  1814. int cmCTestCoverageHandler::RunBullseyeCommand(
  1815. cmCTestCoverageHandlerContainer* cont,
  1816. const char* cmd,
  1817. const char* arg,
  1818. std::string& outputFile)
  1819. {
  1820. std::string program = cmSystemTools::FindProgram(cmd);
  1821. if(program.size() == 0)
  1822. {
  1823. cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
  1824. return 0;
  1825. }
  1826. if(arg)
  1827. {
  1828. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1829. "Run : " << program << " " << arg << "\n");
  1830. }
  1831. else
  1832. {
  1833. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1834. "Run : " << program << "\n");
  1835. }
  1836. // create a process object and start it
  1837. cmCTestRunProcess runCoverageSrc;
  1838. runCoverageSrc.SetCommand(program.c_str());
  1839. runCoverageSrc.AddArgument(arg);
  1840. std::string stdoutFile = cont->BinaryDir + "/Testing/Temporary/";
  1841. stdoutFile += this->GetCTestInstance()->GetCurrentTag();
  1842. stdoutFile += "-";
  1843. stdoutFile += cmd;
  1844. std::string stderrFile = stdoutFile;
  1845. stdoutFile += ".stdout";
  1846. stderrFile += ".stderr";
  1847. runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
  1848. runCoverageSrc.SetStderrFile(stderrFile.c_str());
  1849. if(!runCoverageSrc.StartProcess())
  1850. {
  1851. cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not run : "
  1852. << program << " " << arg << "\n"
  1853. << "kwsys process state : "
  1854. << runCoverageSrc.GetProcessState());
  1855. return 0;
  1856. }
  1857. // since we set the output file names wait for it to end
  1858. runCoverageSrc.WaitForExit();
  1859. outputFile = stdoutFile;
  1860. return 1;
  1861. }
  1862. //----------------------------------------------------------------------
  1863. int cmCTestCoverageHandler::RunBullseyeSourceSummary(
  1864. cmCTestCoverageHandlerContainer* cont)
  1865. {
  1866. // Run the covsrc command and create a temp outputfile
  1867. std::string outputFile;
  1868. if(!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile))
  1869. {
  1870. cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covsrc:\n");
  1871. return 0;
  1872. }
  1873. std::ostream& tmpLog = *cont->OFS;
  1874. // copen the Coverage.xml file in the Testing directory
  1875. cmGeneratedFileStream covSumFile;
  1876. if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))
  1877. {
  1878. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1879. "Cannot open coverage summary file." << std::endl);
  1880. return 0;
  1881. }
  1882. this->CTest->StartXML(covSumFile, this->AppendXML);
  1883. double elapsed_time_start = cmSystemTools::GetTime();
  1884. std::string coverage_start_time = this->CTest->CurrentTime();
  1885. covSumFile << "<Coverage>" << std::endl
  1886. << "\t<StartDateTime>"
  1887. << coverage_start_time << "</StartDateTime>"
  1888. << std::endl
  1889. << "\t<StartTime>"
  1890. << static_cast<unsigned int>(cmSystemTools::GetTime())
  1891. << "</StartTime>"
  1892. << std::endl;
  1893. std::string stdline;
  1894. std::string errline;
  1895. // expected output:
  1896. // first line is:
  1897. // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"
  1898. // after that data follows in that format
  1899. std::string sourceFile;
  1900. int functionsCalled = 0;
  1901. int totalFunctions = 0;
  1902. int percentFunction = 0;
  1903. int branchCovered = 0;
  1904. int totalBranches = 0;
  1905. int percentBranch = 0;
  1906. double total_tested = 0;
  1907. double total_untested = 0;
  1908. double total_functions = 0;
  1909. double percent_coverage =0;
  1910. double number_files = 0;
  1911. std::vector<std::string> coveredFiles;
  1912. std::vector<std::string> coveredFilesFullPath;
  1913. // Read and parse the summary output file
  1914. cmsys::ifstream fin(outputFile.c_str());
  1915. if(!fin)
  1916. {
  1917. cmCTestLog(this->CTest, ERROR_MESSAGE,
  1918. "Cannot open coverage summary file: " <<
  1919. outputFile << std::endl);
  1920. return 0;
  1921. }
  1922. std::set<std::string> coveredFileNames;
  1923. while(cmSystemTools::GetLineFromStream(fin, stdline))
  1924. {
  1925. // if we have a line of output from stdout
  1926. if(stdline.size())
  1927. {
  1928. // parse the comma separated output
  1929. this->ParseBullsEyeCovsrcLine(stdline,
  1930. sourceFile,
  1931. functionsCalled,
  1932. totalFunctions,
  1933. percentFunction,
  1934. branchCovered,
  1935. totalBranches,
  1936. percentBranch);
  1937. // The first line is the header
  1938. if(sourceFile == "Source" || sourceFile == "Total")
  1939. {
  1940. continue;
  1941. }
  1942. std::string file = sourceFile;
  1943. coveredFileNames.insert(file);
  1944. if(!cmSystemTools::FileIsFullPath(sourceFile.c_str()))
  1945. {
  1946. // file will be relative to the binary dir
  1947. file = cont->BinaryDir;
  1948. file += "/";
  1949. file += sourceFile;
  1950. }
  1951. file = cmSystemTools::CollapseFullPath(file);
  1952. bool shouldIDoCoverage
  1953. = this->ShouldIDoCoverage(file.c_str(),
  1954. cont->SourceDir.c_str(),
  1955. cont->BinaryDir.c_str());
  1956. if ( !shouldIDoCoverage )
  1957. {
  1958. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1959. ".NoDartCoverage found, so skip coverage check for: "
  1960. << file
  1961. << std::endl);
  1962. continue;
  1963. }
  1964. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  1965. "Doing coverage for: "
  1966. << file
  1967. << std::endl);
  1968. coveredFiles.push_back(sourceFile);
  1969. coveredFilesFullPath.push_back(file);
  1970. number_files++;
  1971. total_functions += totalFunctions;
  1972. total_tested += functionsCalled;
  1973. total_untested += (totalFunctions - functionsCalled);
  1974. std::string fileName = cmSystemTools::GetFilenameName(file);
  1975. std::string shortFileName =
  1976. this->CTest->GetShortPathToFile(file.c_str());
  1977. float cper = static_cast<float>(percentBranch + percentFunction);
  1978. if(totalBranches > 0)
  1979. {
  1980. cper /= 2.0f;
  1981. }
  1982. percent_coverage += cper;
  1983. float cmet = static_cast<float>(percentFunction + percentBranch);
  1984. if(totalBranches > 0)
  1985. {
  1986. cmet /= 2.0f;
  1987. }
  1988. cmet /= 100.0f;
  1989. tmpLog << stdline << "\n";
  1990. tmpLog << fileName << "\n";
  1991. tmpLog << "functionsCalled: " << functionsCalled/100 << "\n";
  1992. tmpLog << "totalFunctions: " << totalFunctions/100 << "\n";
  1993. tmpLog << "percentFunction: " << percentFunction << "\n";
  1994. tmpLog << "branchCovered: " << branchCovered << "\n";
  1995. tmpLog << "totalBranches: " << totalBranches << "\n";
  1996. tmpLog << "percentBranch: " << percentBranch << "\n";
  1997. tmpLog << "percentCoverage: " << percent_coverage << "\n";
  1998. tmpLog << "coverage metric: " << cmet << "\n";
  1999. covSumFile << "\t<File Name=\"" << cmXMLSafe(sourceFile)
  2000. << "\" FullPath=\"" << cmXMLSafe(shortFileName)
  2001. << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"
  2002. << "\t\t<BranchesTested>"
  2003. << branchCovered
  2004. << "</BranchesTested>\n"
  2005. << "\t\t<BranchesUnTested>"
  2006. << totalBranches - branchCovered
  2007. << "</BranchesUnTested>\n"
  2008. << "\t\t<FunctionsTested>"
  2009. << functionsCalled
  2010. << "</FunctionsTested>\n"
  2011. << "\t\t<FunctionsUnTested>"
  2012. << totalFunctions - functionsCalled
  2013. << "</FunctionsUnTested>\n"
  2014. // Hack for conversion of function to loc assume a function
  2015. // has 100 lines of code
  2016. << "\t\t<LOCTested>" << functionsCalled *100
  2017. << "</LOCTested>\n"
  2018. << "\t\t<LOCUnTested>"
  2019. << (totalFunctions - functionsCalled)*100
  2020. << "</LOCUnTested>\n"
  2021. << "\t\t<PercentCoverage>";
  2022. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  2023. covSumFile.precision(2);
  2024. covSumFile << (cper) << "</PercentCoverage>\n"
  2025. << "\t\t<CoverageMetric>";
  2026. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  2027. covSumFile.precision(2);
  2028. covSumFile << (cmet) << "</CoverageMetric>\n";
  2029. this->WriteXMLLabels(covSumFile, shortFileName);
  2030. covSumFile << "\t</File>" << std::endl;
  2031. }
  2032. }
  2033. std::string end_time = this->CTest->CurrentTime();
  2034. covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
  2035. << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
  2036. << "\t<LOC>" << total_functions << "</LOC>\n"
  2037. << "\t<PercentCoverage>";
  2038. covSumFile.setf(std::ios::fixed, std::ios::floatfield);
  2039. covSumFile.precision(2);
  2040. covSumFile
  2041. << SAFEDIV(percent_coverage,number_files)<< "</PercentCoverage>\n"
  2042. << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"
  2043. << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
  2044. << "</EndTime>\n";
  2045. covSumFile
  2046. << "<ElapsedMinutes>" <<
  2047. static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
  2048. << "</ElapsedMinutes>"
  2049. << "</Coverage>" << std::endl;
  2050. this->CTest->EndXML(covSumFile);
  2051. // Now create the coverage information for each file
  2052. return this->RunBullseyeCoverageBranch(cont,
  2053. coveredFileNames,
  2054. coveredFiles,
  2055. coveredFilesFullPath);
  2056. }
  2057. //----------------------------------------------------------------------
  2058. int cmCTestCoverageHandler::HandleBullseyeCoverage(
  2059. cmCTestCoverageHandlerContainer* cont)
  2060. {
  2061. const char* covfile = cmSystemTools::GetEnv("COVFILE");
  2062. if(!covfile || strlen(covfile) == 0)
  2063. {
  2064. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  2065. " COVFILE environment variable not found, not running "
  2066. " bullseye\n");
  2067. return 0;
  2068. }
  2069. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  2070. " run covsrc with COVFILE=["
  2071. << covfile
  2072. << "]" << std::endl);
  2073. if(!this->RunBullseyeSourceSummary(cont))
  2074. {
  2075. cmCTestLog(this->CTest, ERROR_MESSAGE,
  2076. "Error running bullseye summary.\n");
  2077. return 0;
  2078. }
  2079. cmCTestLog(this->CTest, DEBUG, "HandleBullseyeCoverage return 1 "
  2080. << std::endl);
  2081. return 1;
  2082. }
  2083. bool cmCTestCoverageHandler::GetNextInt(std::string const& inputLine,
  2084. std::string::size_type& pos,
  2085. int& value)
  2086. {
  2087. std::string::size_type start = pos;
  2088. pos = inputLine.find(',', start);
  2089. value = atoi(inputLine.substr(start, pos).c_str());
  2090. if(pos == inputLine.npos)
  2091. {
  2092. return true;
  2093. }
  2094. pos++;
  2095. return true;
  2096. }
  2097. bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
  2098. std::string const& inputLine,
  2099. std::string& sourceFile,
  2100. int& functionsCalled,
  2101. int& totalFunctions,
  2102. int& percentFunction,
  2103. int& branchCovered,
  2104. int& totalBranches,
  2105. int& percentBranch)
  2106. {
  2107. // find the first comma
  2108. std::string::size_type pos = inputLine.find(',');
  2109. if(pos == inputLine.npos)
  2110. {
  2111. cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing string : "
  2112. << inputLine << "\n");
  2113. return false;
  2114. }
  2115. // the source file has "" around it so extract out the file name
  2116. sourceFile = inputLine.substr(1,pos-2);
  2117. pos++;
  2118. if(!this->GetNextInt(inputLine, pos, functionsCalled))
  2119. {
  2120. return false;
  2121. }
  2122. if(!this->GetNextInt(inputLine, pos, totalFunctions))
  2123. {
  2124. return false;
  2125. }
  2126. if(!this->GetNextInt(inputLine, pos, percentFunction))
  2127. {
  2128. return false;
  2129. }
  2130. if(!this->GetNextInt(inputLine, pos, branchCovered))
  2131. {
  2132. return false;
  2133. }
  2134. if(!this->GetNextInt(inputLine, pos, totalBranches))
  2135. {
  2136. return false;
  2137. }
  2138. if(!this->GetNextInt(inputLine, pos, percentBranch))
  2139. {
  2140. return false;
  2141. }
  2142. // should be at the end now
  2143. if(pos != inputLine.npos)
  2144. {
  2145. cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing input : "
  2146. << inputLine << " last pos not npos = " << pos <<
  2147. "\n");
  2148. }
  2149. return true;
  2150. }
  2151. //----------------------------------------------------------------------
  2152. int cmCTestCoverageHandler::GetLabelId(std::string const& label)
  2153. {
  2154. LabelIdMapType::iterator i = this->LabelIdMap.find(label);
  2155. if(i == this->LabelIdMap.end())
  2156. {
  2157. int n = int(this->Labels.size());
  2158. this->Labels.push_back(label);
  2159. LabelIdMapType::value_type entry(label, n);
  2160. i = this->LabelIdMap.insert(entry).first;
  2161. }
  2162. return i->second;
  2163. }
  2164. //----------------------------------------------------------------------
  2165. void cmCTestCoverageHandler::LoadLabels()
  2166. {
  2167. std::string fileList = this->CTest->GetBinaryDir();
  2168. fileList += cmake::GetCMakeFilesDirectory();
  2169. fileList += "/TargetDirectories.txt";
  2170. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  2171. " target directory list [" << fileList << "]\n");
  2172. cmsys::ifstream finList(fileList.c_str());
  2173. std::string line;
  2174. while(cmSystemTools::GetLineFromStream(finList, line))
  2175. {
  2176. this->LoadLabels(line.c_str());
  2177. }
  2178. }
  2179. //----------------------------------------------------------------------
  2180. void cmCTestCoverageHandler::LoadLabels(const char* dir)
  2181. {
  2182. LabelSet& dirLabels = this->TargetDirs[dir];
  2183. std::string fname = dir;
  2184. fname += "/Labels.txt";
  2185. cmsys::ifstream fin(fname.c_str());
  2186. if(!fin)
  2187. {
  2188. return;
  2189. }
  2190. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  2191. " loading labels from [" << fname << "]\n");
  2192. bool inTarget = true;
  2193. std::string source;
  2194. std::string line;
  2195. std::vector<int> targetLabels;
  2196. while(cmSystemTools::GetLineFromStream(fin, line))
  2197. {
  2198. if(line.empty() || line[0] == '#')
  2199. {
  2200. // Ignore blank and comment lines.
  2201. continue;
  2202. }
  2203. else if(line[0] == ' ')
  2204. {
  2205. // Label lines appear indented by one space.
  2206. std::string label = line.substr(1);
  2207. int id = this->GetLabelId(label);
  2208. dirLabels.insert(id);
  2209. if(inTarget)
  2210. {
  2211. targetLabels.push_back(id);
  2212. }
  2213. else
  2214. {
  2215. this->SourceLabels[source].insert(id);
  2216. }
  2217. }
  2218. else
  2219. {
  2220. // Non-indented lines specify a source file name. The first one
  2221. // is the end of the target-wide labels.
  2222. inTarget = false;
  2223. source = this->CTest->GetShortPathToFile(line.c_str());
  2224. // Label the source with the target labels.
  2225. LabelSet& labelSet = this->SourceLabels[source];
  2226. for(std::vector<int>::const_iterator li = targetLabels.begin();
  2227. li != targetLabels.end(); ++li)
  2228. {
  2229. labelSet.insert(*li);
  2230. }
  2231. }
  2232. }
  2233. }
  2234. //----------------------------------------------------------------------
  2235. void cmCTestCoverageHandler::WriteXMLLabels(std::ostream& os,
  2236. std::string const& source)
  2237. {
  2238. LabelMapType::const_iterator li = this->SourceLabels.find(source);
  2239. if(li != this->SourceLabels.end() && !li->second.empty())
  2240. {
  2241. os << "\t\t<Labels>\n";
  2242. for(LabelSet::const_iterator lsi = li->second.begin();
  2243. lsi != li->second.end(); ++lsi)
  2244. {
  2245. os << "\t\t\t<Label>" << cmXMLSafe(this->Labels[*lsi]) << "</Label>\n";
  2246. }
  2247. os << "\t\t</Labels>\n";
  2248. }
  2249. }
  2250. //----------------------------------------------------------------------------
  2251. void
  2252. cmCTestCoverageHandler::SetLabelFilter(std::set<std::string> const& labels)
  2253. {
  2254. this->LabelFilter.clear();
  2255. for(std::set<std::string>::const_iterator li = labels.begin();
  2256. li != labels.end(); ++li)
  2257. {
  2258. this->LabelFilter.insert(this->GetLabelId(*li));
  2259. }
  2260. }
  2261. //----------------------------------------------------------------------
  2262. bool cmCTestCoverageHandler::IntersectsFilter(LabelSet const& labels)
  2263. {
  2264. // If there is no label filter then nothing is filtered out.
  2265. if(this->LabelFilter.empty())
  2266. {
  2267. return true;
  2268. }
  2269. std::vector<int> ids;
  2270. cmsys_stl::set_intersection
  2271. (labels.begin(), labels.end(),
  2272. this->LabelFilter.begin(), this->LabelFilter.end(),
  2273. cmsys_stl::back_inserter(ids));
  2274. return !ids.empty();
  2275. }
  2276. //----------------------------------------------------------------------
  2277. bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source)
  2278. {
  2279. // If there is no label filter then nothing is filtered out.
  2280. if(this->LabelFilter.empty())
  2281. {
  2282. return false;
  2283. }
  2284. // The source is filtered out if it does not have any labels in
  2285. // common with the filter set.
  2286. std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str());
  2287. LabelMapType::const_iterator li = this->SourceLabels.find(shortSrc);
  2288. if(li != this->SourceLabels.end())
  2289. {
  2290. return !this->IntersectsFilter(li->second);
  2291. }
  2292. return true;
  2293. }
  2294. //----------------------------------------------------------------------
  2295. std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(
  2296. cmCTestCoverageHandlerContainer* cont)
  2297. {
  2298. std::set<std::string> extraMatches;
  2299. for(std::vector<std::string>::iterator i = this->ExtraCoverageGlobs.begin();
  2300. i != this->ExtraCoverageGlobs.end(); ++i)
  2301. {
  2302. cmsys::Glob gl;
  2303. gl.RecurseOn();
  2304. gl.RecurseThroughSymlinksOff();
  2305. std::string glob = cont->SourceDir + "/" + *i;
  2306. gl.FindFiles(glob);
  2307. std::vector<std::string> files = gl.GetFiles();
  2308. for(std::vector<std::string>::iterator f = files.begin();
  2309. f != files.end(); ++f)
  2310. {
  2311. if(this->ShouldIDoCoverage(f->c_str(),
  2312. cont->SourceDir.c_str(), cont->BinaryDir.c_str()))
  2313. {
  2314. extraMatches.insert(this->CTest->GetShortPathToFile(
  2315. f->c_str()));
  2316. }
  2317. }
  2318. }
  2319. if(extraMatches.size())
  2320. {
  2321. for(cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =
  2322. cont->TotalCoverage.begin(); i != cont->TotalCoverage.end(); ++i)
  2323. {
  2324. std::string shortPath = this->CTest->GetShortPathToFile(
  2325. i->first.c_str());
  2326. extraMatches.erase(shortPath);
  2327. }
  2328. }
  2329. return extraMatches;
  2330. }