| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044 | /*============================================================================  CMake - Cross Platform Makefile Generator  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium  Distributed under the OSI-approved BSD License (the "License");  see accompanying file Copyright.txt for details.  This software is distributed WITHOUT ANY WARRANTY; without even the  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the License for more information.============================================================================*/#include "cmCTestCoverageHandler.h"#include "cmCTest.h"#include "cmake.h"#include "cmMakefile.h"#include "cmSystemTools.h"#include "cmGeneratedFileStream.h"#include "cmXMLSafe.h"#include <cmsys/Process.h>#include <cmsys/RegularExpression.hxx>#include <cmsys/Glob.hxx>#include <cmsys/stl/iterator>#include <cmsys/stl/algorithm>#include <stdlib.h>#include <math.h>#include <float.h>#define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))class cmCTestRunProcess{public:  cmCTestRunProcess()    {      this->Process = cmsysProcess_New();      this->PipeState = -1;      this->TimeOut = -1;    }  ~cmCTestRunProcess()    {      if(!(this->PipeState == -1)         && !(this->PipeState == cmsysProcess_Pipe_None )         && !(this->PipeState == cmsysProcess_Pipe_Timeout))        {        this->WaitForExit();        }      cmsysProcess_Delete(this->Process);    }  void SetCommand(const char* command)    {      this->CommandLineStrings.clear();      this->CommandLineStrings.push_back(command);;    }  void AddArgument(const char* arg)    {      if(arg)        {        this->CommandLineStrings.push_back(arg);        }    }  void SetWorkingDirectory(const char* dir)    {      this->WorkingDirectory = dir;    }  void SetTimeout(double t)    {      this->TimeOut = t;    }  bool StartProcess()    {      std::vector<const char*> args;      for(std::vector<std::string>::iterator i =            this->CommandLineStrings.begin();          i != this->CommandLineStrings.end(); ++i)        {        args.push_back(i->c_str());        }      args.push_back(0); // null terminate       cmsysProcess_SetCommand(this->Process, &*args.begin());      if(this->WorkingDirectory.size())        {        cmsysProcess_SetWorkingDirectory(this->Process,                                         this->WorkingDirectory.c_str());        }            cmsysProcess_SetOption(this->Process,                              cmsysProcess_Option_HideWindow, 1);      if(this->TimeOut != -1)        {        cmsysProcess_SetTimeout(this->Process, this->TimeOut);        }      cmsysProcess_Execute(this->Process);      this->PipeState = cmsysProcess_GetState(this->Process);      // if the process is running or exited return true      if(this->PipeState == cmsysProcess_State_Executing         || this->PipeState == cmsysProcess_State_Exited)        {        return true;        }      return false;    }  void SetStdoutFile(const char* fname)    {    cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);    }  void SetStderrFile(const char* fname)    {    cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);    }  int WaitForExit(double* timeout =0)     {      this->PipeState = cmsysProcess_WaitForExit(this->Process,                                                 timeout);      return this->PipeState;    }  int GetProcessState() { return this->PipeState;}private:  int PipeState;  cmsysProcess* Process;  std::vector<std::string> CommandLineStrings;  std::string WorkingDirectory;  double TimeOut;};//----------------------------------------------------------------------//**********************************************************************class cmCTestCoverageHandlerContainer{public:  int Error;  std::string SourceDir;  std::string BinaryDir;  typedef std::vector<int> SingleFileCoverageVector;  typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;  TotalCoverageMap TotalCoverage;  std::ostream* OFS;};//**********************************************************************//----------------------------------------------------------------------//----------------------------------------------------------------------cmCTestCoverageHandler::cmCTestCoverageHandler(){}//----------------------------------------------------------------------void cmCTestCoverageHandler::Initialize(){  this->Superclass::Initialize();  this->CustomCoverageExclude.clear();  this->SourceLabels.clear();  this->LabelIdMap.clear();  this->Labels.clear();  this->LabelFilter.clear();}//----------------------------------------------------------------------------void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log){  std::string logGlob = this->CTest->GetCTestConfiguration("BuildDirectory");  logGlob += "/Testing/";  logGlob += this->CTest->GetCurrentTag();  logGlob += "/CoverageLog*";  cmsys::Glob gl;  gl.FindFiles(logGlob.c_str());  std::vector<std::string> const& files = gl.GetFiles();  for(std::vector<std::string>::const_iterator fi = files.begin();      fi != files.end(); ++fi)    {    log << "Removing old coverage log: " << *fi << "\n";    cmSystemTools::RemoveFile(fi->c_str());    }}//----------------------------------------------------------------------bool cmCTestCoverageHandler::StartCoverageLogFile(  cmGeneratedFileStream& covLogFile, int logFileCount){  char covLogFilename[1024];  sprintf(covLogFilename, "CoverageLog-%d", logFileCount);  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Open file: "    << covLogFilename << std::endl);  if(!this->StartResultingXML(cmCTest::PartCoverage,                              covLogFilename, covLogFile))    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open log file: "      << covLogFilename << std::endl);    return false;    }  std::string local_start_time = this->CTest->CurrentTime();  this->CTest->StartXML(covLogFile, this->AppendXML);  covLogFile << "<CoverageLog>" << std::endl             << "\t<StartDateTime>" << local_start_time << "</StartDateTime>"             << "\t<StartTime>"              << static_cast<unsigned int>(cmSystemTools::GetTime())             << "</StartTime>"    << std::endl;  return true;}//----------------------------------------------------------------------void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr,  int logFileCount){  std::string local_end_time = this->CTest->CurrentTime();  ostr << "\t<EndDateTime>" << local_end_time << "</EndDateTime>" << std::endl       << "\t<EndTime>" <<        static_cast<unsigned int>(cmSystemTools::GetTime())       << "</EndTime>" << std::endl    << "</CoverageLog>" << std::endl;  this->CTest->EndXML(ostr);  char covLogFilename[1024];  sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount);  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Close file: "    << covLogFilename << std::endl);  ostr.Close();}//----------------------------------------------------------------------bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file,  const char* srcDir,  const char* binDir){  if(this->IsFilteredOut(file))    {    return false;    }  std::vector<cmsys::RegularExpression>::iterator sit;  for ( sit = this->CustomCoverageExcludeRegex.begin();    sit != this->CustomCoverageExcludeRegex.end(); ++ sit )    {    if ( sit->find(file) )      {      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "  File " << file        << " is excluded in CTestCustom.ctest" << std::endl;);      return false;      }    }  std::string fSrcDir = cmSystemTools::CollapseFullPath(srcDir);  std::string fBinDir = cmSystemTools::CollapseFullPath(binDir);  std::string fFile = cmSystemTools::CollapseFullPath(file);  bool sourceSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(),    fSrcDir.c_str());  bool buildSubDir = cmSystemTools::IsSubDirectory(fFile.c_str(),    fBinDir.c_str());  // Always check parent directory of the file.  std::string fileDir = cmSystemTools::GetFilenamePath(fFile.c_str());  std::string checkDir;  // We also need to check the binary/source directory pair.  if ( sourceSubDir && buildSubDir )    {    if ( fSrcDir.size() > fBinDir.size() )      {      checkDir = fSrcDir;      }    else      {      checkDir = fBinDir;      }    }  else if ( sourceSubDir )    {    checkDir = fSrcDir;    }  else if ( buildSubDir )    {    checkDir = fBinDir;    }  std::string ndc    = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",      fFile.c_str(), checkDir.c_str());  if ( ndc.size() )    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str()      << " so skip coverage of " << file << std::endl);    return false;    }  // By now checkDir should be set to parent directory of the file.  // Get the relative path to the file an apply it to the opposite directory.  // If it is the same as fileDir, then ignore, otherwise check.  std::string relPath;  if(checkDir.size() )    {    relPath = cmSystemTools::RelativePath(checkDir.c_str(),                                          fFile.c_str());    }  else    {    relPath = fFile;    }  if ( checkDir == fSrcDir )    {    checkDir = fBinDir;    }  else    {    checkDir = fSrcDir;    }  fFile = checkDir + "/" + relPath;  fFile = cmSystemTools::GetFilenamePath(fFile.c_str());  if ( fileDir == fFile )    {    // This is in-source build, so we trust the previous check.    return true;    }  ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",    fFile.c_str(), checkDir.c_str());  if ( ndc.size() )    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found: " << ndc.c_str()      << " so skip coverage of: " << file << std::endl);    return false;    }  // Ok, nothing in source tree, nothing in binary tree  return true;}//----------------------------------------------------------------------//clearly it would be nice if this were broken up into a few smaller//functions and commented...int cmCTestCoverageHandler::ProcessHandler(){  this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);  int error = 0;  // do we have time for this  if (this->CTest->GetRemainingTimeAllowed() < 120)    {    return error;    }    std::string coverage_start_time = this->CTest->CurrentTime();  unsigned int coverage_start_time_time = static_cast<unsigned int>(    cmSystemTools::GetTime());  std::string sourceDir    = this->CTest->GetCTestConfiguration("SourceDirectory");  std::string binaryDir    = this->CTest->GetCTestConfiguration("BuildDirectory");  this->LoadLabels();  cmGeneratedFileStream ofs;  double elapsed_time_start = cmSystemTools::GetTime();  if ( !this->StartLogFile("Coverage", ofs) )    {    cmCTestLog(this->CTest, ERROR_MESSAGE,      "Cannot create LastCoverage.log file" << std::endl);    }  ofs << "Performing coverage: " << elapsed_time_start << std::endl;  this->CleanCoverageLogFiles(ofs);  cmSystemTools::ConvertToUnixSlashes(sourceDir);  cmSystemTools::ConvertToUnixSlashes(binaryDir);  cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);  cmCTestCoverageHandlerContainer cont;  cont.Error = error;  cont.SourceDir = sourceDir;  cont.BinaryDir = binaryDir;  cont.OFS = &ofs;  // setup the regex exclude stuff  this->CustomCoverageExcludeRegex.clear();  std::vector<cmStdString>::iterator rexIt;  for ( rexIt = this->CustomCoverageExclude.begin();    rexIt != this->CustomCoverageExclude.end();    ++ rexIt )    {    this->CustomCoverageExcludeRegex.push_back(      cmsys::RegularExpression(rexIt->c_str()));    }  if(this->HandleBullseyeCoverage(&cont))    {    return cont.Error;    }  int file_count = 0;  file_count += this->HandleGCovCoverage(&cont);  if ( file_count < 0 )    {    return error;    }  file_count += this->HandleTracePyCoverage(&cont);  if ( file_count < 0 )    {    return error;    }  error = cont.Error;  std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);  if ( file_count == 0 )    {    cmCTestLog(this->CTest, WARNING,      " Cannot find any coverage files. Ignoring Coverage request."      << std::endl);    return error;    }  cmGeneratedFileStream covSumFile;  cmGeneratedFileStream covLogFile;  if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))    {    cmCTestLog(this->CTest, ERROR_MESSAGE,      "Cannot open coverage summary file." << std::endl);    return -1;    }  this->CTest->StartXML(covSumFile, this->AppendXML);  // Produce output xml files  covSumFile << "<Coverage>" << std::endl    << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>"    << std::endl    << "\t<StartTime>" << coverage_start_time_time << "</StartTime>"    << std::endl;  int logFileCount = 0;  if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )    {    return -1;    }  cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator;  int cnt = 0;  long total_tested = 0;  long total_untested = 0;  //std::string fullSourceDir = sourceDir + "/";  //std::string fullBinaryDir = binaryDir + "/";  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);  cmCTestLog(this->CTest, HANDLER_OUTPUT,    "   Acumulating results (each . represents one file):" << std::endl);  cmCTestLog(this->CTest, HANDLER_OUTPUT, "    ");  std::vector<std::string> errorsWhileAccumulating;  file_count = 0;  for ( fileIterator = cont.TotalCoverage.begin();    fileIterator != cont.TotalCoverage.end();    ++fileIterator )    {    cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);    file_count ++;    if ( file_count % 50 == 0 )      {      cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count        << " out of "        << cont.TotalCoverage.size() << std::endl);      cmCTestLog(this->CTest, HANDLER_OUTPUT, "    ");      }    const std::string fullFileName = fileIterator->first;    bool shouldIDoCoverage      = this->ShouldIDoCoverage(fullFileName.c_str(),        sourceDir.c_str(), binaryDir.c_str());    if ( !shouldIDoCoverage )      {      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,        ".NoDartCoverage found, so skip coverage check for: "        << fullFileName.c_str()        << std::endl);      continue;      }    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "Process file: " << fullFileName << std::endl);    if ( !cmSystemTools::FileExists(fullFileName.c_str()) )      {      cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "        << fullFileName.c_str() << std::endl);      continue;      }    if ( ++cnt % 100 == 0 )      {      this->EndCoverageLogFile(covLogFile, logFileCount);      logFileCount ++;      if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )        {        return -1;        }      }    const std::string fileName      = cmSystemTools::GetFilenameName(fullFileName.c_str());    std::string shortFileName =      this->CTest->GetShortPathToFile(fullFileName.c_str());    const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov      = fileIterator->second;    covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)      << "\" FullPath=\"" << cmXMLSafe(shortFileName) << "\">\n"      << "\t\t<Report>" << std::endl;    std::ifstream ifs(fullFileName.c_str());    if ( !ifs)      {      cmOStringStream ostr;      ostr <<  "Cannot open source file: " << fullFileName.c_str();      errorsWhileAccumulating.push_back(ostr.str());      error ++;      continue;      }    int tested = 0;    int untested = 0;    cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;    std::string line;    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "Actually perfoming coverage for: " << fullFileName << std::endl);    for ( cc= 0; cc < fcov.size(); cc ++ )      {      if ( !cmSystemTools::GetLineFromStream(ifs, line) &&        cc != fcov.size() -1 )        {        cmOStringStream ostr;        ostr << "Problem reading source file: " << fullFileName.c_str()          << " line:" << cc;        errorsWhileAccumulating.push_back(ostr.str());        error ++;        break;        }      covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc]        << "\">"        << cmXMLSafe(line) << "</Line>" << std::endl;      if ( fcov[cc] == 0 )        {        untested ++;        }      else if ( fcov[cc] > 0 )        {        tested ++;        }      }    if ( cmSystemTools::GetLineFromStream(ifs, line) )      {      cmOStringStream ostr;      ostr <<  "Looks like there are more lines in the file: " << line;      errorsWhileAccumulating.push_back(ostr.str());      }    float cper = 0;    float cmet = 0;    if ( tested + untested > 0 )      {      cper = (100 * SAFEDIV(static_cast<float>(tested),          static_cast<float>(tested + untested)));      cmet = ( SAFEDIV(static_cast<float>(tested + 10),          static_cast<float>(tested + untested + 10)));      }    total_tested += tested;    total_untested += untested;    covLogFile << "\t\t</Report>" << std::endl      << "\t</File>" << std::endl;    covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)      << "\" FullPath=\"" << cmXMLSafe(        this->CTest->GetShortPathToFile(fullFileName.c_str()))      << "\" Covered=\"" << (tested > 0 ? "true":"false") << "\">\n"      << "\t\t<LOCTested>" << tested << "</LOCTested>\n"      << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"      << "\t\t<PercentCoverage>";    covSumFile.setf(std::ios::fixed, std::ios::floatfield);    covSumFile.precision(2);    covSumFile << (cper) << "</PercentCoverage>\n"      << "\t\t<CoverageMetric>";    covSumFile.setf(std::ios::fixed, std::ios::floatfield);    covSumFile.precision(2);    covSumFile << (cmet) << "</CoverageMetric>\n";    this->WriteXMLLabels(covSumFile, shortFileName);    covSumFile << "\t</File>" << std::endl;    }  //Handle all the files in the extra coverage globs that have no cov data  for(std::set<std::string>::iterator i = uncovered.begin();      i != uncovered.end(); ++i)    {    std::string shortFileName = this->CTest->GetShortPathToFile(i->c_str());    covLogFile << "\t<File Name=\"" << cmXMLSafe(i->c_str())      << "\" FullPath=\"" << cmXMLSafe(shortFileName) << "\">\n"      << "\t\t<Report>" << std::endl;    std::ifstream ifs(i->c_str());    if (!ifs)      {      cmOStringStream ostr;      ostr <<  "Cannot open source file: " << i->c_str();      errorsWhileAccumulating.push_back(ostr.str());      error ++;      continue;      }    int untested = 0;    std::string line;    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "Actually perfoming coverage for: " << i->c_str() << std::endl);    while (cmSystemTools::GetLineFromStream(ifs, line))      {      covLogFile << "\t\t<Line Number=\"" << untested << "\" Count=\"0\">"        << cmXMLSafe(line) << "</Line>" << std::endl;      untested ++;      }    covLogFile << "\t\t</Report>\n\t</File>" << std::endl;    total_untested += untested;    covSumFile << "\t<File Name=\"" << cmXMLSafe(i->c_str())      << "\" FullPath=\"" << cmXMLSafe(shortFileName.c_str())      << "\" Covered=\"true\">\n"      << "\t\t<LOCTested>0</LOCTested>\n"      << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"      << "\t\t<PercentCoverage>0</PercentCoverage>\n"      << "\t\t<CoverageMetric>0</CoverageMetric>\n";    this->WriteXMLLabels(covSumFile, shortFileName);    covSumFile << "\t</File>" << std::endl;    }  this->EndCoverageLogFile(covLogFile, logFileCount);  if ( errorsWhileAccumulating.size() > 0 )    {    cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);    cmCTestLog(this->CTest, ERROR_MESSAGE,      "Error(s) while acumulating results:" << std::endl);    std::vector<std::string>::iterator erIt;    for ( erIt = errorsWhileAccumulating.begin();      erIt != errorsWhileAccumulating.end();      ++ erIt )      {      cmCTestLog(this->CTest, ERROR_MESSAGE,        "  " << erIt->c_str() << std::endl);      }    }  long total_lines = total_tested + total_untested;  float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),    static_cast<float>(total_lines));  if ( total_lines == 0 )    {    percent_coverage = 0;    }  std::string end_time = this->CTest->CurrentTime();  covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"    << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"    << "\t<LOC>" << total_lines << "</LOC>\n"    << "\t<PercentCoverage>";  covSumFile.setf(std::ios::fixed, std::ios::floatfield);  covSumFile.precision(2);  covSumFile << (percent_coverage)<< "</PercentCoverage>\n"    << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"    << "\t<EndTime>" <<          static_cast<unsigned int>(cmSystemTools::GetTime())    << "</EndTime>\n";  covSumFile << "<ElapsedMinutes>" <<    static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0    << "</ElapsedMinutes>"    << "</Coverage>" << std::endl;  this->CTest->EndXML(covSumFile);  cmCTestLog(this->CTest, HANDLER_OUTPUT, "" << std::endl    << "\tCovered LOC:         "    << total_tested << std::endl    << "\tNot covered LOC:     " << total_untested << std::endl    << "\tTotal LOC:           " << total_lines << std::endl    << "\tPercentage Coverage: "    << std::setiosflags(std::ios::fixed)    << std::setprecision(2)    << (percent_coverage) << "%" << std::endl);  ofs << "\tCovered LOC:         " << total_tested << std::endl    << "\tNot covered LOC:     " << total_untested << std::endl    << "\tTotal LOC:           " << total_lines << std::endl    << "\tPercentage Coverage: "    << std::setiosflags(std::ios::fixed)    << std::setprecision(2)    << (percent_coverage) << "%" << std::endl;  if ( error )    {    return -1;    }  return 0;}//----------------------------------------------------------------------void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf){  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,    " Add coverage exclude regular expressions." << std::endl);  this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",                                this->CustomCoverageExclude);  this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",                                this->ExtraCoverageGlobs);  std::vector<cmStdString>::iterator it;  for ( it = this->CustomCoverageExclude.begin();    it != this->CustomCoverageExclude.end();    ++ it )    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "      << it->c_str() << std::endl);    }  for ( it = this->ExtraCoverageGlobs.begin();    it != this->ExtraCoverageGlobs.end(); ++it)    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage glob: "      << it->c_str() << std::endl);    }}//----------------------------------------------------------------------// Fix for issue #4971 where the case of the drive letter component of// the filenames might be different when analyzing gcov output.//// Compare file names: fnc(fn1) == fnc(fn2) // fnc == file name compare//#ifdef _WIN32#define fnc(s) cmSystemTools::LowerCase(s)#else#define fnc(s) s#endif//----------------------------------------------------------------------bool IsFileInDir(const std::string &infile, const std::string &indir){  std::string file = cmSystemTools::CollapseFullPath(infile.c_str());  std::string dir = cmSystemTools::CollapseFullPath(indir.c_str());  if (    file.size() > dir.size() &&    (fnc(file.substr(0, dir.size())) == fnc(dir)) &&    file[dir.size()] == '/'    )    {    return true;    }  return false;}//----------------------------------------------------------------------int cmCTestCoverageHandler::HandleGCovCoverage(  cmCTestCoverageHandlerContainer* cont){  std::string gcovCommand    = this->CTest->GetCTestConfiguration("CoverageCommand");  // Style 1  std::string st1gcovOutputRex1    = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";  std::string st1gcovOutputRex2 = "^Creating (.*\\.gcov)\\.";  cmsys::RegularExpression st1re1(st1gcovOutputRex1.c_str());  cmsys::RegularExpression st1re2(st1gcovOutputRex2.c_str());  // Style 2  std::string st2gcovOutputRex1 = "^File *[`'](.*)'$";  std::string st2gcovOutputRex2    = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";  std::string st2gcovOutputRex3 = "^(.*):creating [`'](.*\\.gcov)'";  std::string st2gcovOutputRex4 = "^(.*):unexpected EOF *$";  std::string st2gcovOutputRex5 = "^(.*):cannot open source file*$";  std::string st2gcovOutputRex6    = "^(.*):source file is newer than graph file `(.*)'$";  cmsys::RegularExpression st2re1(st2gcovOutputRex1.c_str());  cmsys::RegularExpression st2re2(st2gcovOutputRex2.c_str());  cmsys::RegularExpression st2re3(st2gcovOutputRex3.c_str());  cmsys::RegularExpression st2re4(st2gcovOutputRex4.c_str());  cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());  cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());  std::vector<std::string> files;  this->FindGCovFiles(files);  std::vector<std::string>::iterator it;  if ( files.size() == 0 )    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      " Cannot find any GCov coverage files."      << std::endl);    // No coverage files is a valid thing, so the exit code is 0     return 0;    }  std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";  std::string tempDir = testingDir + "/CoverageInfo";  std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();  cmSystemTools::MakeDirectory(tempDir.c_str());  cmSystemTools::ChangeDirectory(tempDir.c_str());  int gcovStyle = 0;  std::set<std::string> missingFiles;  std::string actualSourceFile = "";  cmCTestLog(this->CTest, HANDLER_OUTPUT,    "   Processing coverage (each . represents one file):" << std::endl);  cmCTestLog(this->CTest, HANDLER_OUTPUT, "    ");  int file_count = 0;  // make sure output from gcov is in English!  cmSystemTools::PutEnv("LC_ALL=POSIX");  // files is a list of *.da and *.gcda files with coverage data in them.  // These are binary files that you give as input to gcov so that it will  // give us text output we can analyze to summarize coverage.  //  for ( it = files.begin(); it != files.end(); ++ it )    {    cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);    // Call gcov to get coverage data for this *.gcda file:    //    std::string fileDir = cmSystemTools::GetFilenamePath(it->c_str());    std::string command = "\"" + gcovCommand + "\" -l -o \"" + fileDir      + "\" \"" + *it + "\"";    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, command.c_str()      << std::endl);    std::string output = "";    std::string errors = "";    int retVal = 0;    *cont->OFS << "* Run coverage for: " << fileDir.c_str() << std::endl;    *cont->OFS << "  Command: " << command.c_str() << std::endl;    int res = this->CTest->RunCommand(command.c_str(), &output, &errors,      &retVal, tempDir.c_str(), 0 /*this->TimeOut*/);    *cont->OFS << "  Output: " << output.c_str() << std::endl;    *cont->OFS << "  Errors: " << errors.c_str() << std::endl;    if ( ! res )      {      cmCTestLog(this->CTest, ERROR_MESSAGE,        "Problem running coverage on file: " << it->c_str() << std::endl);      cmCTestLog(this->CTest, ERROR_MESSAGE,        "Command produced error: " << errors << std::endl);      cont->Error ++;      continue;      }    if ( retVal != 0 )      {      cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "        << retVal << " while processing: " << it->c_str() << std::endl);      cmCTestLog(this->CTest, ERROR_MESSAGE,        "Command produced error: " << cont->Error << std::endl);      }    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "--------------------------------------------------------------"      << std::endl      << output << std::endl      << "--------------------------------------------------------------"      << std::endl);    std::vector<cmStdString> lines;    std::vector<cmStdString>::iterator line;    cmSystemTools::Split(output.c_str(), lines);    for ( line = lines.begin(); line != lines.end(); ++line)      {      std::string sourceFile;      std::string gcovFile;      cmCTestLog(this->CTest, DEBUG, "Line: [" << line->c_str() << "]"        << std::endl);      if ( line->size() == 0 )        {        // Ignore empty line; probably style 2        }      else if ( st1re1.find(line->c_str()) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 1;          }        if ( gcovStyle != 1 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e1"            << std::endl);          cont->Error ++;          break;          }        actualSourceFile = "";        sourceFile = st1re1.match(2);        }      else if ( st1re2.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 1;          }        if ( gcovStyle != 1 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e2"            << std::endl);          cont->Error ++;          break;          }        gcovFile = st1re2.match(1);        }      else if ( st2re1.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e3"            << std::endl);          cont->Error ++;          break;          }        actualSourceFile = "";        sourceFile = st2re1.match(1);        }      else if ( st2re2.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e4"            << std::endl);          cont->Error ++;          break;          }        }      else if ( st2re3.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e5"            << std::endl);          cont->Error ++;          break;          }        gcovFile = st2re3.match(2);        }      else if ( st2re4.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e6"            << std::endl);          cont->Error ++;          break;          }        cmCTestLog(this->CTest, WARNING, "Warning: " << st2re4.match(1)          << " had unexpected EOF" << std::endl);        }      else if ( st2re5.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e7"            << std::endl);          cont->Error ++;          break;          }        cmCTestLog(this->CTest, WARNING, "Warning: Cannot open file: "          << st2re5.match(1) << std::endl);        }      else if ( st2re6.find(line->c_str() ) )        {        if ( gcovStyle == 0 )          {          gcovStyle = 2;          }        if ( gcovStyle != 2 )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style e8"            << std::endl);          cont->Error ++;          break;          }        cmCTestLog(this->CTest, WARNING, "Warning: File: " << st2re6.match(1)          << " is newer than " << st2re6.match(2) << std::endl);        }      else        {        cmCTestLog(this->CTest, ERROR_MESSAGE,          "Unknown gcov output line: [" << line->c_str() << "]" << std::endl);        cont->Error ++;        //abort();        }      // If the last line of gcov output gave us a valid value for gcovFile,      // and we have an actualSourceFile, then insert a (or add to existing)      // SingleFileCoverageVector for actualSourceFile:      //      if ( !gcovFile.empty() && !actualSourceFile.empty() )        {        cmCTestCoverageHandlerContainer::SingleFileCoverageVector& vec          = cont->TotalCoverage[actualSourceFile];        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   in gcovFile: "          << gcovFile << std::endl);        std::ifstream ifile(gcovFile.c_str());        if ( ! ifile )          {          cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "            << gcovFile << std::endl);          }        else          {          long cnt = -1;          std::string nl;          while ( cmSystemTools::GetLineFromStream(ifile, nl) )            {            cnt ++;            //TODO: Handle gcov 3.0 non-coverage lines            // Skip empty lines            if ( !nl.size() )              {              continue;              }            // Skip unused lines            if ( nl.size() < 12 )              {              continue;              }            // Read the coverage count from the beginning of the gcov output            // line            std::string prefix = nl.substr(0, 12);            int cov = atoi(prefix.c_str());            // Read the line number starting at the 10th character of the gcov            // output line            std::string lineNumber = nl.substr(10, 5);            int lineIdx = atoi(lineNumber.c_str())-1;            if ( lineIdx >= 0 )              {              while ( vec.size() <= static_cast<size_t>(lineIdx) )                {                vec.push_back(-1);                }              // Initially all entries are -1 (not used). If we get coverage              // information, increment it to 0 first.              if ( vec[lineIdx] < 0 )                {                if ( cov > 0 || prefix.find("#") != prefix.npos )                  {                  vec[lineIdx] = 0;                  }                }              vec[lineIdx] += cov;              }            }          }        actualSourceFile = "";        }      if ( !sourceFile.empty() && actualSourceFile.empty() )        {        gcovFile = "";        // Is it in the source dir or the binary dir?        //        if ( IsFileInDir(sourceFile, cont->SourceDir) )          {          cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   produced s: "            << sourceFile.c_str() << std::endl);          *cont->OFS << "  produced in source dir: " << sourceFile.c_str()            << std::endl;          actualSourceFile            = cmSystemTools::CollapseFullPath(sourceFile.c_str());          }        else if ( IsFileInDir(sourceFile, cont->BinaryDir) )          {          cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   produced b: "            << sourceFile.c_str() << std::endl);          *cont->OFS << "  produced in binary dir: " << sourceFile.c_str()            << std::endl;          actualSourceFile            = cmSystemTools::CollapseFullPath(sourceFile.c_str());          }        if ( actualSourceFile.empty() )          {          if ( missingFiles.find(sourceFile) == missingFiles.end() )            {            cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,              "Something went wrong" << std::endl);            cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,              "Cannot find file: ["              << sourceFile.c_str() << "]" << std::endl);            cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,              " in source dir: ["              << cont->SourceDir.c_str() << "]"              << std::endl);            cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,              " or binary dir: ["              << cont->BinaryDir.size() << "]"              << std::endl);            *cont->OFS << "  Something went wrong. Cannot find file: "              << sourceFile.c_str()              << " in source dir: " << cont->SourceDir.c_str()              << " or binary dir: " << cont->BinaryDir.c_str() << std::endl;            missingFiles.insert(sourceFile);            }          }        }      }    file_count++;    if ( file_count % 50 == 0 )      {      cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count        << " out of " << files.size() << std::endl);      cmCTestLog(this->CTest, HANDLER_OUTPUT, "    ");      }    }  cmSystemTools::ChangeDirectory(currentDirectory.c_str());  return file_count;}//----------------------------------------------------------------------------void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files){  cmsys::Glob gl;  gl.RecurseOn();  gl.RecurseThroughSymlinksOff();  for(LabelMapType::const_iterator lmi = this->TargetDirs.begin();      lmi != this->TargetDirs.end(); ++lmi)    {    // Skip targets containing no interesting labels.    if(!this->IntersectsFilter(lmi->second))      {      continue;      }    // Coverage files appear next to their object files in the target    // support directory.    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,               "   globbing for coverage in: " << lmi->first << std::endl);    std::string daGlob = lmi->first;    daGlob += "/*.da";    gl.FindFiles(daGlob);    files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());    daGlob = lmi->first;    daGlob += "/*.gcda";    gl.FindFiles(daGlob);    files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());    }}//----------------------------------------------------------------------int cmCTestCoverageHandler::HandleTracePyCoverage(  cmCTestCoverageHandlerContainer* cont){  cmsys::Glob gl;  gl.RecurseOn();  gl.RecurseThroughSymlinksOff();  std::string daGlob = cont->BinaryDir + "/*.cover";  gl.FindFiles(daGlob);  std::vector<std::string> files = gl.GetFiles();  if ( files.size() == 0 )    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      " Cannot find any Python Trace.py coverage files."      << std::endl);    // No coverage files is a valid thing, so the exit code is 0     return 0;    }  std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";  std::string tempDir = testingDir + "/CoverageInfo";  std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();  cmSystemTools::MakeDirectory(tempDir.c_str());  cmSystemTools::ChangeDirectory(tempDir.c_str());  cmSystemTools::ChangeDirectory(currentDirectory.c_str());  std::vector<std::string>::iterator fileIt;  int file_count = 0;  for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )    {    std::string fileName = this->FindFile(cont, *fileIt);    if ( fileName.empty() )      {      cmCTestLog(this->CTest, ERROR_MESSAGE,        "Cannot find source Python file corresponding to: "        << fileIt->c_str() << std::endl);      continue;      }    std::string actualSourceFile      = cmSystemTools::CollapseFullPath(fileName.c_str());    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "   Check coverage for file: " << actualSourceFile.c_str()      << std::endl);    cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec      = &cont->TotalCoverage[actualSourceFile];    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,      "   in file: " << fileIt->c_str() << std::endl);    std::ifstream ifile(fileIt->c_str());    if ( ! ifile )      {      cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "        << fileIt->c_str() << std::endl);      }    else      {      long cnt = -1;      std::string nl;      while ( cmSystemTools::GetLineFromStream(ifile, nl) )        {        cnt ++;        // Skip empty lines        if ( !nl.size() )          {          continue;          }        // Skip unused lines        if ( nl.size() < 12 )          {          continue;          }        // Read the coverage count from the beginning of the Trace.py output        // line        std::string prefix = nl.substr(0, 6);        if ( prefix[5] != ' ' && prefix[5] != ':' )          {          // This is a hack. We should really do something more elaborate          prefix = nl.substr(0, 7);          if ( prefix[6] != ' ' && prefix[6] != ':' )            {            prefix = nl.substr(0, 8);            if ( prefix[7] != ' ' && prefix[7] != ':' )              {              cmCTestLog(this->CTest, ERROR_MESSAGE,                "Currently the limit is maximum coverage of 999999"                << std::endl);              }            }          }        int cov = atoi(prefix.c_str());        if ( prefix[prefix.size()-1] != ':' )          {          // This line does not have ':' so no coverage here. That said,          // Trace.py does not handle not covered lines versus comments etc.          // So, this will be set to 0.          cov = 0;          }        cmCTestLog(this->CTest, DEBUG, "Prefix: " << prefix.c_str()          << " cov: " << cov          << std::endl);        // Read the line number starting at the 10th character of the gcov        // output line        long lineIdx = cnt;        if ( lineIdx >= 0 )          {          while ( vec->size() <=            static_cast<size_t>(lineIdx) )            {            vec->push_back(-1);            }          // Initially all entries are -1 (not used). If we get coverage          // information, increment it to 0 first.          if ( (*vec)[lineIdx] < 0 )            {            if ( cov >= 0 )              {              (*vec)[lineIdx] = 0;              }            }          (*vec)[lineIdx] += cov;          }        }      }    ++ file_count;    }  cmSystemTools::ChangeDirectory(currentDirectory.c_str());  return file_count;}//----------------------------------------------------------------------std::string cmCTestCoverageHandler::FindFile(  cmCTestCoverageHandlerContainer* cont,  std::string fileName){  std::string fileNameNoE    = cmSystemTools::GetFilenameWithoutLastExtension(fileName);  // First check in source and binary directory  std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";  if ( cmSystemTools::FileExists(fullName.c_str()) )    {    return fullName;    }  fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";  if ( cmSystemTools::FileExists(fullName.c_str()) )    {    return fullName;    }  return "";}// This is a header put on each marked up source filenamespace{  const char* bullseyeHelp[] =   {"    Coverage produced by bullseye covbr tool: ",   "      www.bullseye.com/help/ref_covbr.html",   "    * An arrow --> indicates incomplete coverage.",   "    * An X indicates a function that was invoked, a switch label that ",   "      was exercised, a try-block that finished, or an exception handler ",   "      that was invoked.",   "    * A T or F indicates a boolean decision that evaluated true or false,",   "      respectively.",   "    * A t or f indicates a boolean condition within a decision if the ",   "      condition evaluated true or false, respectively.",   "    * A k indicates a constant decision or condition.",   "    * The slash / means this probe is excluded from summary results. ",   0};}  //----------------------------------------------------------------------int cmCTestCoverageHandler::RunBullseyeCoverageBranch(  cmCTestCoverageHandlerContainer* cont,  std::set<cmStdString>& coveredFileNames,  std::vector<std::string>& files,  std::vector<std::string>& filesFullPath){  if(files.size() != filesFullPath.size())    {    cmCTestLog(this->CTest, ERROR_MESSAGE,                "Files and full path files not the same size?:\n");    return 0;    }  // create the output stream for the CoverageLog-N.xml file  cmGeneratedFileStream covLogFile;  int logFileCount = 0;  if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )    {    return -1;    }  // for each file run covbr on that file to get the coverage  // information for that file  std::string outputFile;  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                 "run covbr: "                 << std::endl);  if(!this->RunBullseyeCommand(cont, "covbr", 0, outputFile))    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covbr for." << "\n");    return -1;    }  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,             "covbr output in  " << outputFile             << std::endl);  // open the output file  std::ifstream fin(outputFile.c_str());  if(!fin)    {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "Cannot open coverage file: " <<               outputFile.c_str() << std::endl);    return 0;    }  std::map<cmStdString, cmStdString> fileMap;  std::vector<std::string>::iterator fp = filesFullPath.begin();  for(std::vector<std::string>::iterator f =  files.begin();       f != files.end(); ++f, ++fp)    {    fileMap[*f] = *fp;    }  int count =0; // keep count of the number of files   // Now parse each line from the bullseye cov log file  std::string lineIn;  bool valid = false; // are we in a valid output file  int line = 0; // line of the current file  cmStdString file;  while(cmSystemTools::GetLineFromStream(fin, lineIn))    {    bool startFile = false;    if(lineIn.size() > 1 && lineIn[lineIn.size()-1] == ':')      {      file = lineIn.substr(0, lineIn.size()-1);      if(coveredFileNames.find(file) != coveredFileNames.end())        {        startFile = true;        }      }    if(startFile)      {      // if we are in a valid file close it because a new one started      if(valid)        {        covLogFile << "\t\t</Report>" << std::endl                   << "\t</File>" << std::endl;        }      // only allow 100 files in each log file      if ( count != 0 && count % 100 == 0 )        {        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                   "start a new log file: "                   << count                   << std::endl);        this->EndCoverageLogFile(covLogFile, logFileCount);        logFileCount ++;        if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )          {          return -1;          }        count++; // move on one         }      std::map<cmStdString, cmStdString>::iterator         i = fileMap.find(file);      // if the file should be covered write out the header for that file      if(i != fileMap.end())        {        // we have a new file so count it in the output        count++;        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                   "Produce coverage for file: "                   << file.c_str() << " " << count                   << std::endl);        // start the file output        covLogFile << "\t<File Name=\""                   << cmXMLSafe(i->first)                   << "\" FullPath=\"" << cmXMLSafe(                     this->CTest->GetShortPathToFile(                       i->second.c_str())) << "\">" << std::endl                   << "\t\t<Report>" << std::endl;        // write the bullseye header        line =0;        for(int k =0; bullseyeHelp[k] != 0; ++k)          {          covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"                     << cmXMLSafe(bullseyeHelp[k])                     << "</Line>" << std::endl;          line++;          }        valid = true; // we are in a valid file section        }      else        {        // this is not a file that we want coverage for        valid = false;        }      }    // we are not at a start file, and we are in a valid file output the line    else if(valid)      {      covLogFile << "\t\t<Line Number=\"" << line << "\" Count=\"-1\">"                 << cmXMLSafe(lineIn)                 << "</Line>" << std::endl;      line++;      }    }  // if we ran out of lines a valid file then close that file  if(valid)    {    covLogFile << "\t\t</Report>" << std::endl               << "\t</File>" << std::endl;    }  this->EndCoverageLogFile(covLogFile, logFileCount);  return 1;}//----------------------------------------------------------------------int cmCTestCoverageHandler::RunBullseyeCommand(  cmCTestCoverageHandlerContainer* cont,  const char* cmd,  const char* arg,  std::string& outputFile){  std::string program = cmSystemTools::FindProgram(cmd);  if(program.size() == 0)    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");    return 0;    }  if(arg)    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,               "Run : " << program.c_str() << " " << arg << "\n");    }  else    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,               "Run : " << program.c_str() << "\n");    }  // create a process object and start it  cmCTestRunProcess runCoverageSrc;  runCoverageSrc.SetCommand(program.c_str());  runCoverageSrc.AddArgument(arg);  std::string stdoutFile = cont->BinaryDir + "/Testing/Temporary/";  stdoutFile += this->GetCTestInstance()->GetCurrentTag();  stdoutFile += "-";  stdoutFile += cmd;  std::string stderrFile = stdoutFile;  stdoutFile += ".stdout";  stderrFile += ".stderr";  runCoverageSrc.SetStdoutFile(stdoutFile.c_str());  runCoverageSrc.SetStderrFile(stderrFile.c_str());  if(!runCoverageSrc.StartProcess())    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not run : "               << program.c_str() << " " << arg << "\n"               << "kwsys process state : "               << runCoverageSrc.GetProcessState());    return 0;    }  // since we set the output file names wait for it to end  runCoverageSrc.WaitForExit();  outputFile = stdoutFile;  return 1;}//----------------------------------------------------------------------int cmCTestCoverageHandler::RunBullseyeSourceSummary(  cmCTestCoverageHandlerContainer* cont){  // Run the covsrc command and create a temp outputfile  std::string outputFile;  if(!this->RunBullseyeCommand(cont, "covsrc", "-c", outputFile))    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "error running covsrc:\n");    return 0;    }    std::ostream& tmpLog = *cont->OFS;  // copen the Coverage.xml file in the Testing directory  cmGeneratedFileStream covSumFile;   if(!this->StartResultingXML(cmCTest::PartCoverage, "Coverage", covSumFile))    {    cmCTestLog(this->CTest, ERROR_MESSAGE,      "Cannot open coverage summary file." << std::endl);    return 0;    }  this->CTest->StartXML(covSumFile, this->AppendXML);  double elapsed_time_start = cmSystemTools::GetTime();  std::string coverage_start_time = this->CTest->CurrentTime();  covSumFile << "<Coverage>" << std::endl             << "\t<StartDateTime>"              << coverage_start_time << "</StartDateTime>"             << std::endl             << "\t<StartTime>"              << static_cast<unsigned int>(cmSystemTools::GetTime())             << "</StartTime>"             << std::endl;  std::string stdline;  std::string errline;  // expected output:  // first line is:  // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"  // after that data follows in that format  std::string sourceFile;  int functionsCalled = 0;  int totalFunctions = 0;  int percentFunction = 0;  int branchCovered = 0;  int totalBranches = 0;  int percentBranch = 0;  double total_tested = 0;  double total_untested = 0;  double total_functions = 0;  double percent_coverage =0;  double number_files  = 0;  std::vector<std::string> coveredFiles;  std::vector<std::string> coveredFilesFullPath;  // Read and parse the summary output file  std::ifstream fin(outputFile.c_str());  if(!fin)    {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "Cannot open coverage summary file: " <<               outputFile.c_str() << std::endl);    return 0;    }  std::set<cmStdString> coveredFileNames;  while(cmSystemTools::GetLineFromStream(fin, stdline))    {    // if we have a line of output from stdout    if(stdline.size())      {      // parse the comma separated output      this->ParseBullsEyeCovsrcLine(stdline,                                    sourceFile,                                     functionsCalled,                                    totalFunctions,                                    percentFunction,                                    branchCovered,                                    totalBranches,                                    percentBranch);      // The first line is the header      if(sourceFile == "Source" || sourceFile == "Total")        {        continue;        }      std::string file = sourceFile;      coveredFileNames.insert(file);      if(!cmSystemTools::FileIsFullPath(sourceFile.c_str()))        {        // file will be relative to the binary dir        file = cont->BinaryDir;        file += "/";        file += sourceFile;        }      file = cmSystemTools::CollapseFullPath(file.c_str());      bool shouldIDoCoverage        = this->ShouldIDoCoverage(file.c_str(),                                  cont->SourceDir.c_str(),                                   cont->BinaryDir.c_str());      if ( !shouldIDoCoverage )        {        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                   ".NoDartCoverage found, so skip coverage check for: "                   << file.c_str()                   << std::endl);        continue;        }      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                 "Doing coverage for: "                 << file.c_str()                 << std::endl);      coveredFiles.push_back(sourceFile);      coveredFilesFullPath.push_back(file);      number_files++;      total_functions += totalFunctions;      total_tested += functionsCalled;      total_untested += (totalFunctions - functionsCalled);      std::string fileName = cmSystemTools::GetFilenameName(file.c_str());      std::string shortFileName =        this->CTest->GetShortPathToFile(file.c_str());      float cper = static_cast<float>(percentBranch + percentFunction);      if(totalBranches > 0)        {        cper /= 2.0f;        }      percent_coverage += cper;      float cmet = static_cast<float>(percentFunction + percentBranch);      if(totalBranches > 0)        {        cmet /= 2.0f;        }      cmet /= 100.0f;      tmpLog << stdline.c_str() << "\n";      tmpLog << fileName << "\n";      tmpLog << "functionsCalled: " << functionsCalled/100 << "\n";      tmpLog << "totalFunctions: " << totalFunctions/100 << "\n";      tmpLog << "percentFunction: " << percentFunction << "\n";      tmpLog << "branchCovered: " << branchCovered << "\n";      tmpLog << "totalBranches: " << totalBranches << "\n";      tmpLog << "percentBranch: " << percentBranch << "\n";      tmpLog << "percentCoverage: " << percent_coverage << "\n";      tmpLog << "coverage metric: " << cmet << "\n";      covSumFile << "\t<File Name=\"" << cmXMLSafe(sourceFile)                 << "\" FullPath=\"" << cmXMLSafe(shortFileName)                 << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"                 << "\t\t<BranchesTested>"                 << branchCovered                 << "</BranchesTested>\n"                 << "\t\t<BranchesUnTested>"                  << totalBranches - branchCovered                 << "</BranchesUnTested>\n"                 << "\t\t<FunctionsTested>"                 << functionsCalled                 << "</FunctionsTested>\n"                 << "\t\t<FunctionsUnTested>"                  << totalFunctions - functionsCalled                 << "</FunctionsUnTested>\n"        // Hack for conversion of function to loc assume a function        // has 100 lines of code                 << "\t\t<LOCTested>" << functionsCalled *100                 << "</LOCTested>\n"                 << "\t\t<LOCUnTested>"                  << (totalFunctions - functionsCalled)*100                 << "</LOCUnTested>\n"                 << "\t\t<PercentCoverage>";      covSumFile.setf(std::ios::fixed, std::ios::floatfield);      covSumFile.precision(2);      covSumFile << (cper) << "</PercentCoverage>\n"                 << "\t\t<CoverageMetric>";      covSumFile.setf(std::ios::fixed, std::ios::floatfield);      covSumFile.precision(2);      covSumFile << (cmet) << "</CoverageMetric>\n";      this->WriteXMLLabels(covSumFile, shortFileName);      covSumFile << "\t</File>" << std::endl;      }    }  std::string end_time = this->CTest->CurrentTime();  covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"    << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"    << "\t<LOC>" << total_functions << "</LOC>\n"    << "\t<PercentCoverage>";  covSumFile.setf(std::ios::fixed, std::ios::floatfield);  covSumFile.precision(2);  covSumFile     << SAFEDIV(percent_coverage,number_files)<< "</PercentCoverage>\n"    << "\t<EndDateTime>" << end_time << "</EndDateTime>\n"    << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())    << "</EndTime>\n";  covSumFile     << "<ElapsedMinutes>" <<    static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0    << "</ElapsedMinutes>"    << "</Coverage>" << std::endl;  this->CTest->EndXML(covSumFile);  // Now create the coverage information for each file  return this->RunBullseyeCoverageBranch(cont,                                         coveredFileNames,                                         coveredFiles,                                         coveredFilesFullPath);}//----------------------------------------------------------------------int cmCTestCoverageHandler::HandleBullseyeCoverage(  cmCTestCoverageHandlerContainer* cont){  const char* covfile = cmSystemTools::GetEnv("COVFILE");  if(!covfile)    {    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                " COVFILE environment variable not found, not running "                " bullseye\n");    return 0;    }  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,              " run covsrc with COVFILE=["              << covfile             << "]" << std::endl);  if(!this->RunBullseyeSourceSummary(cont))    {     cmCTestLog(this->CTest, ERROR_MESSAGE,                "Error running bullseye summary.\n");    return 0;    }  cmCTestLog(this->CTest, DEBUG, "HandleBullseyeCoverage return 1 "               << std::endl);  return 1;}bool cmCTestCoverageHandler::GetNextInt(std::string const& inputLine,                                        std::string::size_type& pos,                                        int& value){   std::string::size_type start = pos;  pos = inputLine.find(',', start);  value = atoi(inputLine.substr(start, pos).c_str());  if(pos == inputLine.npos)    {    return true;    }  pos++;  return true;}                                                 bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(  std::string const& inputLine,  std::string& sourceFile,  int& functionsCalled,  int& totalFunctions,  int& percentFunction,  int& branchCovered,  int& totalBranches,  int& percentBranch){  // find the first comma  std::string::size_type pos = inputLine.find(',');  if(pos == inputLine.npos)    {     cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing string : "               << inputLine.c_str() << "\n");    return false;    }  // the source file has "" around it so extract out the file name  sourceFile = inputLine.substr(1,pos-2);  pos++;  if(!this->GetNextInt(inputLine, pos, functionsCalled))    {    return false;    }  if(!this->GetNextInt(inputLine, pos, totalFunctions))    {    return false;    }  if(!this->GetNextInt(inputLine, pos, percentFunction))    {    return false;    }  if(!this->GetNextInt(inputLine, pos, branchCovered))    {    return false;    }  if(!this->GetNextInt(inputLine, pos, totalBranches))    {    return false;    }  if(!this->GetNextInt(inputLine, pos, percentBranch))    {    return false;    }  // should be at the end now  if(pos != inputLine.npos)    {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing input : "               << inputLine.c_str() << " last pos not npos =  " << pos <<                "\n");    }  return true;}//----------------------------------------------------------------------int cmCTestCoverageHandler::GetLabelId(std::string const& label){  LabelIdMapType::iterator i = this->LabelIdMap.find(label);  if(i == this->LabelIdMap.end())    {    int n = int(this->Labels.size());    this->Labels.push_back(label);    LabelIdMapType::value_type entry(label, n);    i = this->LabelIdMap.insert(entry).first;    }  return i->second;}//----------------------------------------------------------------------void cmCTestCoverageHandler::LoadLabels(){  std::string fileList = this->CTest->GetBinaryDir();  fileList += cmake::GetCMakeFilesDirectory();  fileList += "/TargetDirectories.txt";  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,             " target directory list [" << fileList << "]\n");  std::ifstream finList(fileList.c_str());  std::string line;  while(cmSystemTools::GetLineFromStream(finList, line))    {    this->LoadLabels(line.c_str());    }}//----------------------------------------------------------------------void cmCTestCoverageHandler::LoadLabels(const char* dir){  LabelSet& dirLabels = this->TargetDirs[dir];  std::string fname = dir;  fname += "/Labels.txt";  std::ifstream fin(fname.c_str());  if(!fin)    {    return;    }  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,             " loading labels from [" << fname << "]\n");  bool inTarget = true;  std::string source;  std::string line;  std::vector<int> targetLabels;  while(cmSystemTools::GetLineFromStream(fin, line))    {    if(line.empty() || line[0] == '#')      {      // Ignore blank and comment lines.      continue;      }    else if(line[0] == ' ')      {      // Label lines appear indented by one space.      std::string label = line.substr(1);      int id = this->GetLabelId(label);      dirLabels.insert(id);      if(inTarget)        {        targetLabels.push_back(id);        }      else        {        this->SourceLabels[source].insert(id);        }      }    else      {      // Non-indented lines specify a source file name.  The first one      // is the end of the target-wide labels.      inTarget = false;      source = this->CTest->GetShortPathToFile(line.c_str());      // Label the source with the target labels.      LabelSet& labelSet = this->SourceLabels[source];      for(std::vector<int>::const_iterator li = targetLabels.begin();          li != targetLabels.end(); ++li)        {        labelSet.insert(*li);        }      }    }}//----------------------------------------------------------------------void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os,                                            std::string const& source){  LabelMapType::const_iterator li = this->SourceLabels.find(source);  if(li != this->SourceLabels.end() && !li->second.empty())    {    os << "\t\t<Labels>\n";    for(LabelSet::const_iterator lsi = li->second.begin();        lsi != li->second.end(); ++lsi)      {      os << "\t\t\t<Label>" << cmXMLSafe(this->Labels[*lsi]) << "</Label>\n";      }    os << "\t\t</Labels>\n";    }}//----------------------------------------------------------------------------voidcmCTestCoverageHandler::SetLabelFilter(std::set<cmStdString> const& labels){  this->LabelFilter.clear();  for(std::set<cmStdString>::const_iterator li = labels.begin();      li != labels.end(); ++li)    {    this->LabelFilter.insert(this->GetLabelId(*li));    }}//----------------------------------------------------------------------bool cmCTestCoverageHandler::IntersectsFilter(LabelSet const& labels){  // If there is no label filter then nothing is filtered out.  if(this->LabelFilter.empty())    {    return true;    }  std::vector<int> ids;  cmsys_stl::set_intersection    (labels.begin(), labels.end(),     this->LabelFilter.begin(), this->LabelFilter.end(),     cmsys_stl::back_inserter(ids));  return !ids.empty();}//----------------------------------------------------------------------bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source){  // If there is no label filter then nothing is filtered out.  if(this->LabelFilter.empty())    {    return false;    }  // The source is filtered out if it does not have any labels in  // common with the filter set.  std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str());  LabelMapType::const_iterator li = this->SourceLabels.find(shortSrc);  if(li != this->SourceLabels.end())    {    return !this->IntersectsFilter(li->second);    }  return true;}//----------------------------------------------------------------------std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(  cmCTestCoverageHandlerContainer* cont){  std::set<std::string> extraMatches;  for(std::vector<cmStdString>::iterator i = this->ExtraCoverageGlobs.begin();      i != this->ExtraCoverageGlobs.end(); ++i)    {    cmsys::Glob gl;    gl.RecurseOn();    gl.RecurseThroughSymlinksOff();    std::string glob = cont->BinaryDir + "/" + *i;    gl.FindFiles(glob);    std::vector<std::string> files = gl.GetFiles();    extraMatches.insert(files.begin(), files.end());    }  if(extraMatches.size())    {    for(cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =        cont->TotalCoverage.begin(); i != cont->TotalCoverage.end(); ++i)      {      extraMatches.erase(i->first);      }    }  return extraMatches;}
 |