diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index bf64afc02..067a4e96d 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -17,22 +17,55 @@ #include "cmCTestCoverageCommand.h" #include "cmCTest.h" -#include "cmCTestGenericHandler.h" +#include "cmCTestCoverageHandler.h" cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() { this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, "CoverageCommand", "CTEST_COVERAGE_COMMAND"); - cmCTestGenericHandler* handler - = this->CTest->GetInitializedHandler("coverage"); + cmCTestCoverageHandler* handler = static_cast( + this->CTest->GetInitializedHandler("coverage")); if ( !handler ) { this->SetError("internal CTest error. Cannot instantiate test handler"); return 0; } + + // If a LABELS option was given, select only files with the labels. + if(this->LabelsMentioned) + { + handler->SetLabelFilter(this->Labels); + } + return handler; } +//---------------------------------------------------------------------------- +bool cmCTestCoverageCommand::CheckArgumentKeyword(std::string const& arg) +{ + // Look for arguments specific to this command. + if(arg == "LABELS") + { + this->ArgumentDoing = ArgumentDoingLabels; + this->LabelsMentioned = true; + return true; + } + // Look for other arguments. + return this->Superclass::CheckArgumentKeyword(arg); +} +//---------------------------------------------------------------------------- +bool cmCTestCoverageCommand::CheckArgumentValue(std::string const& arg) +{ + // Handle states specific to this command. + if(this->ArgumentDoing == ArgumentDoingLabels) + { + this->Labels.insert(arg); + return true; + } + + // Look for other arguments. + return this->Superclass::CheckArgumentValue(arg); +} diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index 379639236..c2062cd08 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -60,11 +60,15 @@ public: virtual const char* GetFullDocumentation() { return - " ctest_coverage([BUILD build_dir] [RETURN_VALUE res] [APPEND])\n" + " ctest_coverage([BUILD build_dir] [RETURN_VALUE res] [APPEND]\n" + " [LABELS label1 [label2 [...]]])\n" "Perform the coverage of the given build directory and stores results " "in Coverage.xml. The second argument is a variable that will hold " "value." "\n" + "The LABELS option filters the coverage report to include only " + "source files labeled with at least one of the labels specified." + "\n" CTEST_COMMAND_APPEND_OPTION_DOCS; } @@ -72,6 +76,18 @@ public: protected: cmCTestGenericHandler* InitializeHandler(); + + virtual bool CheckArgumentKeyword(std::string const& arg); + virtual bool CheckArgumentValue(std::string const& arg); + + enum + { + ArgumentDoingLabels = Superclass::ArgumentDoingLast1, + ArgumentDoingLast2 + }; + + bool LabelsMentioned; + std::set Labels; }; diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index f39b7e1c9..1faf05abb 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -17,6 +17,7 @@ #include "cmCTestCoverageHandler.h" #include "cmCTest.h" #include "cmake.h" +#include "cmMakefile.h" #include "cmSystemTools.h" #include "cmGeneratedFileStream.h" #include "cmXMLSafe.h" @@ -24,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -156,6 +159,7 @@ void cmCTestCoverageHandler::Initialize() this->SourceLabels.clear(); this->LabelIdMap.clear(); this->Labels.clear(); + this->LabelFilter.clear(); } //---------------------------------------------------------------------- @@ -207,6 +211,11 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file, const char* srcDir, const char* binDir) { + if(this->IsFilteredOut(file)) + { + return false; + } + std::vector::iterator sit; for ( sit = this->CustomCoverageExcludeRegex.begin(); sit != this->CustomCoverageExcludeRegex.end(); ++ sit ) @@ -1817,3 +1826,39 @@ void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os, os << "\t\t\n"; } } + +//---------------------------------------------------------------------------- +void +cmCTestCoverageHandler::SetLabelFilter(std::set const& labels) +{ + this->LabelFilter.clear(); + for(std::set::const_iterator li = labels.begin(); + li != labels.end(); ++li) + { + this->LabelFilter.insert(this->GetLabelId(*li)); + } +} + +//---------------------------------------------------------------------- +bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source) +{ + // If there is no label filter then nothing is filtered out. + if(this->LabelFilter.empty()) + { + return false; + } + + // The source is filtered out if it does not have any labels in + // common with the filter set. + std::vector ids; + std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str()); + LabelMapType::const_iterator li = this->SourceLabels.find(shortSrc); + if(li != this->SourceLabels.end() && !li->second.empty()) + { + cmsys_stl::set_intersection + (li->second.begin(), li->second.end(), + this->LabelFilter.begin(), this->LabelFilter.end(), + cmsys_stl::back_inserter(ids)); + } + return ids.empty(); +} diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index b391b87e8..48894fb31 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -50,6 +50,9 @@ public: */ void PopulateCustomVectors(cmMakefile *mf); + /** Report coverage only for sources with these labels. */ + void SetLabelFilter(std::set const& labels); + private: bool ShouldIDoCoverage(const char* file, const char* srcDir, const char* binDir); @@ -153,6 +156,10 @@ private: void LoadLabels(); void LoadLabels(const char* fname); void WriteXMLLabels(std::ofstream& os, std::string const& source); + + // Label-based filtering. + std::set LabelFilter; + bool IsFilteredOut(std::string const& source); }; #endif