diff options
author | Andy Cedilnik <andy.cedilnik@kitware.com> | 2007-04-27 03:20:12 (GMT) |
---|---|---|
committer | Andy Cedilnik <andy.cedilnik@kitware.com> | 2007-04-27 03:20:12 (GMT) |
commit | 64e0459f93d303bef1330c0c2bc988c67c1c8582 (patch) | |
tree | bb3058f3ca86d1c8b0038a4bc261788f3d3a3987 /Source | |
parent | 1d4613a63bbdd5eafc8add05bf58e5c61c7ca5e5 (diff) | |
download | CMake-64e0459f93d303bef1330c0c2bc988c67c1c8582.zip CMake-64e0459f93d303bef1330c0c2bc988c67c1c8582.tar.gz CMake-64e0459f93d303bef1330c0c2bc988c67c1c8582.tar.bz2 |
ENH: Initial attempt to do python coverage. Hopefully will not break coverage on GCov
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.cxx | 759 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.h | 7 |
2 files changed, 487 insertions, 279 deletions
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index c3295f0..9dfef44 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -33,6 +33,22 @@ #define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0)) //---------------------------------------------------------------------- +//********************************************************************** +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() { } @@ -186,12 +202,12 @@ int cmCTestCoverageHandler::ProcessHandler() return error; } + std::string coverage_start_time = this->CTest->CurrentTime(); + std::string sourceDir = this->CTest->GetCTestConfiguration("SourceDirectory"); std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory"); - std::string gcovCommand - = this->CTest->GetCTestConfiguration("CoverageCommand"); cmGeneratedFileStream ofs; double elapsed_time_start = cmSystemTools::GetTime(); @@ -209,6 +225,298 @@ int cmCTestCoverageHandler::ProcessHandler() std::string asfGlob = sourceDir + "/*"; std::string abfGlob = binaryDir + "/*"; + cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl); + + cmCTestCoverageHandlerContainer cont; + cont.Error = error; + cont.SourceDir = sourceDir; + cont.BinaryDir = binaryDir; + cont.OFS = &ofs; + + 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; + + + 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("Coverage", covSumFile)) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Cannot open coverage summary file." << std::endl); + return -1; + } + + this->CTest->StartXML(covSumFile); + // Produce output xml files + + covSumFile << "<Coverage>" << std::endl + << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>" + << 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, " "); + } + if ( cnt % 100 == 0 ) + { + this->EndCoverageLogFile(covLogFile, logFileCount); + logFileCount ++; + if ( !this->StartCoverageLogFile(covLogFile, logFileCount) ) + { + return -1; + } + } + const std::string fullFileName = fileIterator->first; + const std::string fileName + = cmSystemTools::GetFilenameName(fullFileName.c_str()); + std::string fullFilePath + = cmSystemTools::GetFilenamePath(fullFileName.c_str()); + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Process file: " << fullFileName << std::endl); + + cmSystemTools::ConvertToUnixSlashes(fullFilePath); + + if ( !cmSystemTools::FileExists(fullFileName.c_str()) ) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: " + << fullFileName.c_str() << std::endl); + continue; + } + + 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; + } + + const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov + = fileIterator->second; + covLogFile << "\t<File Name=\"" + << this->CTest->MakeXMLSafe(fileName.c_str()) + << "\" FullPath=\"" << this->CTest->MakeXMLSafe( + this->CTest->GetShortPathToFile( + fileIterator->first.c_str())) << "\">" << std::endl + << "\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] + << "\">" + << this->CTest->MakeXMLSafe(line.c_str()) << "</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=\"" << this->CTest->MakeXMLSafe(fileName) + << "\" FullPath=\"" << this->CTest->MakeXMLSafe( + this->CTest->GetShortPathToFile(fullFileName.c_str())) + << "\" Covered=\"" << (cmet>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" + << "\t</File>" << std::endl; + cnt ++; + } + 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); + } + } + + int 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"; + 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); + 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); + } +} + +//---------------------------------------------------------------------- +int cmCTestCoverageHandler::HandleGCovCoverage( + cmCTestCoverageHandlerContainer* cont) +{ + std::string gcovCommand + = this->CTest->GetCTestConfiguration("CoverageCommand"); // Style 1 std::string st1gcovOutputRex1 @@ -234,22 +542,13 @@ int cmCTestCoverageHandler::ProcessHandler() cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str()); cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str()); - cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl); - - std::string coverage_start_time = this->CTest->CurrentTime(); - - 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()); cmsys::Glob gl; gl.RecurseOn(); - std::string daGlob = binaryDir + "/*.da"; + std::string daGlob = cont->BinaryDir + "/*.da"; gl.FindFiles(daGlob); std::vector<std::string> files = gl.GetFiles(); - daGlob = binaryDir + "/*.gcda"; + daGlob = cont->BinaryDir + "/*.gcda"; gl.FindFiles(daGlob); std::vector<std::string>& moreFiles = gl.GetFiles(); files.insert(files.end(), moreFiles.begin(), moreFiles.end()); @@ -257,14 +556,19 @@ int cmCTestCoverageHandler::ProcessHandler() if ( files.size() == 0 ) { - cmCTestLog(this->CTest, WARNING, - " Cannot find any coverage files. Ignoring Coverage request." + 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 - cmSystemTools::ChangeDirectory(currentDirectory.c_str()); 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()); + this->CustomCoverageExcludeRegex.empty(); std::vector<cmStdString>::iterator rexIt; for ( rexIt = this->CustomCoverageExclude.begin(); @@ -275,11 +579,6 @@ int cmCTestCoverageHandler::ProcessHandler() cmsys::RegularExpression(rexIt->c_str())); } - typedef std::vector<int> singleFileCoverageVector; - typedef std::map<std::string, singleFileCoverageVector> totalCoverageMap; - - totalCoverageMap totalCoverage; - int gcovStyle = 0; std::set<std::string> missingFiles; @@ -300,20 +599,20 @@ int cmCTestCoverageHandler::ProcessHandler() std::string output = ""; std::string errors = ""; int retVal = 0; - ofs << "* Run coverage for: " << fileDir.c_str() << std::endl; - ofs << " Command: " << command.c_str() << std::endl; + *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*/); - ofs << " Output: " << output.c_str() << std::endl; - ofs << " Errors: " << errors.c_str() << std::endl; + *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); - error ++; + cont->Error ++; continue; } if ( retVal != 0 ) @@ -321,7 +620,7 @@ int cmCTestCoverageHandler::ProcessHandler() cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: " << retVal << " while processing: " << it->c_str() << std::endl); cmCTestLog(this->CTest, ERROR_MESSAGE, - "Command produced error: " << error << std::endl); + "Command produced error: " << cont->Error << std::endl); } cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "--------------------------------------------------------------" @@ -353,7 +652,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 1; @@ -370,7 +669,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 1; @@ -386,7 +685,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -403,7 +702,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -417,7 +716,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -433,7 +732,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -450,7 +749,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -467,7 +766,7 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style" << std::endl); - error ++; + cont->Error ++; break; } gcovStyle = 2; @@ -480,12 +779,13 @@ int cmCTestCoverageHandler::ProcessHandler() { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown line: [" << line->c_str() << "]" << std::endl); - error ++; + cont->Error ++; //abort(); } if ( !gcovFile.empty() && actualSourceFile.size() ) { - singleFileCoverageVector* vec = &totalCoverage[actualSourceFile]; + cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec + = &cont->TotalCoverage[actualSourceFile]; cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in file: " << gcovFile << std::endl); std::ifstream ifile(gcovFile.c_str()); @@ -527,7 +827,7 @@ int cmCTestCoverageHandler::ProcessHandler() if ( lineIdx >= 0 ) { while ( vec->size() <= - static_cast<singleFileCoverageVector::size_type>(lineIdx) ) + static_cast<size_t>(lineIdx) ) { vec->push_back(-1); } @@ -550,25 +850,25 @@ int cmCTestCoverageHandler::ProcessHandler() { gcovFile = ""; // Is it in the source dir? - if ( sourceFile.size() > sourceDir.size() && - sourceFile.substr(0, sourceDir.size()) == sourceDir && - sourceFile[sourceDir.size()] == '/' ) + if ( sourceFile.size() > cont->SourceDir.size() && + sourceFile.substr(0, cont->SourceDir.size()) == cont->SourceDir && + sourceFile[cont->SourceDir.size()] == '/' ) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced s: " << sourceFile.c_str() << std::endl); - ofs << " produced in source dir: " << sourceFile.c_str() + *cont->OFS << " produced in source dir: " << sourceFile.c_str() << std::endl; actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile.c_str()); } // Binary dir? - if ( sourceFile.size() > binaryDir.size() && - sourceFile.substr(0, binaryDir.size()) == binaryDir && - sourceFile[binaryDir.size()] == '/' ) + if ( sourceFile.size() > cont->BinaryDir.size() && + sourceFile.substr(0, cont->BinaryDir.size()) == cont->BinaryDir && + sourceFile[cont->BinaryDir.size()] == '/' ) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced b: " << sourceFile.c_str() << std::endl); - ofs << " produced in binary dir: " << sourceFile.c_str() + *cont->OFS << " produced in binary dir: " << sourceFile.c_str() << std::endl; actualSourceFile = cmSystemTools::CollapseFullPath(sourceFile.c_str()); @@ -582,13 +882,13 @@ int cmCTestCoverageHandler::ProcessHandler() cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "File: [" << sourceFile.c_str() << "]" << std::endl); cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "s: [" - << sourceFile.substr(0, sourceDir.size()) << "]" << std::endl); + << sourceFile.substr(0, cont->SourceDir.size()) << "]" << std::endl); cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "b: [" - << sourceFile.substr(0, binaryDir.size()) << "]" << std::endl); - ofs << " Something went wrong. Cannot find: " + << sourceFile.substr(0, cont->BinaryDir.size()) << "]" << std::endl); + *cont->OFS << " Something went wrong. Cannot find: " << sourceFile.c_str() - << " in source dir: " << sourceDir.c_str() - << " or binary dir: " << binaryDir.c_str() << std::endl; + << " in source dir: " << cont->SourceDir.c_str() + << " or binary dir: " << cont->BinaryDir.c_str() << std::endl; missingFiles.insert(actualSourceFile); } } @@ -602,259 +902,160 @@ int cmCTestCoverageHandler::ProcessHandler() cmCTestLog(this->CTest, HANDLER_OUTPUT, " "); } } + cmSystemTools::ChangeDirectory(currentDirectory.c_str()); + return file_count; +} - cmGeneratedFileStream covSumFile; - cmGeneratedFileStream covLogFile; +//---------------------------------------------------------------------- +int cmCTestCoverageHandler::HandleTracePyCoverage( + cmCTestCoverageHandlerContainer* cont) +{ + cmsys::Glob gl; + gl.RecurseOn(); + std::string daGlob = cont->BinaryDir + "/*.cover"; + gl.FindFiles(daGlob); + std::vector<std::string> files = gl.GetFiles(); - if (!this->StartResultingXML("Coverage", covSumFile)) + if ( files.size() == 0 ) { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Cannot open coverage summary file." << std::endl); - cmSystemTools::ChangeDirectory(currentDirectory.c_str()); - return -1; + 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; } - this->CTest->StartXML(covSumFile); - // Produce output xml files - - covSumFile << "<Coverage>" << std::endl - << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>" - << std::endl; - int logFileCount = 0; - if ( !this->StartCoverageLogFile(covLogFile, logFileCount) ) - { - cmSystemTools::ChangeDirectory(currentDirectory.c_str()); - return -1; - } - 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::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()); - std::vector<std::string> errorsWhileAccumulating; + cmSystemTools::ChangeDirectory(currentDirectory.c_str()); - file_count = 0; - for ( fileIterator = totalCoverage.begin(); - fileIterator != totalCoverage.end(); - ++fileIterator ) + std::vector<std::string>::iterator fileIt; + int file_count = 0; + for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt ) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush); - file_count ++; - if ( file_count % 50 == 0 ) + std::string fileName = this->FindFile(cont, *fileIt); + if ( fileName.empty() ) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count - << " out of " - << totalCoverage.size() << std::endl); - cmCTestLog(this->CTest, HANDLER_OUTPUT, " "); - } - if ( cnt % 100 == 0 ) - { - this->EndCoverageLogFile(covLogFile, logFileCount); - logFileCount ++; - if ( !this->StartCoverageLogFile(covLogFile, logFileCount) ) - { - cmSystemTools::ChangeDirectory(currentDirectory.c_str()); - return -1; - } - } - const std::string fullFileName = fileIterator->first; - const std::string fileName - = cmSystemTools::GetFilenameName(fullFileName.c_str()); - std::string fullFilePath - = cmSystemTools::GetFilenamePath(fullFileName.c_str()); - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Process file: " - << fullFileName << std::endl); - - cmSystemTools::ConvertToUnixSlashes(fullFilePath); - - if ( !cmSystemTools::FileExists(fullFileName.c_str()) ) - { - cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: " - << fullFileName.c_str() << std::endl); + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Cannot find source Python file corresponding to: " + << fileIt->c_str() << std::endl); continue; } - bool shouldIDoCoverage - = this->ShouldIDoCoverage(fullFileName.c_str(), - sourceDir.c_str(), binaryDir.c_str()); - if ( !shouldIDoCoverage ) + 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, HANDLER_VERBOSE_OUTPUT, - ".NoDartCoverage found, so skip coverage check for: " - << fullFileName.c_str() - << std::endl); - continue; + cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: " + << fileIt->c_str() << std::endl); } - - const singleFileCoverageVector& fcov = fileIterator->second; - covLogFile << "\t<File Name=\"" - << this->CTest->MakeXMLSafe(fileName.c_str()) - << "\" FullPath=\"" << this->CTest->MakeXMLSafe( - this->CTest->GetShortPathToFile( - fileIterator->first.c_str())) << "\">" << std::endl - << "\t\t<Report>" << std::endl; - - std::ifstream ifs(fullFileName.c_str()); - if ( !ifs) + else { - cmOStringStream ostr; - ostr << "Cannot open source file: " << fullFileName.c_str(); - errorsWhileAccumulating.push_back(ostr.str()); - error ++; - continue; - } + long cnt = -1; + std::string nl; + while ( cmSystemTools::GetLineFromStream(ifile, nl) ) + { + cnt ++; - int tested = 0; - int untested = 0; + // Skip empty lines + if ( !nl.size() ) + { + continue; + } - singleFileCoverageVector::size_type cc; - std::string line; - 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] - << "\">" - << this->CTest->MakeXMLSafe(line.c_str()) << "</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=\"" << this->CTest->MakeXMLSafe(fileName) - << "\" FullPath=\"" << this->CTest->MakeXMLSafe( - this->CTest->GetShortPathToFile(fullFileName.c_str())) - << "\" Covered=\"" << (cmet>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" - << "\t</File>" << std::endl; - cnt ++; - } - this->EndCoverageLogFile(covLogFile, logFileCount); + // Skip unused lines + if ( nl.size() < 12 ) + { + continue; + } - 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); + // 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 + int 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; } - - int 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"; - 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, "\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; - cmSystemTools::ChangeDirectory(currentDirectory.c_str()); - - if ( error ) - { - return -1; - } - return 0; + return file_count; } //---------------------------------------------------------------------- -void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf) +std::string cmCTestCoverageHandler::FindFile( + cmCTestCoverageHandlerContainer* cont, + std::string fileName) { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, - " Add coverage exclude regular expressions." << std::endl); - this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE", - this->CustomCoverageExclude); - std::vector<cmStdString>::iterator it; - for ( it = this->CustomCoverageExclude.begin(); - it != this->CustomCoverageExclude.end(); - ++ it ) + 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()) ) { - cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: " - << it->c_str() << std::endl); + return fullName; + } + fullName = cont->BinaryDir + "/" + fileNameNoE + ".py"; + if ( cmSystemTools::FileExists(fullName.c_str()) ) + { + return fullName; } + return ""; } diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index d2e798b..38422e0 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -25,6 +25,7 @@ #include <cmsys/RegularExpression.hxx> class cmGeneratedFileStream; +class cmCTestCoverageHandlerContainer; /** \class cmCTestCoverageHandler * \brief A class that handles coverage computaiton for ctest @@ -55,6 +56,12 @@ private: bool StartCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount); void EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount); + int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont); + int HandleTracePyCoverage(cmCTestCoverageHandlerContainer* cont); + + std::string FindFile(cmCTestCoverageHandlerContainer* cont, + std::string fileName); + struct cmCTestCoverage { cmCTestCoverage() |