1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestCoverageHandler.cxx,v $
6 Date: $Date: 2008-11-23 15:49:46 $
7 Version: $Revision: 1.57 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmCTestCoverageHandler.h"
20 #include "cmSystemTools.h"
21 #include "cmGeneratedFileStream.h"
23 #include <cmsys/Process.h>
24 #include <cmsys/RegularExpression.hxx>
25 #include <cmsys/Glob.hxx>
31 #define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
33 class cmCTestRunProcess
38 this->Process
= cmsysProcess_New();
44 if(!(this->PipeState
== -1)
45 && !(this->PipeState
== cmsysProcess_Pipe_None
)
46 && !(this->PipeState
== cmsysProcess_Pipe_Timeout
))
50 cmsysProcess_Delete(this->Process
);
52 void SetCommand(const char* command
)
54 this->CommandLineStrings
.clear();
55 this->CommandLineStrings
.push_back(command
);;
57 void AddArgument(const char* arg
)
61 this->CommandLineStrings
.push_back(arg
);
64 void SetWorkingDirectory(const char* dir
)
66 this->WorkingDirectory
= dir
;
68 void SetTimeout(double t
)
74 std::vector
<const char*> args
;
75 for(std::vector
<std::string
>::iterator i
=
76 this->CommandLineStrings
.begin();
77 i
!= this->CommandLineStrings
.end(); ++i
)
79 args
.push_back(i
->c_str());
81 args
.push_back(0); // null terminate
82 cmsysProcess_SetCommand(this->Process
, &*args
.begin());
83 if(this->WorkingDirectory
.size())
85 cmsysProcess_SetWorkingDirectory(this->Process
,
86 this->WorkingDirectory
.c_str());
89 cmsysProcess_SetOption(this->Process
,
90 cmsysProcess_Option_HideWindow
, 1);
91 if(this->TimeOut
!= -1)
93 cmsysProcess_SetTimeout(this->Process
, this->TimeOut
);
95 cmsysProcess_Execute(this->Process
);
96 this->PipeState
= cmsysProcess_GetState(this->Process
);
97 // if the process is running or exited return true
98 if(this->PipeState
== cmsysProcess_State_Executing
99 || this->PipeState
== cmsysProcess_State_Exited
)
105 void SetStdoutFile(const char* fname
)
107 cmsysProcess_SetPipeFile(this->Process
, cmsysProcess_Pipe_STDOUT
, fname
);
109 void SetStderrFile(const char* fname
)
111 cmsysProcess_SetPipeFile(this->Process
, cmsysProcess_Pipe_STDERR
, fname
);
113 int WaitForExit(double* timeout
=0)
115 this->PipeState
= cmsysProcess_WaitForExit(this->Process
,
117 return this->PipeState
;
119 int GetProcessState() { return this->PipeState
;}
122 cmsysProcess
* Process
;
123 std::vector
<std::string
> CommandLineStrings
;
124 std::string WorkingDirectory
;
129 //----------------------------------------------------------------------
130 //**********************************************************************
131 class cmCTestCoverageHandlerContainer
135 std::string SourceDir
;
136 std::string BinaryDir
;
137 typedef std::vector
<int> SingleFileCoverageVector
;
138 typedef std::map
<std::string
, SingleFileCoverageVector
> TotalCoverageMap
;
139 TotalCoverageMap TotalCoverage
;
142 //**********************************************************************
143 //----------------------------------------------------------------------
145 //----------------------------------------------------------------------
146 cmCTestCoverageHandler::cmCTestCoverageHandler()
150 //----------------------------------------------------------------------
151 void cmCTestCoverageHandler::Initialize()
153 this->Superclass::Initialize();
154 this->CustomCoverageExclude
.empty();
157 //----------------------------------------------------------------------
158 bool cmCTestCoverageHandler::StartCoverageLogFile(
159 cmGeneratedFileStream
& covLogFile
, int logFileCount
)
161 char covLogFilename
[1024];
162 sprintf(covLogFilename
, "CoverageLog-%d", logFileCount
);
163 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Open file: "
164 << covLogFilename
<< std::endl
);
165 if (!this->StartResultingXML(covLogFilename
, covLogFile
) )
167 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open log file: "
168 << covLogFilename
<< std::endl
);
171 std::string local_start_time
= this->CTest
->CurrentTime();
172 this->CTest
->StartXML(covLogFile
);
173 covLogFile
<< "<CoverageLog>" << std::endl
174 << "\t<StartDateTime>" << local_start_time
<< "</StartDateTime>"
176 << static_cast<unsigned int>(cmSystemTools::GetTime())
182 //----------------------------------------------------------------------
183 void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream
& ostr
,
186 std::string local_end_time
= this->CTest
->CurrentTime();
187 ostr
<< "\t<EndDateTime>" << local_end_time
<< "</EndDateTime>" << std::endl
189 static_cast<unsigned int>(cmSystemTools::GetTime())
190 << "</EndTime>" << std::endl
191 << "</CoverageLog>" << std::endl
;
192 this->CTest
->EndXML(ostr
);
193 char covLogFilename
[1024];
194 sprintf(covLogFilename
, "CoverageLog-%d.xml", logFileCount
);
195 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Close file: "
196 << covLogFilename
<< std::endl
);
200 //----------------------------------------------------------------------
201 bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file
,
205 std::vector
<cmsys::RegularExpression
>::iterator sit
;
206 for ( sit
= this->CustomCoverageExcludeRegex
.begin();
207 sit
!= this->CustomCoverageExcludeRegex
.end(); ++ sit
)
209 if ( sit
->find(file
) )
211 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " File " << file
212 << " is excluded in CTestCustom.ctest" << std::endl
;);
217 std::string fSrcDir
= cmSystemTools::CollapseFullPath(srcDir
);
218 std::string fBinDir
= cmSystemTools::CollapseFullPath(binDir
);
219 std::string fFile
= cmSystemTools::CollapseFullPath(file
);
220 bool sourceSubDir
= cmSystemTools::IsSubDirectory(fFile
.c_str(),
222 bool buildSubDir
= cmSystemTools::IsSubDirectory(fFile
.c_str(),
224 // Always check parent directory of the file.
225 std::string fileDir
= cmSystemTools::GetFilenamePath(fFile
.c_str());
226 std::string checkDir
;
228 // We also need to check the binary/source directory pair.
229 if ( sourceSubDir
&& buildSubDir
)
231 if ( fSrcDir
.size() > fBinDir
.size() )
240 else if ( sourceSubDir
)
244 else if ( buildSubDir
)
249 = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
250 fFile
.c_str(), checkDir
.c_str());
253 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Found: " << ndc
.c_str()
254 << " so skip coverage of " << file
<< std::endl
);
258 // By now checkDir should be set to parent directory of the file.
259 // Get the relative path to the file an apply it to the opposite directory.
260 // If it is the same as fileDir, then ignore, otherwise check.
264 relPath
= cmSystemTools::RelativePath(checkDir
.c_str(),
271 if ( checkDir
== fSrcDir
)
279 fFile
= checkDir
+ "/" + relPath
;
280 fFile
= cmSystemTools::GetFilenamePath(fFile
.c_str());
282 if ( fileDir
== fFile
)
284 // This is in-source build, so we trust the previous check.
288 ndc
= cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
289 fFile
.c_str(), checkDir
.c_str());
292 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Found: " << ndc
.c_str()
293 << " so skip coverage of: " << file
<< std::endl
);
296 // Ok, nothing in source tree, nothing in binary tree
300 //----------------------------------------------------------------------
301 //clearly it would be nice if this were broken up into a few smaller
302 //functions and commented...
303 int cmCTestCoverageHandler::ProcessHandler()
306 // do we have time for this
307 if (this->CTest
->GetRemainingTimeAllowed() < 120)
312 std::string coverage_start_time
= this->CTest
->CurrentTime();
313 unsigned int coverage_start_time_time
= static_cast<unsigned int>(
314 cmSystemTools::GetTime());
315 std::string sourceDir
316 = this->CTest
->GetCTestConfiguration("SourceDirectory");
317 std::string binaryDir
318 = this->CTest
->GetCTestConfiguration("BuildDirectory");
320 cmGeneratedFileStream ofs
;
321 double elapsed_time_start
= cmSystemTools::GetTime();
322 if ( !this->StartLogFile("Coverage", ofs
) )
324 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
325 "Cannot create LastCoverage.log file" << std::endl
);
328 ofs
<< "Performing coverage: " << elapsed_time_start
<< std::endl
;
330 cmSystemTools::ConvertToUnixSlashes(sourceDir
);
331 cmSystemTools::ConvertToUnixSlashes(binaryDir
);
333 std::string asfGlob
= sourceDir
+ "/*";
334 std::string abfGlob
= binaryDir
+ "/*";
336 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "Performing coverage" << std::endl
);
338 cmCTestCoverageHandlerContainer cont
;
340 cont
.SourceDir
= sourceDir
;
341 cont
.BinaryDir
= binaryDir
;
344 // setup the regex exclude stuff
345 this->CustomCoverageExcludeRegex
.empty();
346 std::vector
<cmStdString
>::iterator rexIt
;
347 for ( rexIt
= this->CustomCoverageExclude
.begin();
348 rexIt
!= this->CustomCoverageExclude
.end();
351 this->CustomCoverageExcludeRegex
.push_back(
352 cmsys::RegularExpression(rexIt
->c_str()));
356 if(this->HandleBullseyeCoverage(&cont
))
361 file_count
+= this->HandleGCovCoverage(&cont
);
362 if ( file_count
< 0 )
366 file_count
+= this->HandleTracePyCoverage(&cont
);
367 if ( file_count
< 0 )
374 if ( file_count
== 0 )
376 cmCTestLog(this->CTest
, WARNING
,
377 " Cannot find any coverage files. Ignoring Coverage request."
381 cmGeneratedFileStream covSumFile
;
382 cmGeneratedFileStream covLogFile
;
384 if (!this->StartResultingXML("Coverage", covSumFile
))
386 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
387 "Cannot open coverage summary file." << std::endl
);
391 this->CTest
->StartXML(covSumFile
);
392 // Produce output xml files
394 covSumFile
<< "<Coverage>" << std::endl
395 << "\t<StartDateTime>" << coverage_start_time
<< "</StartDateTime>"
397 << "\t<StartTime>" << coverage_start_time_time
<< "</StartTime>"
399 int logFileCount
= 0;
400 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
404 cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator
;
406 long total_tested
= 0;
407 long total_untested
= 0;
408 //std::string fullSourceDir = sourceDir + "/";
409 //std::string fullBinaryDir = binaryDir + "/";
410 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, std::endl
);
411 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
412 " Acumulating results (each . represents one file):" << std::endl
);
413 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
415 std::vector
<std::string
> errorsWhileAccumulating
;
418 for ( fileIterator
= cont
.TotalCoverage
.begin();
419 fileIterator
!= cont
.TotalCoverage
.end();
422 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "." << std::flush
);
424 if ( file_count
% 50 == 0 )
426 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " processed: " << file_count
428 << cont
.TotalCoverage
.size() << std::endl
);
429 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
431 if ( cnt
% 100 == 0 )
433 this->EndCoverageLogFile(covLogFile
, logFileCount
);
435 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
440 const std::string fullFileName
= fileIterator
->first
;
441 const std::string fileName
442 = cmSystemTools::GetFilenameName(fullFileName
.c_str());
443 std::string fullFilePath
444 = cmSystemTools::GetFilenamePath(fullFileName
.c_str());
445 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
446 "Process file: " << fullFileName
<< std::endl
);
448 cmSystemTools::ConvertToUnixSlashes(fullFilePath
);
450 if ( !cmSystemTools::FileExists(fullFileName
.c_str()) )
452 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot find file: "
453 << fullFileName
.c_str() << std::endl
);
457 bool shouldIDoCoverage
458 = this->ShouldIDoCoverage(fullFileName
.c_str(),
459 sourceDir
.c_str(), binaryDir
.c_str());
460 if ( !shouldIDoCoverage
)
462 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
463 ".NoDartCoverage found, so skip coverage check for: "
464 << fullFileName
.c_str()
469 const cmCTestCoverageHandlerContainer::SingleFileCoverageVector
& fcov
470 = fileIterator
->second
;
471 covLogFile
<< "\t<File Name=\""
472 << this->CTest
->MakeXMLSafe(fileName
.c_str())
473 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
474 this->CTest
->GetShortPathToFile(
475 fileIterator
->first
.c_str())) << "\">" << std::endl
476 << "\t\t<Report>" << std::endl
;
478 std::ifstream
ifs(fullFileName
.c_str());
481 cmOStringStream ostr
;
482 ostr
<< "Cannot open source file: " << fullFileName
.c_str();
483 errorsWhileAccumulating
.push_back(ostr
.str());
491 cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc
;
493 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
494 "Actually perfoming coverage for: " << fullFileName
<< std::endl
);
495 for ( cc
= 0; cc
< fcov
.size(); cc
++ )
497 if ( !cmSystemTools::GetLineFromStream(ifs
, line
) &&
498 cc
!= fcov
.size() -1 )
500 cmOStringStream ostr
;
501 ostr
<< "Problem reading source file: " << fullFileName
.c_str()
503 errorsWhileAccumulating
.push_back(ostr
.str());
507 covLogFile
<< "\t\t<Line Number=\"" << cc
<< "\" Count=\"" << fcov
[cc
]
509 << this->CTest
->MakeXMLSafe(line
.c_str()) << "</Line>" << std::endl
;
514 else if ( fcov
[cc
] > 0 )
519 if ( cmSystemTools::GetLineFromStream(ifs
, line
) )
521 cmOStringStream ostr
;
522 ostr
<< "Looks like there are more lines in the file: " << line
;
523 errorsWhileAccumulating
.push_back(ostr
.str());
527 if ( tested
+ untested
> 0 )
529 cper
= (100 * SAFEDIV(static_cast<float>(tested
),
530 static_cast<float>(tested
+ untested
)));
531 cmet
= ( SAFEDIV(static_cast<float>(tested
+ 10),
532 static_cast<float>(tested
+ untested
+ 10)));
534 total_tested
+= tested
;
535 total_untested
+= untested
;
536 covLogFile
<< "\t\t</Report>" << std::endl
537 << "\t</File>" << std::endl
;
538 covSumFile
<< "\t<File Name=\"" << this->CTest
->MakeXMLSafe(fileName
)
539 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
540 this->CTest
->GetShortPathToFile(fullFileName
.c_str()))
541 << "\" Covered=\"" << (tested
> 0 ? "true":"false") << "\">\n"
542 << "\t\t<LOCTested>" << tested
<< "</LOCTested>\n"
543 << "\t\t<LOCUnTested>" << untested
<< "</LOCUnTested>\n"
544 << "\t\t<PercentCoverage>";
545 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
546 covSumFile
.precision(2);
547 covSumFile
<< (cper
) << "</PercentCoverage>\n"
548 << "\t\t<CoverageMetric>";
549 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
550 covSumFile
.precision(2);
551 covSumFile
<< (cmet
) << "</CoverageMetric>\n"
552 << "\t</File>" << std::endl
;
555 this->EndCoverageLogFile(covLogFile
, logFileCount
);
557 if ( errorsWhileAccumulating
.size() > 0 )
559 cmCTestLog(this->CTest
, ERROR_MESSAGE
, std::endl
);
560 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
561 "Error(s) while acumulating results:" << std::endl
);
562 std::vector
<std::string
>::iterator erIt
;
563 for ( erIt
= errorsWhileAccumulating
.begin();
564 erIt
!= errorsWhileAccumulating
.end();
567 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
568 " " << erIt
->c_str() << std::endl
);
572 int total_lines
= total_tested
+ total_untested
;
573 float percent_coverage
= 100 * SAFEDIV(static_cast<float>(total_tested
),
574 static_cast<float>(total_lines
));
575 if ( total_lines
== 0 )
577 percent_coverage
= 0;
580 std::string end_time
= this->CTest
->CurrentTime();
582 covSumFile
<< "\t<LOCTested>" << total_tested
<< "</LOCTested>\n"
583 << "\t<LOCUntested>" << total_untested
<< "</LOCUntested>\n"
584 << "\t<LOC>" << total_lines
<< "</LOC>\n"
585 << "\t<PercentCoverage>";
586 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
587 covSumFile
.precision(2);
588 covSumFile
<< (percent_coverage
)<< "</PercentCoverage>\n"
589 << "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n"
591 static_cast<unsigned int>(cmSystemTools::GetTime())
593 covSumFile
<< "<ElapsedMinutes>" <<
594 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
595 << "</ElapsedMinutes>"
596 << "</Coverage>" << std::endl
;
597 this->CTest
->EndXML(covSumFile
);
599 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "" << std::endl
601 << total_tested
<< std::endl
602 << "\tNot covered LOC: " << total_untested
<< std::endl
603 << "\tTotal LOC: " << total_lines
<< std::endl
604 << "\tPercentage Coverage: "
605 << std::setiosflags(std::ios::fixed
)
606 << std::setprecision(2)
607 << (percent_coverage
) << "%" << std::endl
);
609 ofs
<< "\tCovered LOC: " << total_tested
<< std::endl
610 << "\tNot covered LOC: " << total_untested
<< std::endl
611 << "\tTotal LOC: " << total_lines
<< std::endl
612 << "\tPercentage Coverage: "
613 << std::setiosflags(std::ios::fixed
)
614 << std::setprecision(2)
615 << (percent_coverage
) << "%" << std::endl
;
625 //----------------------------------------------------------------------
626 void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile
*mf
)
628 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
629 " Add coverage exclude regular expressions." << std::endl
);
630 this->CTest
->PopulateCustomVector(mf
, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
631 this->CustomCoverageExclude
);
632 std::vector
<cmStdString
>::iterator it
;
633 for ( it
= this->CustomCoverageExclude
.begin();
634 it
!= this->CustomCoverageExclude
.end();
637 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Add coverage exclude: "
638 << it
->c_str() << std::endl
);
642 //----------------------------------------------------------------------
643 // Fix for issue #4971 where the case of the drive letter component of
644 // the filenames might be different when analyzing gcov output.
646 // Compare file names: fnc(fn1) == fnc(fn2) // fnc == file name compare
649 #define fnc(s) cmSystemTools::LowerCase(s)
654 //----------------------------------------------------------------------
655 int cmCTestCoverageHandler::HandleGCovCoverage(
656 cmCTestCoverageHandlerContainer
* cont
)
658 std::string gcovCommand
659 = this->CTest
->GetCTestConfiguration("CoverageCommand");
662 std::string st1gcovOutputRex1
663 = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
664 std::string st1gcovOutputRex2
= "^Creating (.*\\.gcov)\\.";
665 cmsys::RegularExpression
st1re1(st1gcovOutputRex1
.c_str());
666 cmsys::RegularExpression
st1re2(st1gcovOutputRex2
.c_str());
670 std::string st2gcovOutputRex1
= "^File *[`'](.*)'$";
671 std::string st2gcovOutputRex2
672 = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
673 std::string st2gcovOutputRex3
= "^(.*):creating [`'](.*\\.gcov)'";
674 std::string st2gcovOutputRex4
= "^(.*):unexpected EOF *$";
675 std::string st2gcovOutputRex5
= "^(.*):cannot open source file*$";
676 std::string st2gcovOutputRex6
677 = "^(.*):source file is newer than graph file `(.*)'$";
678 cmsys::RegularExpression
st2re1(st2gcovOutputRex1
.c_str());
679 cmsys::RegularExpression
st2re2(st2gcovOutputRex2
.c_str());
680 cmsys::RegularExpression
st2re3(st2gcovOutputRex3
.c_str());
681 cmsys::RegularExpression
st2re4(st2gcovOutputRex4
.c_str());
682 cmsys::RegularExpression
st2re5(st2gcovOutputRex5
.c_str());
683 cmsys::RegularExpression
st2re6(st2gcovOutputRex6
.c_str());
688 gl
.RecurseThroughSymlinksOff();
689 std::string daGlob
= cont
->BinaryDir
+ "/*.da";
690 gl
.FindFiles(daGlob
);
691 std::vector
<std::string
> files
= gl
.GetFiles();
692 daGlob
= cont
->BinaryDir
+ "/*.gcda";
693 gl
.FindFiles(daGlob
);
694 std::vector
<std::string
>& moreFiles
= gl
.GetFiles();
695 files
.insert(files
.end(), moreFiles
.begin(), moreFiles
.end());
696 std::vector
<std::string
>::iterator it
;
698 if ( files
.size() == 0 )
700 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
701 " Cannot find any GCov coverage files."
703 // No coverage files is a valid thing, so the exit code is 0
707 std::string testingDir
= this->CTest
->GetBinaryDir() + "/Testing";
708 std::string tempDir
= testingDir
+ "/CoverageInfo";
709 std::string currentDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
710 cmSystemTools::MakeDirectory(tempDir
.c_str());
711 cmSystemTools::ChangeDirectory(tempDir
.c_str());
715 std::set
<std::string
> missingFiles
;
717 std::string actualSourceFile
= "";
718 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
719 " Processing coverage (each . represents one file):" << std::endl
);
720 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
722 // make sure output from gcov is in English!
723 cmSystemTools::PutEnv("LC_ALL=POSIX");
724 for ( it
= files
.begin(); it
!= files
.end(); ++ it
)
726 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "." << std::flush
);
727 std::string fileDir
= cmSystemTools::GetFilenamePath(it
->c_str());
728 std::string command
= "\"" + gcovCommand
+ "\" -l -o \"" + fileDir
729 + "\" \"" + *it
+ "\"";
730 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, command
.c_str()
732 std::string output
= "";
733 std::string errors
= "";
735 *cont
->OFS
<< "* Run coverage for: " << fileDir
.c_str() << std::endl
;
736 *cont
->OFS
<< " Command: " << command
.c_str() << std::endl
;
737 int res
= this->CTest
->RunCommand(command
.c_str(), &output
, &errors
,
738 &retVal
, tempDir
.c_str(), 0 /*this->TimeOut*/);
740 *cont
->OFS
<< " Output: " << output
.c_str() << std::endl
;
741 *cont
->OFS
<< " Errors: " << errors
.c_str() << std::endl
;
744 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
745 "Problem running coverage on file: " << it
->c_str() << std::endl
);
746 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
747 "Command produced error: " << errors
<< std::endl
);
753 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Coverage command returned: "
754 << retVal
<< " while processing: " << it
->c_str() << std::endl
);
755 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
756 "Command produced error: " << cont
->Error
<< std::endl
);
758 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
759 "--------------------------------------------------------------"
761 << output
<< std::endl
762 << "--------------------------------------------------------------"
764 std::vector
<cmStdString
> lines
;
765 std::vector
<cmStdString
>::iterator line
;
768 // Globals for storing current source file and current gcov file;
769 cmSystemTools::Split(output
.c_str(), lines
);
770 for ( line
= lines
.begin(); line
!= lines
.end(); ++line
)
772 std::string sourceFile
;
773 std::string gcovFile
;
774 cmCTestLog(this->CTest
, DEBUG
, "Line: [" << line
->c_str() << "]"
776 if ( line
->size() == 0 )
778 // Ignore empty line; probably style 2
780 else if ( st1re1
.find(line
->c_str()) )
782 if ( gcovStyle
!= 0 )
784 if ( gcovStyle
!= 1 )
786 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
794 actualSourceFile
= "";
795 sourceFile
= st1re1
.match(2);
797 else if ( st1re2
.find(line
->c_str() ) )
799 if ( gcovStyle
!= 0 )
801 if ( gcovStyle
!= 1 )
803 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
811 gcovFile
= st1re2
.match(1);
813 else if ( st2re1
.find(line
->c_str() ) )
815 if ( gcovStyle
!= 0 )
817 if ( gcovStyle
!= 2 )
819 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
827 actualSourceFile
= "";
828 sourceFile
= st2re1
.match(1);
830 else if ( st2re2
.find(line
->c_str() ) )
832 if ( gcovStyle
!= 0 )
834 if ( gcovStyle
!= 2 )
836 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
844 else if ( st2re3
.find(line
->c_str() ) )
846 if ( gcovStyle
!= 0 )
848 if ( gcovStyle
!= 2 )
850 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
858 gcovFile
= st2re3
.match(2);
860 else if ( st2re4
.find(line
->c_str() ) )
862 if ( gcovStyle
!= 0 )
864 if ( gcovStyle
!= 2 )
866 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
874 cmCTestLog(this->CTest
, WARNING
, "Warning: " << st2re4
.match(1)
875 << " had unexpected EOF" << std::endl
);
877 else if ( st2re5
.find(line
->c_str() ) )
879 if ( gcovStyle
!= 0 )
881 if ( gcovStyle
!= 2 )
883 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
891 cmCTestLog(this->CTest
, WARNING
, "Warning: Cannot open file: "
892 << st2re5
.match(1) << std::endl
);
894 else if ( st2re6
.find(line
->c_str() ) )
896 if ( gcovStyle
!= 0 )
898 if ( gcovStyle
!= 2 )
900 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
908 cmCTestLog(this->CTest
, WARNING
, "Warning: File: " << st2re6
.match(1)
909 << " is newer than " << st2re6
.match(2) << std::endl
);
913 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
914 "Unknown line: [" << line
->c_str() << "]" << std::endl
);
918 if ( !gcovFile
.empty() && actualSourceFile
.size() )
920 cmCTestCoverageHandlerContainer::SingleFileCoverageVector
* vec
921 = &cont
->TotalCoverage
[actualSourceFile
];
922 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " in file: "
923 << gcovFile
<< std::endl
);
924 std::ifstream
ifile(gcovFile
.c_str());
927 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open file: "
928 << gcovFile
<< std::endl
);
934 while ( cmSystemTools::GetLineFromStream(ifile
, nl
) )
938 //TODO: Handle gcov 3.0 non-coverage lines
947 if ( nl
.size() < 12 )
952 // Read the coverage count from the beginning of the gcov output
954 std::string prefix
= nl
.substr(0, 12);
955 int cov
= atoi(prefix
.c_str());
956 // Read the line number starting at the 10th character of the gcov
958 std::string lineNumber
= nl
.substr(10, 5);
959 int lineIdx
= atoi(lineNumber
.c_str())-1;
962 while ( vec
->size() <=
963 static_cast<size_t>(lineIdx
) )
967 // Initially all entries are -1 (not used). If we get coverage
968 // information, increment it to 0 first.
969 if ( (*vec
)[lineIdx
] < 0 )
971 if ( cov
> 0 || prefix
.find("#") != prefix
.npos
)
976 (*vec
)[lineIdx
] += cov
;
980 actualSourceFile
= "";
982 if ( !sourceFile
.empty() && actualSourceFile
.empty() )
986 // Is it in the source dir?
987 if ( sourceFile
.size() > cont
->SourceDir
.size() &&
988 (fnc(sourceFile
.substr(0, cont
->SourceDir
.size())) ==
989 fnc(cont
->SourceDir
)) &&
990 sourceFile
[cont
->SourceDir
.size()] == '/' )
992 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " produced s: "
993 << sourceFile
.c_str() << std::endl
);
994 *cont
->OFS
<< " produced in source dir: " << sourceFile
.c_str()
997 = cmSystemTools::CollapseFullPath(sourceFile
.c_str());
1001 if ( sourceFile
.size() > cont
->BinaryDir
.size() &&
1002 (fnc(sourceFile
.substr(0, cont
->BinaryDir
.size())) ==
1003 fnc(cont
->BinaryDir
)) &&
1004 sourceFile
[cont
->BinaryDir
.size()] == '/' )
1006 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " produced b: "
1007 << sourceFile
.c_str() << std::endl
);
1008 *cont
->OFS
<< " produced in binary dir: " << sourceFile
.c_str()
1011 = cmSystemTools::CollapseFullPath(sourceFile
.c_str());
1014 if ( actualSourceFile
.empty() )
1016 if ( missingFiles
.find(actualSourceFile
) == missingFiles
.end() )
1018 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1019 "Something went wrong" << std::endl
);
1020 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1021 "Cannot find file: ["
1022 << sourceFile
.c_str() << "]" << std::endl
);
1023 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1025 << cont
->SourceDir
.c_str() << "]"
1027 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1029 << cont
->BinaryDir
.size() << "]"
1031 *cont
->OFS
<< " Something went wrong. Cannot find file: "
1032 << sourceFile
.c_str()
1033 << " in source dir: " << cont
->SourceDir
.c_str()
1034 << " or binary dir: " << cont
->BinaryDir
.c_str() << std::endl
;
1035 missingFiles
.insert(actualSourceFile
);
1041 if ( file_count
% 50 == 0 )
1043 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " processed: " << file_count
1044 << " out of " << files
.size() << std::endl
);
1045 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
1048 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1052 //----------------------------------------------------------------------
1053 int cmCTestCoverageHandler::HandleTracePyCoverage(
1054 cmCTestCoverageHandlerContainer
* cont
)
1058 gl
.RecurseThroughSymlinksOff();
1059 std::string daGlob
= cont
->BinaryDir
+ "/*.cover";
1060 gl
.FindFiles(daGlob
);
1061 std::vector
<std::string
> files
= gl
.GetFiles();
1063 if ( files
.size() == 0 )
1065 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1066 " Cannot find any Python Trace.py coverage files."
1068 // No coverage files is a valid thing, so the exit code is 0
1072 std::string testingDir
= this->CTest
->GetBinaryDir() + "/Testing";
1073 std::string tempDir
= testingDir
+ "/CoverageInfo";
1074 std::string currentDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
1075 cmSystemTools::MakeDirectory(tempDir
.c_str());
1076 cmSystemTools::ChangeDirectory(tempDir
.c_str());
1078 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1080 std::vector
<std::string
>::iterator fileIt
;
1082 for ( fileIt
= files
.begin(); fileIt
!= files
.end(); ++ fileIt
)
1084 std::string fileName
= this->FindFile(cont
, *fileIt
);
1085 if ( fileName
.empty() )
1087 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1088 "Cannot find source Python file corresponding to: "
1089 << fileIt
->c_str() << std::endl
);
1093 std::string actualSourceFile
1094 = cmSystemTools::CollapseFullPath(fileName
.c_str());
1095 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1096 " Check coverage for file: " << actualSourceFile
.c_str()
1098 cmCTestCoverageHandlerContainer::SingleFileCoverageVector
* vec
1099 = &cont
->TotalCoverage
[actualSourceFile
];
1100 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1101 " in file: " << fileIt
->c_str() << std::endl
);
1102 std::ifstream
ifile(fileIt
->c_str());
1105 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open file: "
1106 << fileIt
->c_str() << std::endl
);
1112 while ( cmSystemTools::GetLineFromStream(ifile
, nl
) )
1122 // Skip unused lines
1123 if ( nl
.size() < 12 )
1128 // Read the coverage count from the beginning of the Trace.py output
1130 std::string prefix
= nl
.substr(0, 6);
1131 if ( prefix
[5] != ' ' && prefix
[5] != ':' )
1133 // This is a hack. We should really do something more elaborate
1134 prefix
= nl
.substr(0, 7);
1135 if ( prefix
[6] != ' ' && prefix
[6] != ':' )
1137 prefix
= nl
.substr(0, 8);
1138 if ( prefix
[7] != ' ' && prefix
[7] != ':' )
1140 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1141 "Currently the limit is maximum coverage of 999999"
1146 int cov
= atoi(prefix
.c_str());
1147 if ( prefix
[prefix
.size()-1] != ':' )
1149 // This line does not have ':' so no coverage here. That said,
1150 // Trace.py does not handle not covered lines versus comments etc.
1151 // So, this will be set to 0.
1154 cmCTestLog(this->CTest
, DEBUG
, "Prefix: " << prefix
.c_str()
1157 // Read the line number starting at the 10th character of the gcov
1162 while ( vec
->size() <=
1163 static_cast<size_t>(lineIdx
) )
1167 // Initially all entries are -1 (not used). If we get coverage
1168 // information, increment it to 0 first.
1169 if ( (*vec
)[lineIdx
] < 0 )
1173 (*vec
)[lineIdx
] = 0;
1176 (*vec
)[lineIdx
] += cov
;
1182 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1186 //----------------------------------------------------------------------
1187 std::string
cmCTestCoverageHandler::FindFile(
1188 cmCTestCoverageHandlerContainer
* cont
,
1189 std::string fileName
)
1191 std::string fileNameNoE
1192 = cmSystemTools::GetFilenameWithoutLastExtension(fileName
);
1193 // First check in source and binary directory
1194 std::string fullName
= cont
->SourceDir
+ "/" + fileNameNoE
+ ".py";
1195 if ( cmSystemTools::FileExists(fullName
.c_str()) )
1199 fullName
= cont
->BinaryDir
+ "/" + fileNameNoE
+ ".py";
1200 if ( cmSystemTools::FileExists(fullName
.c_str()) )
1207 // This is a header put on each marked up source file
1210 const char* bullseyeHelp
[] =
1211 {" Coverage produced by bullseye covbr tool: ",
1212 " www.bullseye.com/help/ref_covbr.html",
1213 " * An arrow --> indicates incomplete coverage.",
1214 " * An X indicates a function that was invoked, a switch label that ",
1215 " was exercised, a try-block that finished, or an exception handler ",
1216 " that was invoked.",
1217 " * A T or F indicates a boolean decision that evaluated true or false,",
1219 " * A t or f indicates a boolean condition within a decision if the ",
1220 " condition evaluated true or false, respectively.",
1221 " * A k indicates a constant decision or condition.",
1222 " * The slash / means this probe is excluded from summary results. ",
1226 //----------------------------------------------------------------------
1227 int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
1228 cmCTestCoverageHandlerContainer
* cont
,
1229 std::set
<cmStdString
>& coveredFileNames
,
1230 std::vector
<std::string
>& files
,
1231 std::vector
<std::string
>& filesFullPath
)
1233 if(files
.size() != filesFullPath
.size())
1235 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1236 "Files and full path files not the same size?:\n");
1239 // create the output stream for the CoverageLog-N.xml file
1240 cmGeneratedFileStream covLogFile
;
1241 int logFileCount
= 0;
1242 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
1246 // for each file run covbr on that file to get the coverage
1247 // information for that file
1248 std::string outputFile
;
1249 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1253 if(!this->RunBullseyeCommand(cont
, "covbr", 0, outputFile
))
1255 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "error running covbr for." << "\n");
1258 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1259 "covbr output in " << outputFile
1261 // open the output file
1262 std::ifstream
fin(outputFile
.c_str());
1265 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1266 "Cannot open coverage file: " <<
1267 outputFile
.c_str() << std::endl
);
1270 std::map
<cmStdString
, cmStdString
> fileMap
;
1271 std::vector
<std::string
>::iterator fp
= filesFullPath
.begin();
1272 for(std::vector
<std::string
>::iterator f
= files
.begin();
1273 f
!= files
.end(); ++f
, ++fp
)
1278 int count
=0; // keep count of the number of files
1279 // Now parse each line from the bullseye cov log file
1281 bool valid
= false; // are we in a valid output file
1282 int line
= 0; // line of the current file
1284 while(cmSystemTools::GetLineFromStream(fin
, lineIn
))
1286 bool startFile
= false;
1287 if(lineIn
.size() > 1 && lineIn
[lineIn
.size()-1] == ':')
1289 file
= lineIn
.substr(0, lineIn
.size()-1);
1290 if(coveredFileNames
.find(file
) != coveredFileNames
.end())
1297 // if we are in a valid file close it because a new one started
1300 covLogFile
<< "\t\t</Report>" << std::endl
1301 << "\t</File>" << std::endl
;
1303 // only allow 100 files in each log file
1304 if ( count
!= 0 && count
% 100 == 0 )
1306 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1307 "start a new log file: "
1310 this->EndCoverageLogFile(covLogFile
, logFileCount
);
1312 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
1316 count
++; // move on one
1318 std::map
<cmStdString
, cmStdString
>::iterator
1319 i
= fileMap
.find(file
);
1320 // if the file should be covered write out the header for that file
1321 if(i
!= fileMap
.end())
1323 // we have a new file so count it in the output
1325 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1326 "Produce coverage for file: "
1327 << file
.c_str() << " " << count
1329 // start the file output
1330 covLogFile
<< "\t<File Name=\""
1331 << this->CTest
->MakeXMLSafe(i
->first
.c_str())
1332 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
1333 this->CTest
->GetShortPathToFile(
1334 i
->second
.c_str())) << "\">" << std::endl
1335 << "\t\t<Report>" << std::endl
;
1336 // write the bullseye header
1338 for(int k
=0; bullseyeHelp
[k
] != 0; ++k
)
1340 covLogFile
<< "\t\t<Line Number=\"" << line
<< "\" Count=\"-1\">"
1341 << this->CTest
->MakeXMLSafe(bullseyeHelp
[k
])
1342 << "</Line>" << std::endl
;
1345 valid
= true; // we are in a valid file section
1349 // this is not a file that we want coverage for
1353 // we are not at a start file, and we are in a valid file output the line
1356 covLogFile
<< "\t\t<Line Number=\"" << line
<< "\" Count=\"-1\">"
1357 << this->CTest
->MakeXMLSafe(lineIn
.c_str())
1358 << "</Line>" << std::endl
;
1362 // if we ran out of lines a valid file then close that file
1365 covLogFile
<< "\t\t</Report>" << std::endl
1366 << "\t</File>" << std::endl
;
1368 this->EndCoverageLogFile(covLogFile
, logFileCount
);
1372 //----------------------------------------------------------------------
1373 int cmCTestCoverageHandler::RunBullseyeCommand(
1374 cmCTestCoverageHandlerContainer
* cont
,
1377 std::string
& outputFile
)
1379 std::string program
= cmSystemTools::FindProgram(cmd
);
1380 if(program
.size() == 0)
1382 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot find :" << cmd
<< "\n");
1387 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1388 "Run : " << program
.c_str() << " " << arg
<< "\n");
1392 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1393 "Run : " << program
.c_str() << "\n");
1395 // create a process object and start it
1396 cmCTestRunProcess runCoverageSrc
;
1397 runCoverageSrc
.SetCommand(program
.c_str());
1398 runCoverageSrc
.AddArgument(arg
);
1399 std::string stdoutFile
= cont
->BinaryDir
+ "/Testing/Temporary/";
1400 stdoutFile
+= this->GetCTestInstance()->GetCurrentTag();
1403 std::string stderrFile
= stdoutFile
;
1404 stdoutFile
+= ".stdout";
1405 stderrFile
+= ".stderr";
1406 runCoverageSrc
.SetStdoutFile(stdoutFile
.c_str());
1407 runCoverageSrc
.SetStderrFile(stderrFile
.c_str());
1408 if(!runCoverageSrc
.StartProcess())
1410 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Could not run : "
1411 << program
.c_str() << " " << arg
<< "\n"
1412 << "kwsys process state : "
1413 << runCoverageSrc
.GetProcessState());
1416 // since we set the output file names wait for it to end
1417 runCoverageSrc
.WaitForExit();
1418 outputFile
= stdoutFile
;
1422 //----------------------------------------------------------------------
1423 int cmCTestCoverageHandler::RunBullseyeSourceSummary(
1424 cmCTestCoverageHandlerContainer
* cont
)
1426 // Run the covsrc command and create a temp outputfile
1427 std::string outputFile
;
1428 if(!this->RunBullseyeCommand(cont
, "covsrc", "-c", outputFile
))
1430 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "error running covsrc:\n");
1434 std::ostream
& tmpLog
= *cont
->OFS
;
1435 // copen the Coverage.xml file in the Testing directory
1436 cmGeneratedFileStream covSumFile
;
1437 if (!this->StartResultingXML("Coverage", covSumFile
))
1439 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1440 "Cannot open coverage summary file." << std::endl
);
1443 this->CTest
->StartXML(covSumFile
);
1444 double elapsed_time_start
= cmSystemTools::GetTime();
1445 std::string coverage_start_time
= this->CTest
->CurrentTime();
1446 covSumFile
<< "<Coverage>" << std::endl
1447 << "\t<StartDateTime>"
1448 << coverage_start_time
<< "</StartDateTime>"
1451 << static_cast<unsigned int>(cmSystemTools::GetTime())
1454 std::string stdline
;
1455 std::string errline
;
1458 // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"
1459 // after that data follows in that format
1460 std::string sourceFile
;
1461 int functionsCalled
= 0;
1462 int totalFunctions
= 0;
1463 int percentFunction
= 0;
1464 int branchCovered
= 0;
1465 int totalBranches
= 0;
1466 int percentBranch
= 0;
1467 double total_tested
= 0;
1468 double total_untested
= 0;
1469 double total_functions
= 0;
1470 double percent_coverage
=0;
1471 double number_files
= 0;
1472 std::vector
<std::string
> coveredFiles
;
1473 std::vector
<std::string
> coveredFilesFullPath
;
1474 // Read and parse the summary output file
1475 std::ifstream
fin(outputFile
.c_str());
1478 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1479 "Cannot open coverage summary file: " <<
1480 outputFile
.c_str() << std::endl
);
1483 std::set
<cmStdString
> coveredFileNames
;
1484 while(cmSystemTools::GetLineFromStream(fin
, stdline
))
1486 // if we have a line of output from stdout
1489 // parse the comma separated output
1490 this->ParseBullsEyeCovsrcLine(stdline
,
1498 // The first line is the header
1499 if(sourceFile
== "Source" || sourceFile
== "Total")
1503 std::string file
= sourceFile
;
1504 coveredFileNames
.insert(file
);
1505 if(!cmSystemTools::FileIsFullPath(sourceFile
.c_str()))
1507 // file will be relative to the binary dir
1508 file
= cont
->BinaryDir
;
1512 file
= cmSystemTools::CollapseFullPath(file
.c_str());
1513 bool shouldIDoCoverage
1514 = this->ShouldIDoCoverage(file
.c_str(),
1515 cont
->SourceDir
.c_str(),
1516 cont
->BinaryDir
.c_str());
1517 if ( !shouldIDoCoverage
)
1519 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1520 ".NoDartCoverage found, so skip coverage check for: "
1526 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1527 "Doing coverage for: "
1531 coveredFiles
.push_back(sourceFile
);
1532 coveredFilesFullPath
.push_back(file
);
1535 total_functions
+= totalFunctions
;
1536 total_tested
+= functionsCalled
;
1537 total_untested
+= (totalFunctions
- functionsCalled
);
1539 std::string fileName
= cmSystemTools::GetFilenameName(file
.c_str());
1541 float cper
= percentBranch
+ percentFunction
;
1542 if(totalBranches
> 0)
1546 percent_coverage
+= cper
;
1547 float cmet
= percentFunction
+ percentBranch
;
1548 if(totalBranches
> 0)
1553 tmpLog
<< stdline
.c_str() << "\n";
1554 tmpLog
<< fileName
<< "\n";
1555 tmpLog
<< "functionsCalled: " << functionsCalled
/100 << "\n";
1556 tmpLog
<< "totalFunctions: " << totalFunctions
/100 << "\n";
1557 tmpLog
<< "percentFunction: " << percentFunction
<< "\n";
1558 tmpLog
<< "branchCovered: " << branchCovered
<< "\n";
1559 tmpLog
<< "totalBranches: " << totalBranches
<< "\n";
1560 tmpLog
<< "percentBranch: " << percentBranch
<< "\n";
1561 tmpLog
<< "percentCoverage: " << percent_coverage
<< "\n";
1562 tmpLog
<< "coverage metric: " << cmet
<< "\n";
1563 covSumFile
<< "\t<File Name=\"" << this->CTest
->MakeXMLSafe(sourceFile
)
1564 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
1565 this->CTest
->GetShortPathToFile(file
.c_str()))
1566 << "\" Covered=\"" << (cmet
>0?"true":"false") << "\">\n"
1567 << "\t\t<BranchesTested>"
1569 << "</BranchesTested>\n"
1570 << "\t\t<BranchesUnTested>"
1571 << totalBranches
- branchCovered
1572 << "</BranchesUnTested>\n"
1573 << "\t\t<FunctionsTested>"
1575 << "</FunctionsTested>\n"
1576 << "\t\t<FunctionsUnTested>"
1577 << totalFunctions
- functionsCalled
1578 << "</FunctionsUnTested>\n"
1579 // Hack for conversion of function to loc assume a function
1580 // has 100 lines of code
1581 << "\t\t<LOCTested>" << functionsCalled
*100
1583 << "\t\t<LOCUnTested>"
1584 << (totalFunctions
- functionsCalled
)*100
1585 << "</LOCUnTested>\n"
1586 << "\t\t<PercentCoverage>";
1587 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1588 covSumFile
.precision(2);
1589 covSumFile
<< (cper
) << "</PercentCoverage>\n"
1590 << "\t\t<CoverageMetric>";
1591 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1592 covSumFile
.precision(2);
1593 covSumFile
<< (cmet
) << "</CoverageMetric>\n"
1594 << "\t</File>" << std::endl
;
1597 std::string end_time
= this->CTest
->CurrentTime();
1598 covSumFile
<< "\t<LOCTested>" << total_tested
<< "</LOCTested>\n"
1599 << "\t<LOCUntested>" << total_untested
<< "</LOCUntested>\n"
1600 << "\t<LOC>" << total_functions
<< "</LOC>\n"
1601 << "\t<PercentCoverage>";
1602 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1603 covSumFile
.precision(2);
1605 << SAFEDIV(percent_coverage
,number_files
)<< "</PercentCoverage>\n"
1606 << "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n"
1607 << "\t<EndTime>" << static_cast<unsigned int>(cmSystemTools::GetTime())
1610 << "<ElapsedMinutes>" <<
1611 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
1612 << "</ElapsedMinutes>"
1613 << "</Coverage>" << std::endl
;
1614 this->CTest
->EndXML(covSumFile
);
1615 // Now create the coverage information for each file
1616 return this->RunBullseyeCoverageBranch(cont
,
1619 coveredFilesFullPath
);
1622 //----------------------------------------------------------------------
1623 int cmCTestCoverageHandler::HandleBullseyeCoverage(
1624 cmCTestCoverageHandlerContainer
* cont
)
1626 const char* covfile
= cmSystemTools::GetEnv("COVFILE");
1629 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1630 " COVFILE environment variable not found, not running "
1634 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1635 " run covsrc with COVFILE=["
1637 << "]" << std::endl
);
1638 if(!this->RunBullseyeSourceSummary(cont
))
1640 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1641 "Error running bullseye summary.\n");
1644 cmCTestLog(this->CTest
, DEBUG
, "HandleBullseyeCoverage return 1 "
1649 bool cmCTestCoverageHandler::GetNextInt(std::string
const& inputLine
,
1650 std::string::size_type
& pos
,
1653 std::string::size_type start
= pos
;
1654 pos
= inputLine
.find(',', start
);
1655 value
= atoi(inputLine
.substr(start
, pos
).c_str());
1656 if(pos
== inputLine
.npos
)
1664 bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
1665 std::string
const& inputLine
,
1666 std::string
& sourceFile
,
1667 int& functionsCalled
,
1668 int& totalFunctions
,
1669 int& percentFunction
,
1674 // find the first comma
1675 std::string::size_type pos
= inputLine
.find(',');
1676 if(pos
== inputLine
.npos
)
1678 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Error parsing string : "
1679 << inputLine
.c_str() << "\n");
1682 // the source file has "" around it so extract out the file name
1683 sourceFile
= inputLine
.substr(1,pos
-2);
1685 if(!this->GetNextInt(inputLine
, pos
, functionsCalled
))
1689 if(!this->GetNextInt(inputLine
, pos
, totalFunctions
))
1693 if(!this->GetNextInt(inputLine
, pos
, percentFunction
))
1697 if(!this->GetNextInt(inputLine
, pos
, branchCovered
))
1701 if(!this->GetNextInt(inputLine
, pos
, totalBranches
))
1705 if(!this->GetNextInt(inputLine
, pos
, percentBranch
))
1709 // should be at the end now
1710 if(pos
!= inputLine
.npos
)
1712 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Error parsing input : "
1713 << inputLine
.c_str() << " last pos not npos = " << pos
<<