ENH: Teach ctest_coverage to filter with LABELS

This teaches ctest_coverage() to report only coverage of files labeled
with at least one label given by a new LABELS option.
This commit is contained in:
Brad King 2009-03-02 15:33:18 -05:00
parent 3078fef81c
commit 91a8569648
4 changed files with 105 additions and 4 deletions

View File

@ -17,22 +17,55 @@
#include "cmCTestCoverageCommand.h" #include "cmCTestCoverageCommand.h"
#include "cmCTest.h" #include "cmCTest.h"
#include "cmCTestGenericHandler.h" #include "cmCTestCoverageHandler.h"
cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
{ {
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile, this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
"CoverageCommand", "CTEST_COVERAGE_COMMAND"); "CoverageCommand", "CTEST_COVERAGE_COMMAND");
cmCTestGenericHandler* handler cmCTestCoverageHandler* handler = static_cast<cmCTestCoverageHandler*>(
= this->CTest->GetInitializedHandler("coverage"); this->CTest->GetInitializedHandler("coverage"));
if ( !handler ) if ( !handler )
{ {
this->SetError("internal CTest error. Cannot instantiate test handler"); this->SetError("internal CTest error. Cannot instantiate test handler");
return 0; return 0;
} }
// If a LABELS option was given, select only files with the labels.
if(this->LabelsMentioned)
{
handler->SetLabelFilter(this->Labels);
}
return handler; 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);
}

View File

@ -60,11 +60,15 @@ public:
virtual const char* GetFullDocumentation() virtual const char* GetFullDocumentation()
{ {
return 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 " "Perform the coverage of the given build directory and stores results "
"in Coverage.xml. The second argument is a variable that will hold " "in Coverage.xml. The second argument is a variable that will hold "
"value." "value."
"\n" "\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; CTEST_COMMAND_APPEND_OPTION_DOCS;
} }
@ -72,6 +76,18 @@ public:
protected: protected:
cmCTestGenericHandler* InitializeHandler(); 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<cmStdString> Labels;
}; };

View File

@ -17,6 +17,7 @@
#include "cmCTestCoverageHandler.h" #include "cmCTestCoverageHandler.h"
#include "cmCTest.h" #include "cmCTest.h"
#include "cmake.h" #include "cmake.h"
#include "cmMakefile.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmGeneratedFileStream.h" #include "cmGeneratedFileStream.h"
#include "cmXMLSafe.h" #include "cmXMLSafe.h"
@ -24,6 +25,8 @@
#include <cmsys/Process.h> #include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx> #include <cmsys/RegularExpression.hxx>
#include <cmsys/Glob.hxx> #include <cmsys/Glob.hxx>
#include <cmsys/stl/iterator>
#include <cmsys/stl/algorithm>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
@ -156,6 +159,7 @@ void cmCTestCoverageHandler::Initialize()
this->SourceLabels.clear(); this->SourceLabels.clear();
this->LabelIdMap.clear(); this->LabelIdMap.clear();
this->Labels.clear(); this->Labels.clear();
this->LabelFilter.clear();
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -207,6 +211,11 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file,
const char* srcDir, const char* srcDir,
const char* binDir) const char* binDir)
{ {
if(this->IsFilteredOut(file))
{
return false;
}
std::vector<cmsys::RegularExpression>::iterator sit; std::vector<cmsys::RegularExpression>::iterator sit;
for ( sit = this->CustomCoverageExcludeRegex.begin(); for ( sit = this->CustomCoverageExcludeRegex.begin();
sit != this->CustomCoverageExcludeRegex.end(); ++ sit ) sit != this->CustomCoverageExcludeRegex.end(); ++ sit )
@ -1817,3 +1826,39 @@ void cmCTestCoverageHandler::WriteXMLLabels(std::ofstream& os,
os << "\t\t</Labels>\n"; os << "\t\t</Labels>\n";
} }
} }
//----------------------------------------------------------------------------
void
cmCTestCoverageHandler::SetLabelFilter(std::set<cmStdString> const& labels)
{
this->LabelFilter.clear();
for(std::set<cmStdString>::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<int> 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();
}

View File

@ -50,6 +50,9 @@ public:
*/ */
void PopulateCustomVectors(cmMakefile *mf); void PopulateCustomVectors(cmMakefile *mf);
/** Report coverage only for sources with these labels. */
void SetLabelFilter(std::set<cmStdString> const& labels);
private: private:
bool ShouldIDoCoverage(const char* file, const char* srcDir, bool ShouldIDoCoverage(const char* file, const char* srcDir,
const char* binDir); const char* binDir);
@ -153,6 +156,10 @@ private:
void LoadLabels(); void LoadLabels();
void LoadLabels(const char* fname); void LoadLabels(const char* fname);
void WriteXMLLabels(std::ofstream& os, std::string const& source); void WriteXMLLabels(std::ofstream& os, std::string const& source);
// Label-based filtering.
std::set<int> LabelFilter;
bool IsFilteredOut(std::string const& source);
}; };
#endif #endif