From 70b1ed2548aae673c4b798fc18c5b5c91d9ef6d8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 13 Feb 2009 15:17:06 -0500 Subject: [PATCH] ENH: Teach CTest to put labels in coverage results This teaches CTest to include source file labels in coverage dashboard submissions. The labels for each source are the union of the LABELS property from the source file and all the targets in which it is built. --- Source/CTest/cmCTestCoverageHandler.cxx | 113 ++++++++++++++++++++++-- Source/CTest/cmCTestCoverageHandler.h | 16 ++++ 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 71d5abc2b..678ec7584 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -319,6 +319,8 @@ int cmCTestCoverageHandler::ProcessHandler() std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory"); + this->LoadLabels(); + cmGeneratedFileStream ofs; double elapsed_time_start = cmSystemTools::GetTime(); if ( !this->StartLogFile("Coverage", ofs) ) @@ -464,13 +466,12 @@ int cmCTestCoverageHandler::ProcessHandler() continue; } + std::string shortFileName = + this->CTest->GetShortPathToFile(fullFileName.c_str()); const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov = fileIterator->second; - covLogFile << "\tCTest->GetShortPathToFile( - fileIterator->first.c_str())) << "\">" << std::endl + covLogFile << "\t\n" << "\t\t" << std::endl; std::ifstream ifs(fullFileName.c_str()); @@ -546,8 +547,9 @@ int cmCTestCoverageHandler::ProcessHandler() << "\t\t"; covSumFile.setf(std::ios::fixed, std::ios::floatfield); covSumFile.precision(2); - covSumFile << (cmet) << "\n" - << "\t" << std::endl; + covSumFile << (cmet) << "\n"; + this->WriteXMLLabels(covSumFile, shortFileName); + covSumFile << "\t" << std::endl; cnt ++; } this->EndCoverageLogFile(covLogFile, logFileCount); @@ -1713,3 +1715,100 @@ bool cmCTestCoverageHandler::ParseBullsEyeCovsrcLine( } return true; } + +//---------------------------------------------------------------------- +int cmCTestCoverageHandler::GetLabelId(std::string const& label) +{ + LabelIdMapType::iterator i = this->LabelIdMap.find(label); + if(i == this->LabelIdMap.end()) + { + int n = int(this->Labels.size()); + this->Labels.push_back(label); + LabelIdMapType::value_type entry(label, n); + i = this->LabelIdMap.insert(entry).first; + } + return i->second; +} + +//---------------------------------------------------------------------- +void cmCTestCoverageHandler::LoadLabels() +{ + std::string fileList = this->CTest->GetBinaryDir(); + fileList += cmake::GetCMakeFilesDirectory(); + fileList += "/LabelFiles.txt"; + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + " label file list [" << fileList << "]\n"); + std::ifstream finList(fileList.c_str()); + std::string line; + while(cmSystemTools::GetLineFromStream(finList, line)) + { + this->LoadLabels(line.c_str()); + } +} + +//---------------------------------------------------------------------- +void cmCTestCoverageHandler::LoadLabels(const char* fname) +{ + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + " loading labels from [" << fname << "]\n"); + std::ifstream fin(fname); + bool inTarget = true; + std::string source; + std::string line; + std::vector targetLabels; + while(cmSystemTools::GetLineFromStream(fin, line)) + { + if(line.empty() || line[0] == '#') + { + // Ignore blank and comment lines. + continue; + } + else if(line[0] == ' ') + { + // Label lines appear indented by one space. + std::string label = line.substr(1); + int id = this->GetLabelId(label); + if(inTarget) + { + targetLabels.push_back(id); + } + else + { + this->SourceLabels[source].insert(id); + } + } + else + { + // Non-indented lines specify a source file name. The first one + // is the end of the target-wide labels. + inTarget = false; + + source = this->CTest->GetShortPathToFile(line.c_str()); + + // Label the source with the target labels. + LabelSet& labelSet = this->SourceLabels[source]; + for(std::vector::const_iterator li = targetLabels.begin(); + li != targetLabels.end(); ++li) + { + labelSet.insert(*li); + } + } + } +} + +//---------------------------------------------------------------------- +void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os, + std::string const& source) +{ + LabelMapType::const_iterator li = this->SourceLabels.find(source); + if(li != this->SourceLabels.end() && !li->second.empty()) + { + os << "\t\t\n"; + for(LabelSet::const_iterator lsi = li->second.begin(); + lsi != li->second.end(); ++lsi) + { + os << "\t\t\t\n"; + } + os << "\t\t\n"; + } +} diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index 658ab7845..b391b87e8 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -137,6 +137,22 @@ private: std::vector CustomCoverageExcludeRegex; typedef std::map CoverageMap; + + // Map from source file to label ids. + class LabelSet: public std::set {}; + typedef std::map LabelMapType; + LabelMapType SourceLabels; + + // Map from label name to label id. + typedef std::map LabelIdMapType; + LabelIdMapType LabelIdMap; + std::vector Labels; + int GetLabelId(std::string const& label); + + // Load reading and writing methods. + void LoadLabels(); + void LoadLabels(const char* fname); + void WriteXMLLabels(std::ofstream& os, std::string const& source); }; #endif