1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmCTestCoverageHandler.cxx,v $
6 Date: $Date: 2007-11-16 16:32:38 $
7 Version: $Revision: 1.50 $
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>"
179 //----------------------------------------------------------------------
180 void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream
& ostr
,
183 std::string local_end_time
= this->CTest
->CurrentTime();
184 ostr
<< "\t<EndDateTime>" << local_end_time
<< "</EndDateTime>" << std::endl
185 << "</CoverageLog>" << std::endl
;
186 this->CTest
->EndXML(ostr
);
187 char covLogFilename
[1024];
188 sprintf(covLogFilename
, "CoverageLog-%d.xml", logFileCount
);
189 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Close file: "
190 << covLogFilename
<< std::endl
);
194 //----------------------------------------------------------------------
195 bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file
,
199 std::vector
<cmsys::RegularExpression
>::iterator sit
;
200 for ( sit
= this->CustomCoverageExcludeRegex
.begin();
201 sit
!= this->CustomCoverageExcludeRegex
.end(); ++ sit
)
203 if ( sit
->find(file
) )
205 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " File " << file
206 << " is excluded in CTestCustom.ctest" << std::endl
;);
211 std::string fSrcDir
= cmSystemTools::CollapseFullPath(srcDir
);
212 std::string fBinDir
= cmSystemTools::CollapseFullPath(binDir
);
213 std::string fFile
= cmSystemTools::CollapseFullPath(file
);
214 bool sourceSubDir
= cmSystemTools::IsSubDirectory(fFile
.c_str(),
216 bool buildSubDir
= cmSystemTools::IsSubDirectory(fFile
.c_str(),
218 // Always check parent directory of the file.
219 std::string fileDir
= cmSystemTools::GetFilenamePath(fFile
.c_str());
220 std::string checkDir
;
222 // We also need to check the binary/source directory pair.
223 if ( sourceSubDir
&& buildSubDir
)
225 if ( fSrcDir
.size() > fBinDir
.size() )
234 else if ( sourceSubDir
)
238 else if ( buildSubDir
)
243 = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
244 fFile
.c_str(), checkDir
.c_str());
247 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Found: " << ndc
.c_str()
248 << " so skip coverage of " << file
<< std::endl
);
252 // By now checkDir should be set to parent directory of the file.
253 // Get the relative path to the file an apply it to the opposite directory.
254 // If it is the same as fileDir, then ignore, otherwise check.
258 relPath
= cmSystemTools::RelativePath(checkDir
.c_str(),
265 if ( checkDir
== fSrcDir
)
273 fFile
= checkDir
+ "/" + relPath
;
274 fFile
= cmSystemTools::GetFilenamePath(fFile
.c_str());
276 if ( fileDir
== fFile
)
278 // This is in-source build, so we trust the previous check.
282 ndc
= cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage",
283 fFile
.c_str(), checkDir
.c_str());
286 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "Found: " << ndc
.c_str()
287 << " so skip coverage of: " << file
<< std::endl
);
290 // Ok, nothing in source tree, nothing in binary tree
294 //----------------------------------------------------------------------
295 //clearly it would be nice if this were broken up into a few smaller
296 //functions and commented...
297 int cmCTestCoverageHandler::ProcessHandler()
300 // do we have time for this
301 if (this->CTest
->GetRemainingTimeAllowed() < 120)
306 std::string coverage_start_time
= this->CTest
->CurrentTime();
308 std::string sourceDir
309 = this->CTest
->GetCTestConfiguration("SourceDirectory");
310 std::string binaryDir
311 = this->CTest
->GetCTestConfiguration("BuildDirectory");
313 cmGeneratedFileStream ofs
;
314 double elapsed_time_start
= cmSystemTools::GetTime();
315 if ( !this->StartLogFile("Coverage", ofs
) )
317 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
318 "Cannot create LastCoverage.log file" << std::endl
);
321 ofs
<< "Performing coverage: " << elapsed_time_start
<< std::endl
;
323 cmSystemTools::ConvertToUnixSlashes(sourceDir
);
324 cmSystemTools::ConvertToUnixSlashes(binaryDir
);
326 std::string asfGlob
= sourceDir
+ "/*";
327 std::string abfGlob
= binaryDir
+ "/*";
329 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "Performing coverage" << std::endl
);
331 cmCTestCoverageHandlerContainer cont
;
333 cont
.SourceDir
= sourceDir
;
334 cont
.BinaryDir
= binaryDir
;
337 // setup the regex exclude stuff
338 this->CustomCoverageExcludeRegex
.empty();
339 std::vector
<cmStdString
>::iterator rexIt
;
340 for ( rexIt
= this->CustomCoverageExclude
.begin();
341 rexIt
!= this->CustomCoverageExclude
.end();
344 this->CustomCoverageExcludeRegex
.push_back(
345 cmsys::RegularExpression(rexIt
->c_str()));
349 if(this->HandleBullseyeCoverage(&cont
))
354 file_count
+= this->HandleGCovCoverage(&cont
);
355 if ( file_count
< 0 )
359 file_count
+= this->HandleTracePyCoverage(&cont
);
360 if ( file_count
< 0 )
367 if ( file_count
== 0 )
369 cmCTestLog(this->CTest
, WARNING
,
370 " Cannot find any coverage files. Ignoring Coverage request."
374 cmGeneratedFileStream covSumFile
;
375 cmGeneratedFileStream covLogFile
;
377 if (!this->StartResultingXML("Coverage", covSumFile
))
379 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
380 "Cannot open coverage summary file." << std::endl
);
384 this->CTest
->StartXML(covSumFile
);
385 // Produce output xml files
387 covSumFile
<< "<Coverage>" << std::endl
388 << "\t<StartDateTime>" << coverage_start_time
<< "</StartDateTime>"
390 int logFileCount
= 0;
391 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
395 cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator
;
397 long total_tested
= 0;
398 long total_untested
= 0;
399 //std::string fullSourceDir = sourceDir + "/";
400 //std::string fullBinaryDir = binaryDir + "/";
401 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, std::endl
);
402 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
403 " Acumulating results (each . represents one file):" << std::endl
);
404 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
406 std::vector
<std::string
> errorsWhileAccumulating
;
409 for ( fileIterator
= cont
.TotalCoverage
.begin();
410 fileIterator
!= cont
.TotalCoverage
.end();
413 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "." << std::flush
);
415 if ( file_count
% 50 == 0 )
417 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " processed: " << file_count
419 << cont
.TotalCoverage
.size() << std::endl
);
420 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
422 if ( cnt
% 100 == 0 )
424 this->EndCoverageLogFile(covLogFile
, logFileCount
);
426 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
431 const std::string fullFileName
= fileIterator
->first
;
432 const std::string fileName
433 = cmSystemTools::GetFilenameName(fullFileName
.c_str());
434 std::string fullFilePath
435 = cmSystemTools::GetFilenamePath(fullFileName
.c_str());
436 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
437 "Process file: " << fullFileName
<< std::endl
);
439 cmSystemTools::ConvertToUnixSlashes(fullFilePath
);
441 if ( !cmSystemTools::FileExists(fullFileName
.c_str()) )
443 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot find file: "
444 << fullFileName
.c_str() << std::endl
);
448 bool shouldIDoCoverage
449 = this->ShouldIDoCoverage(fullFileName
.c_str(),
450 sourceDir
.c_str(), binaryDir
.c_str());
451 if ( !shouldIDoCoverage
)
453 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
454 ".NoDartCoverage found, so skip coverage check for: "
455 << fullFileName
.c_str()
460 const cmCTestCoverageHandlerContainer::SingleFileCoverageVector
& fcov
461 = fileIterator
->second
;
462 covLogFile
<< "\t<File Name=\""
463 << this->CTest
->MakeXMLSafe(fileName
.c_str())
464 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
465 this->CTest
->GetShortPathToFile(
466 fileIterator
->first
.c_str())) << "\">" << std::endl
467 << "\t\t<Report>" << std::endl
;
469 std::ifstream
ifs(fullFileName
.c_str());
472 cmOStringStream ostr
;
473 ostr
<< "Cannot open source file: " << fullFileName
.c_str();
474 errorsWhileAccumulating
.push_back(ostr
.str());
482 cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc
;
484 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
485 "Actually perfoming coverage for: " << fullFileName
<< std::endl
);
486 for ( cc
= 0; cc
< fcov
.size(); cc
++ )
488 if ( !cmSystemTools::GetLineFromStream(ifs
, line
) &&
489 cc
!= fcov
.size() -1 )
491 cmOStringStream ostr
;
492 ostr
<< "Problem reading source file: " << fullFileName
.c_str()
494 errorsWhileAccumulating
.push_back(ostr
.str());
498 covLogFile
<< "\t\t<Line Number=\"" << cc
<< "\" Count=\"" << fcov
[cc
]
500 << this->CTest
->MakeXMLSafe(line
.c_str()) << "</Line>" << std::endl
;
505 else if ( fcov
[cc
] > 0 )
510 if ( cmSystemTools::GetLineFromStream(ifs
, line
) )
512 cmOStringStream ostr
;
513 ostr
<< "Looks like there are more lines in the file: " << line
;
514 errorsWhileAccumulating
.push_back(ostr
.str());
518 if ( tested
+ untested
> 0 )
520 cper
= (100 * SAFEDIV(static_cast<float>(tested
),
521 static_cast<float>(tested
+ untested
)));
522 cmet
= ( SAFEDIV(static_cast<float>(tested
+ 10),
523 static_cast<float>(tested
+ untested
+ 10)));
525 total_tested
+= tested
;
526 total_untested
+= untested
;
527 covLogFile
<< "\t\t</Report>" << std::endl
528 << "\t</File>" << std::endl
;
529 covSumFile
<< "\t<File Name=\"" << this->CTest
->MakeXMLSafe(fileName
)
530 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
531 this->CTest
->GetShortPathToFile(fullFileName
.c_str()))
532 << "\" Covered=\"" << (tested
==0?"true":"false") << "\">\n"
533 << "\t\t<LOCTested>" << tested
<< "</LOCTested>\n"
534 << "\t\t<LOCUnTested>" << untested
<< "</LOCUnTested>\n"
535 << "\t\t<PercentCoverage>";
536 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
537 covSumFile
.precision(2);
538 covSumFile
<< (cper
) << "</PercentCoverage>\n"
539 << "\t\t<CoverageMetric>";
540 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
541 covSumFile
.precision(2);
542 covSumFile
<< (cmet
) << "</CoverageMetric>\n"
543 << "\t</File>" << std::endl
;
546 this->EndCoverageLogFile(covLogFile
, logFileCount
);
548 if ( errorsWhileAccumulating
.size() > 0 )
550 cmCTestLog(this->CTest
, ERROR_MESSAGE
, std::endl
);
551 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
552 "Error(s) while acumulating results:" << std::endl
);
553 std::vector
<std::string
>::iterator erIt
;
554 for ( erIt
= errorsWhileAccumulating
.begin();
555 erIt
!= errorsWhileAccumulating
.end();
558 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
559 " " << erIt
->c_str() << std::endl
);
563 int total_lines
= total_tested
+ total_untested
;
564 float percent_coverage
= 100 * SAFEDIV(static_cast<float>(total_tested
),
565 static_cast<float>(total_lines
));
566 if ( total_lines
== 0 )
568 percent_coverage
= 0;
571 std::string end_time
= this->CTest
->CurrentTime();
573 covSumFile
<< "\t<LOCTested>" << total_tested
<< "</LOCTested>\n"
574 << "\t<LOCUntested>" << total_untested
<< "</LOCUntested>\n"
575 << "\t<LOC>" << total_lines
<< "</LOC>\n"
576 << "\t<PercentCoverage>";
577 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
578 covSumFile
.precision(2);
579 covSumFile
<< (percent_coverage
)<< "</PercentCoverage>\n"
580 << "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n";
581 covSumFile
<< "<ElapsedMinutes>" <<
582 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
583 << "</ElapsedMinutes>"
584 << "</Coverage>" << std::endl
;
585 this->CTest
->EndXML(covSumFile
);
587 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "" << std::endl
589 << total_tested
<< std::endl
590 << "\tNot covered LOC: " << total_untested
<< std::endl
591 << "\tTotal LOC: " << total_lines
<< std::endl
592 << "\tPercentage Coverage: "
593 << std::setiosflags(std::ios::fixed
)
594 << std::setprecision(2)
595 << (percent_coverage
) << "%" << std::endl
);
597 ofs
<< "\tCovered LOC: " << total_tested
<< std::endl
598 << "\tNot covered LOC: " << total_untested
<< std::endl
599 << "\tTotal LOC: " << total_lines
<< std::endl
600 << "\tPercentage Coverage: "
601 << std::setiosflags(std::ios::fixed
)
602 << std::setprecision(2)
603 << (percent_coverage
) << "%" << std::endl
;
613 //----------------------------------------------------------------------
614 void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile
*mf
)
616 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
617 " Add coverage exclude regular expressions." << std::endl
);
618 this->CTest
->PopulateCustomVector(mf
, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
619 this->CustomCoverageExclude
);
620 std::vector
<cmStdString
>::iterator it
;
621 for ( it
= this->CustomCoverageExclude
.begin();
622 it
!= this->CustomCoverageExclude
.end();
625 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " Add coverage exclude: "
626 << it
->c_str() << std::endl
);
630 //----------------------------------------------------------------------
631 int cmCTestCoverageHandler::HandleGCovCoverage(
632 cmCTestCoverageHandlerContainer
* cont
)
634 std::string gcovCommand
635 = this->CTest
->GetCTestConfiguration("CoverageCommand");
638 std::string st1gcovOutputRex1
639 = "[0-9]+\\.[0-9]+% of [0-9]+ (source |)lines executed in file (.*)$";
640 std::string st1gcovOutputRex2
= "^Creating (.*\\.gcov)\\.";
641 cmsys::RegularExpression
st1re1(st1gcovOutputRex1
.c_str());
642 cmsys::RegularExpression
st1re2(st1gcovOutputRex2
.c_str());
646 std::string st2gcovOutputRex1
= "^File *[`'](.*)'$";
647 std::string st2gcovOutputRex2
648 = "Lines executed: *[0-9]+\\.[0-9]+% of [0-9]+$";
649 std::string st2gcovOutputRex3
= "^(.*):creating [`'](.*\\.gcov)'";
650 std::string st2gcovOutputRex4
= "^(.*):unexpected EOF *$";
651 std::string st2gcovOutputRex5
= "^(.*):cannot open source file*$";
652 std::string st2gcovOutputRex6
653 = "^(.*):source file is newer than graph file `(.*)'$";
654 cmsys::RegularExpression
st2re1(st2gcovOutputRex1
.c_str());
655 cmsys::RegularExpression
st2re2(st2gcovOutputRex2
.c_str());
656 cmsys::RegularExpression
st2re3(st2gcovOutputRex3
.c_str());
657 cmsys::RegularExpression
st2re4(st2gcovOutputRex4
.c_str());
658 cmsys::RegularExpression
st2re5(st2gcovOutputRex5
.c_str());
659 cmsys::RegularExpression
st2re6(st2gcovOutputRex6
.c_str());
664 std::string daGlob
= cont
->BinaryDir
+ "/*.da";
665 gl
.FindFiles(daGlob
);
666 std::vector
<std::string
> files
= gl
.GetFiles();
667 daGlob
= cont
->BinaryDir
+ "/*.gcda";
668 gl
.FindFiles(daGlob
);
669 std::vector
<std::string
>& moreFiles
= gl
.GetFiles();
670 files
.insert(files
.end(), moreFiles
.begin(), moreFiles
.end());
671 std::vector
<std::string
>::iterator it
;
673 if ( files
.size() == 0 )
675 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
676 " Cannot find any GCov coverage files."
678 // No coverage files is a valid thing, so the exit code is 0
682 std::string testingDir
= this->CTest
->GetBinaryDir() + "/Testing";
683 std::string tempDir
= testingDir
+ "/CoverageInfo";
684 std::string currentDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
685 cmSystemTools::MakeDirectory(tempDir
.c_str());
686 cmSystemTools::ChangeDirectory(tempDir
.c_str());
690 std::set
<std::string
> missingFiles
;
692 std::string actualSourceFile
= "";
693 cmCTestLog(this->CTest
, HANDLER_OUTPUT
,
694 " Processing coverage (each . represents one file):" << std::endl
);
695 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
697 for ( it
= files
.begin(); it
!= files
.end(); ++ it
)
699 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, "." << std::flush
);
700 std::string fileDir
= cmSystemTools::GetFilenamePath(it
->c_str());
701 std::string command
= "\"" + gcovCommand
+ "\" -l -o \"" + fileDir
702 + "\" \"" + *it
+ "\"";
703 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, command
.c_str()
705 std::string output
= "";
706 std::string errors
= "";
708 *cont
->OFS
<< "* Run coverage for: " << fileDir
.c_str() << std::endl
;
709 *cont
->OFS
<< " Command: " << command
.c_str() << std::endl
;
710 int res
= this->CTest
->RunCommand(command
.c_str(), &output
, &errors
,
711 &retVal
, tempDir
.c_str(), 0 /*this->TimeOut*/);
713 *cont
->OFS
<< " Output: " << output
.c_str() << std::endl
;
714 *cont
->OFS
<< " Errors: " << errors
.c_str() << std::endl
;
717 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
718 "Problem running coverage on file: " << it
->c_str() << std::endl
);
719 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
720 "Command produced error: " << errors
<< std::endl
);
726 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Coverage command returned: "
727 << retVal
<< " while processing: " << it
->c_str() << std::endl
);
728 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
729 "Command produced error: " << cont
->Error
<< std::endl
);
731 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
732 "--------------------------------------------------------------"
734 << output
<< std::endl
735 << "--------------------------------------------------------------"
737 std::vector
<cmStdString
> lines
;
738 std::vector
<cmStdString
>::iterator line
;
741 // Globals for storing current source file and current gcov file;
742 cmSystemTools::Split(output
.c_str(), lines
);
743 for ( line
= lines
.begin(); line
!= lines
.end(); ++line
)
745 std::string sourceFile
;
746 std::string gcovFile
;
747 cmCTestLog(this->CTest
, DEBUG
, "Line: [" << line
->c_str() << "]"
749 if ( line
->size() == 0 )
751 // Ignore empty line; probably style 2
753 else if ( st1re1
.find(line
->c_str()) )
755 if ( gcovStyle
!= 0 )
757 if ( gcovStyle
!= 1 )
759 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
767 actualSourceFile
= "";
768 sourceFile
= st1re1
.match(2);
770 else if ( st1re2
.find(line
->c_str() ) )
772 if ( gcovStyle
!= 0 )
774 if ( gcovStyle
!= 1 )
776 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
784 gcovFile
= st1re2
.match(1);
786 else if ( st2re1
.find(line
->c_str() ) )
788 if ( gcovStyle
!= 0 )
790 if ( gcovStyle
!= 2 )
792 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
800 actualSourceFile
= "";
801 sourceFile
= st2re1
.match(1);
803 else if ( st2re2
.find(line
->c_str() ) )
805 if ( gcovStyle
!= 0 )
807 if ( gcovStyle
!= 2 )
809 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
817 else if ( st2re3
.find(line
->c_str() ) )
819 if ( gcovStyle
!= 0 )
821 if ( gcovStyle
!= 2 )
823 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
831 gcovFile
= st2re3
.match(2);
833 else if ( st2re4
.find(line
->c_str() ) )
835 if ( gcovStyle
!= 0 )
837 if ( gcovStyle
!= 2 )
839 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
847 cmCTestLog(this->CTest
, WARNING
, "Warning: " << st2re4
.match(1)
848 << " had unexpected EOF" << std::endl
);
850 else if ( st2re5
.find(line
->c_str() ) )
852 if ( gcovStyle
!= 0 )
854 if ( gcovStyle
!= 2 )
856 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
864 cmCTestLog(this->CTest
, WARNING
, "Warning: Cannot open file: "
865 << st2re5
.match(1) << std::endl
);
867 else if ( st2re6
.find(line
->c_str() ) )
869 if ( gcovStyle
!= 0 )
871 if ( gcovStyle
!= 2 )
873 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Unknown gcov output style"
881 cmCTestLog(this->CTest
, WARNING
, "Warning: File: " << st2re6
.match(1)
882 << " is newer than " << st2re6
.match(2) << std::endl
);
886 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
887 "Unknown line: [" << line
->c_str() << "]" << std::endl
);
891 if ( !gcovFile
.empty() && actualSourceFile
.size() )
893 cmCTestCoverageHandlerContainer::SingleFileCoverageVector
* vec
894 = &cont
->TotalCoverage
[actualSourceFile
];
895 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " in file: "
896 << gcovFile
<< std::endl
);
897 std::ifstream
ifile(gcovFile
.c_str());
900 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open file: "
901 << gcovFile
<< std::endl
);
907 while ( cmSystemTools::GetLineFromStream(ifile
, nl
) )
911 //TODO: Handle gcov 3.0 non-coverage lines
920 if ( nl
.size() < 12 )
925 // Read the coverage count from the beginning of the gcov output
927 std::string prefix
= nl
.substr(0, 12);
928 int cov
= atoi(prefix
.c_str());
929 // Read the line number starting at the 10th character of the gcov
931 std::string lineNumber
= nl
.substr(10, 5);
932 int lineIdx
= atoi(lineNumber
.c_str())-1;
935 while ( vec
->size() <=
936 static_cast<size_t>(lineIdx
) )
940 // Initially all entries are -1 (not used). If we get coverage
941 // information, increment it to 0 first.
942 if ( (*vec
)[lineIdx
] < 0 )
944 if ( cov
> 0 || prefix
.find("#") != prefix
.npos
)
949 (*vec
)[lineIdx
] += cov
;
953 actualSourceFile
= "";
955 if ( !sourceFile
.empty() && actualSourceFile
.empty() )
958 // Is it in the source dir?
959 if ( sourceFile
.size() > cont
->SourceDir
.size() &&
960 sourceFile
.substr(0, cont
->SourceDir
.size()) == cont
->SourceDir
&&
961 sourceFile
[cont
->SourceDir
.size()] == '/' )
963 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " produced s: "
964 << sourceFile
.c_str() << std::endl
);
965 *cont
->OFS
<< " produced in source dir: " << sourceFile
.c_str()
968 = cmSystemTools::CollapseFullPath(sourceFile
.c_str());
971 if ( sourceFile
.size() > cont
->BinaryDir
.size() &&
972 sourceFile
.substr(0, cont
->BinaryDir
.size()) == cont
->BinaryDir
&&
973 sourceFile
[cont
->BinaryDir
.size()] == '/' )
975 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, " produced b: "
976 << sourceFile
.c_str() << std::endl
);
977 *cont
->OFS
<< " produced in binary dir: " << sourceFile
.c_str()
980 = cmSystemTools::CollapseFullPath(sourceFile
.c_str());
982 if ( actualSourceFile
.empty() )
984 if ( missingFiles
.find(actualSourceFile
) == missingFiles
.end() )
986 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
987 "Something went wrong" << std::endl
);
988 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "File: ["
989 << sourceFile
.c_str() << "]" << std::endl
);
990 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "s: ["
991 << sourceFile
.substr(0, cont
->SourceDir
.size()) << "]"
993 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
, "b: ["
994 << sourceFile
.substr(0, cont
->BinaryDir
.size()) << "]"
996 *cont
->OFS
<< " Something went wrong. Cannot find: "
997 << sourceFile
.c_str()
998 << " in source dir: " << cont
->SourceDir
.c_str()
999 << " or binary dir: " << cont
->BinaryDir
.c_str() << std::endl
;
1000 missingFiles
.insert(actualSourceFile
);
1006 if ( file_count
% 50 == 0 )
1008 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " processed: " << file_count
1009 << " out of " << files
.size() << std::endl
);
1010 cmCTestLog(this->CTest
, HANDLER_OUTPUT
, " ");
1013 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1017 //----------------------------------------------------------------------
1018 int cmCTestCoverageHandler::HandleTracePyCoverage(
1019 cmCTestCoverageHandlerContainer
* cont
)
1023 std::string daGlob
= cont
->BinaryDir
+ "/*.cover";
1024 gl
.FindFiles(daGlob
);
1025 std::vector
<std::string
> files
= gl
.GetFiles();
1027 if ( files
.size() == 0 )
1029 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1030 " Cannot find any Python Trace.py coverage files."
1032 // No coverage files is a valid thing, so the exit code is 0
1036 std::string testingDir
= this->CTest
->GetBinaryDir() + "/Testing";
1037 std::string tempDir
= testingDir
+ "/CoverageInfo";
1038 std::string currentDirectory
= cmSystemTools::GetCurrentWorkingDirectory();
1039 cmSystemTools::MakeDirectory(tempDir
.c_str());
1040 cmSystemTools::ChangeDirectory(tempDir
.c_str());
1042 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1044 std::vector
<std::string
>::iterator fileIt
;
1046 for ( fileIt
= files
.begin(); fileIt
!= files
.end(); ++ fileIt
)
1048 std::string fileName
= this->FindFile(cont
, *fileIt
);
1049 if ( fileName
.empty() )
1051 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1052 "Cannot find source Python file corresponding to: "
1053 << fileIt
->c_str() << std::endl
);
1057 std::string actualSourceFile
1058 = cmSystemTools::CollapseFullPath(fileName
.c_str());
1059 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1060 " Check coverage for file: " << actualSourceFile
.c_str()
1062 cmCTestCoverageHandlerContainer::SingleFileCoverageVector
* vec
1063 = &cont
->TotalCoverage
[actualSourceFile
];
1064 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1065 " in file: " << fileIt
->c_str() << std::endl
);
1066 std::ifstream
ifile(fileIt
->c_str());
1069 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot open file: "
1070 << fileIt
->c_str() << std::endl
);
1076 while ( cmSystemTools::GetLineFromStream(ifile
, nl
) )
1086 // Skip unused lines
1087 if ( nl
.size() < 12 )
1092 // Read the coverage count from the beginning of the Trace.py output
1094 std::string prefix
= nl
.substr(0, 6);
1095 if ( prefix
[5] != ' ' && prefix
[5] != ':' )
1097 // This is a hack. We should really do something more elaborate
1098 prefix
= nl
.substr(0, 7);
1099 if ( prefix
[6] != ' ' && prefix
[6] != ':' )
1101 prefix
= nl
.substr(0, 8);
1102 if ( prefix
[7] != ' ' && prefix
[7] != ':' )
1104 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1105 "Currently the limit is maximum coverage of 999999"
1110 int cov
= atoi(prefix
.c_str());
1111 if ( prefix
[prefix
.size()-1] != ':' )
1113 // This line does not have ':' so no coverage here. That said,
1114 // Trace.py does not handle not covered lines versus comments etc.
1115 // So, this will be set to 0.
1118 cmCTestLog(this->CTest
, DEBUG
, "Prefix: " << prefix
.c_str()
1121 // Read the line number starting at the 10th character of the gcov
1126 while ( vec
->size() <=
1127 static_cast<size_t>(lineIdx
) )
1131 // Initially all entries are -1 (not used). If we get coverage
1132 // information, increment it to 0 first.
1133 if ( (*vec
)[lineIdx
] < 0 )
1137 (*vec
)[lineIdx
] = 0;
1140 (*vec
)[lineIdx
] += cov
;
1146 cmSystemTools::ChangeDirectory(currentDirectory
.c_str());
1150 //----------------------------------------------------------------------
1151 std::string
cmCTestCoverageHandler::FindFile(
1152 cmCTestCoverageHandlerContainer
* cont
,
1153 std::string fileName
)
1155 std::string fileNameNoE
1156 = cmSystemTools::GetFilenameWithoutLastExtension(fileName
);
1157 // First check in source and binary directory
1158 std::string fullName
= cont
->SourceDir
+ "/" + fileNameNoE
+ ".py";
1159 if ( cmSystemTools::FileExists(fullName
.c_str()) )
1163 fullName
= cont
->BinaryDir
+ "/" + fileNameNoE
+ ".py";
1164 if ( cmSystemTools::FileExists(fullName
.c_str()) )
1171 // This is a header put on each marked up source file
1174 const char* bullseyeHelp
[] =
1175 {" Coverage produced by bullseye covbr tool: ",
1176 " www.bullseye.com/help/ref_covbr.html",
1177 " * An arrow --> indicates incomplete coverage.",
1178 " * An X indicates a function that was invoked, a switch label that ",
1179 " was exercised, a try-block that finished, or an exception handler ",
1180 " that was invoked.",
1181 " * A T or F indicates a boolean decision that evaluated true or false,",
1183 " * A t or f indicates a boolean condition within a decision if the ",
1184 " condition evaluated true or false, respectively.",
1185 " * A k indicates a constant decision or condition.",
1186 " * The slash / means this probe is excluded from summary results. ",
1190 //----------------------------------------------------------------------
1191 int cmCTestCoverageHandler::RunBullseyeCoverageBranch(
1192 cmCTestCoverageHandlerContainer
* cont
,
1193 std::set
<cmStdString
>& coveredFileNames
,
1194 std::vector
<std::string
>& files
,
1195 std::vector
<std::string
>& filesFullPath
)
1197 if(files
.size() != filesFullPath
.size())
1199 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1200 "Files and full path files not the same size?:\n");
1203 // create the output stream for the CoverageLog-N.xml file
1204 cmGeneratedFileStream covLogFile
;
1205 int logFileCount
= 0;
1206 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
1210 // for each file run covbr on that file to get the coverage
1211 // information for that file
1212 std::string outputFile
;
1213 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1217 if(!this->RunBullseyeCommand(cont
, "covbr", 0, outputFile
))
1219 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "error running covbr for." << "\n");
1222 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1223 "covbr output in " << outputFile
1225 // open the output file
1226 std::ifstream
fin(outputFile
.c_str());
1229 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1230 "Cannot open coverage file: " <<
1231 outputFile
.c_str() << std::endl
);
1234 std::map
<cmStdString
, cmStdString
> fileMap
;
1235 std::vector
<std::string
>::iterator fp
= filesFullPath
.begin();
1236 for(std::vector
<std::string
>::iterator f
= files
.begin();
1237 f
!= files
.end(); ++f
, ++fp
)
1242 int count
=0; // keep count of the number of files
1243 // Now parse each line from the bullseye cov log file
1245 bool valid
= false; // are we in a valid output file
1246 int line
= 0; // line of the current file
1248 while(cmSystemTools::GetLineFromStream(fin
, lineIn
))
1250 bool startFile
= false;
1251 if(lineIn
.size() > 1 && lineIn
[lineIn
.size()-1] == ':')
1253 file
= lineIn
.substr(0, lineIn
.size()-1);
1254 if(coveredFileNames
.find(file
) != coveredFileNames
.end())
1261 // if we are in a valid file close it because a new one started
1264 covLogFile
<< "\t\t</Report>" << std::endl
1265 << "\t</File>" << std::endl
;
1267 // only allow 100 files in each log file
1268 if ( count
!= 0 && count
% 100 == 0 )
1270 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1271 "start a new log file: "
1274 this->EndCoverageLogFile(covLogFile
, logFileCount
);
1276 if ( !this->StartCoverageLogFile(covLogFile
, logFileCount
) )
1280 count
++; // move on one
1282 std::map
<cmStdString
, cmStdString
>::iterator
1283 i
= fileMap
.find(file
);
1284 // if the file should be covered write out the header for that file
1285 if(i
!= fileMap
.end())
1287 // we have a new file so count it in the output
1289 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1290 "Produce coverage for file: "
1291 << file
.c_str() << " " << count
1293 // start the file output
1294 covLogFile
<< "\t<File Name=\""
1295 << this->CTest
->MakeXMLSafe(i
->first
.c_str())
1296 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
1297 this->CTest
->GetShortPathToFile(
1298 i
->second
.c_str())) << "\">" << std::endl
1299 << "\t\t<Report>" << std::endl
;
1300 // write the bullseye header
1302 for(int k
=0; bullseyeHelp
[k
] != 0; ++k
)
1304 covLogFile
<< "\t\t<Line Number=\"" << line
<< "\" Count=\"-1\">"
1305 << this->CTest
->MakeXMLSafe(bullseyeHelp
[k
])
1306 << "</Line>" << std::endl
;
1309 valid
= true; // we are in a valid file section
1313 // this is not a file that we want coverage for
1317 // we are not at a start file, and we are in a valid file output the line
1320 covLogFile
<< "\t\t<Line Number=\"" << line
<< "\" Count=\"-1\">"
1321 << this->CTest
->MakeXMLSafe(lineIn
.c_str())
1322 << "</Line>" << std::endl
;
1326 // if we ran out of lines a valid file then close that file
1329 covLogFile
<< "\t\t</Report>" << std::endl
1330 << "\t</File>" << std::endl
;
1332 this->EndCoverageLogFile(covLogFile
, logFileCount
);
1336 //----------------------------------------------------------------------
1337 int cmCTestCoverageHandler::RunBullseyeCommand(
1338 cmCTestCoverageHandlerContainer
* cont
,
1341 std::string
& outputFile
)
1343 std::string program
= cmSystemTools::FindProgram(cmd
);
1344 if(program
.size() == 0)
1346 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Cannot find :" << cmd
<< "\n");
1351 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1352 "Run : " << program
.c_str() << " " << arg
<< "\n");
1356 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1357 "Run : " << program
.c_str() << "\n");
1359 // create a process object and start it
1360 cmCTestRunProcess runCoverageSrc
;
1361 runCoverageSrc
.SetCommand(program
.c_str());
1362 runCoverageSrc
.AddArgument(arg
);
1363 std::string stdoutFile
= cont
->BinaryDir
+ "/Testing/Temporary/";
1364 stdoutFile
+= this->GetCTestInstance()->GetCurrentTag();
1367 std::string stderrFile
= stdoutFile
;
1368 stdoutFile
+= ".stdout";
1369 stderrFile
+= ".stderr";
1370 runCoverageSrc
.SetStdoutFile(stdoutFile
.c_str());
1371 runCoverageSrc
.SetStderrFile(stderrFile
.c_str());
1372 if(!runCoverageSrc
.StartProcess())
1374 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Could not run : "
1375 << program
.c_str() << " " << arg
<< "\n"
1376 << "kwsys process state : "
1377 << runCoverageSrc
.GetProcessState());
1380 // since we set the output file names wait for it to end
1381 runCoverageSrc
.WaitForExit();
1382 outputFile
= stdoutFile
;
1386 //----------------------------------------------------------------------
1387 int cmCTestCoverageHandler::RunBullseyeSourceSummary(
1388 cmCTestCoverageHandlerContainer
* cont
)
1390 // Run the covsrc command and create a temp outputfile
1391 std::string outputFile
;
1392 if(!this->RunBullseyeCommand(cont
, "covsrc", "-c", outputFile
))
1394 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "error running covsrc:\n");
1398 std::ostream
& tmpLog
= *cont
->OFS
;
1399 // copen the Coverage.xml file in the Testing directory
1400 cmGeneratedFileStream covSumFile
;
1401 if (!this->StartResultingXML("Coverage", covSumFile
))
1403 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1404 "Cannot open coverage summary file." << std::endl
);
1407 this->CTest
->StartXML(covSumFile
);
1408 double elapsed_time_start
= cmSystemTools::GetTime();
1409 std::string coverage_start_time
= this->CTest
->CurrentTime();
1410 covSumFile
<< "<Coverage>" << std::endl
1411 << "\t<StartDateTime>"
1412 << coverage_start_time
<< "</StartDateTime>"
1414 std::string stdline
;
1415 std::string errline
;
1418 // "Source","Function Coverage","out of","%","C/D Coverage","out of","%"
1419 // after that data follows in that format
1420 std::string sourceFile
;
1421 int functionsCalled
= 0;
1422 int totalFunctions
= 0;
1423 int percentFunction
= 0;
1424 int branchCovered
= 0;
1425 int totalBranches
= 0;
1426 int percentBranch
= 0;
1427 double total_tested
= 0;
1428 double total_untested
= 0;
1429 double total_functions
= 0;
1430 double percent_coverage
=0;
1431 double number_files
= 0;
1432 std::vector
<std::string
> coveredFiles
;
1433 std::vector
<std::string
> coveredFilesFullPath
;
1434 // Read and parse the summary output file
1435 std::ifstream
fin(outputFile
.c_str());
1438 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1439 "Cannot open coverage summary file: " <<
1440 outputFile
.c_str() << std::endl
);
1443 std::set
<cmStdString
> coveredFileNames
;
1444 while(cmSystemTools::GetLineFromStream(fin
, stdline
))
1446 // if we have a line of output from stdout
1449 // parse the comma separated output
1450 this->ParseBullsEyeCovsrcLine(stdline
,
1458 // The first line is the header
1459 if(sourceFile
== "Source" || sourceFile
== "Total")
1463 std::string file
= sourceFile
;
1464 coveredFileNames
.insert(file
);
1465 if(!cmSystemTools::FileIsFullPath(sourceFile
.c_str()))
1467 // file will be relative to the binary dir
1468 file
= cont
->BinaryDir
;
1472 file
= cmSystemTools::CollapseFullPath(file
.c_str());
1473 bool shouldIDoCoverage
1474 = this->ShouldIDoCoverage(file
.c_str(),
1475 cont
->SourceDir
.c_str(),
1476 cont
->BinaryDir
.c_str());
1477 if ( !shouldIDoCoverage
)
1479 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1480 ".NoDartCoverage found, so skip coverage check for: "
1486 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1487 "Doing coverage for: "
1491 coveredFiles
.push_back(sourceFile
);
1492 coveredFilesFullPath
.push_back(file
);
1495 total_functions
+= totalFunctions
;
1496 total_tested
+= functionsCalled
;
1497 total_untested
+= (totalFunctions
- functionsCalled
);
1499 std::string fileName
= cmSystemTools::GetFilenameName(file
.c_str());
1501 float cper
= percentBranch
+ percentFunction
;
1502 if(totalBranches
> 0)
1506 percent_coverage
+= cper
;
1507 float cmet
= percentFunction
+ percentBranch
;
1508 if(totalBranches
> 0)
1513 tmpLog
<< stdline
.c_str() << "\n";
1514 tmpLog
<< fileName
<< "\n";
1515 tmpLog
<< "functionsCalled: " << functionsCalled
/100 << "\n";
1516 tmpLog
<< "totalFunctions: " << totalFunctions
/100 << "\n";
1517 tmpLog
<< "percentFunction: " << percentFunction
<< "\n";
1518 tmpLog
<< "branchCovered: " << branchCovered
<< "\n";
1519 tmpLog
<< "totalBranches: " << totalBranches
<< "\n";
1520 tmpLog
<< "percentBranch: " << percentBranch
<< "\n";
1521 tmpLog
<< "percentCoverage: " << percent_coverage
<< "\n";
1522 tmpLog
<< "coverage metric: " << cmet
<< "\n";
1523 covSumFile
<< "\t<File Name=\"" << this->CTest
->MakeXMLSafe(sourceFile
)
1524 << "\" FullPath=\"" << this->CTest
->MakeXMLSafe(
1525 this->CTest
->GetShortPathToFile(file
.c_str()))
1526 << "\" Covered=\"" << (cmet
>0?"true":"false") << "\">\n"
1527 << "\t\t<BranchesTested>"
1529 << "</BranchesTested>\n"
1530 << "\t\t<BranchesUnTested>"
1531 << totalBranches
- branchCovered
1532 << "</BranchesUnTested>\n"
1533 << "\t\t<FunctionsTested>"
1535 << "</FunctionsTested>\n"
1536 << "\t\t<FunctionsUnTested>"
1537 << totalFunctions
- functionsCalled
1538 << "</FunctionsUnTested>\n"
1539 // Hack for conversion of function to loc assume a function
1540 // has 100 lines of code
1541 << "\t\t<LOCTested>" << functionsCalled
*100
1543 << "\t\t<LOCUnTested>"
1544 << (totalFunctions
- functionsCalled
)*100
1545 << "</LOCUnTested>\n"
1546 << "\t\t<PercentCoverage>";
1547 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1548 covSumFile
.precision(2);
1549 covSumFile
<< (cper
) << "</PercentCoverage>\n"
1550 << "\t\t<CoverageMetric>";
1551 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1552 covSumFile
.precision(2);
1553 covSumFile
<< (cmet
) << "</CoverageMetric>\n"
1554 << "\t</File>" << std::endl
;
1557 std::string end_time
= this->CTest
->CurrentTime();
1558 covSumFile
<< "\t<LOCTested>" << total_tested
<< "</LOCTested>\n"
1559 << "\t<LOCUntested>" << total_untested
<< "</LOCUntested>\n"
1560 << "\t<LOC>" << total_functions
<< "</LOC>\n"
1561 << "\t<PercentCoverage>";
1562 covSumFile
.setf(std::ios::fixed
, std::ios::floatfield
);
1563 covSumFile
.precision(2);
1564 covSumFile
<< SAFEDIV(percent_coverage
,number_files
)<< "</PercentCoverage>\n"
1565 << "\t<EndDateTime>" << end_time
<< "</EndDateTime>\n";
1566 covSumFile
<< "<ElapsedMinutes>" <<
1567 static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start
)/6)/10.0
1568 << "</ElapsedMinutes>"
1569 << "</Coverage>" << std::endl
;
1570 this->CTest
->EndXML(covSumFile
);
1571 // Now create the coverage information for each file
1572 return this->RunBullseyeCoverageBranch(cont
,
1575 coveredFilesFullPath
);
1578 //----------------------------------------------------------------------
1579 int cmCTestCoverageHandler::HandleBullseyeCoverage(
1580 cmCTestCoverageHandlerContainer
* cont
)
1582 const char* covfile
= cmSystemTools::GetEnv("COVFILE");
1585 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1586 " COVFILE environment variable not found, not running "
1590 cmCTestLog(this->CTest
, HANDLER_VERBOSE_OUTPUT
,
1591 " run covsrc with COVFILE=["
1593 << "]" << std::endl
);
1594 if(!this->RunBullseyeSourceSummary(cont
))
1596 cmCTestLog(this->CTest
, ERROR_MESSAGE
,
1597 "Error running bullseye summary.\n");
1603 bool cmCTestCoverageHandler::GetNextInt(std::string
const& inputLine
,
1604 std::string::size_type
& pos
,
1607 std::string::size_type start
= pos
;
1608 pos
= inputLine
.find(',', start
);
1609 value
= atoi(inputLine
.substr(start
, pos
).c_str());
1610 if(pos
== inputLine
.npos
)
1618 bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine(
1619 std::string
const& inputLine
,
1620 std::string
& sourceFile
,
1621 int& functionsCalled
,
1622 int& totalFunctions
,
1623 int& percentFunction
,
1628 // find the first comma
1629 std::string::size_type pos
= inputLine
.find(',');
1630 if(pos
== inputLine
.npos
)
1632 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Error parsing string : "
1633 << inputLine
.c_str() << "\n");
1636 // the source file has "" around it so extract out the file name
1637 sourceFile
= inputLine
.substr(1,pos
-2);
1639 if(!this->GetNextInt(inputLine
, pos
, functionsCalled
))
1643 if(!this->GetNextInt(inputLine
, pos
, totalFunctions
))
1647 if(!this->GetNextInt(inputLine
, pos
, percentFunction
))
1651 if(!this->GetNextInt(inputLine
, pos
, branchCovered
))
1655 if(!this->GetNextInt(inputLine
, pos
, totalBranches
))
1659 if(!this->GetNextInt(inputLine
, pos
, percentBranch
))
1663 // should be at the end now
1664 if(pos
!= inputLine
.npos
)
1666 cmCTestLog(this->CTest
, ERROR_MESSAGE
, "Error parsing input : "
1667 << inputLine
.c_str() << " last pos not npos = " << pos
<<