Bladeren bron

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.
Brad King 16 jaren geleden
bovenliggende
commit
91a8569648

+ 36 - 3
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<cmCTestCoverageHandler*>(
+    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);
+}

+ 17 - 1
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<cmStdString> Labels;
 };
 
 

+ 45 - 0
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 <cmsys/Process.h>
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/Glob.hxx>
+#include <cmsys/stl/iterator>
+#include <cmsys/stl/algorithm>
 
 #include <stdlib.h>
 #include <math.h>
@@ -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<cmsys::RegularExpression>::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</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();
+}

+ 7 - 0
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<cmStdString> 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<int> LabelFilter;
+  bool IsFilteredOut(std::string const& source);
 };
 
 #endif