소스 검색

ENH: Several cleanups and improvements

Andy Cedilnik 21 년 전
부모
커밋
c22cc421e0

+ 1 - 0
Source/CMakeLists.txt

@@ -149,6 +149,7 @@ SET(CMTEST_SRCS ctest.cxx cmCTest.cxx
   CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
   CTest/cmCTestRunScriptCommand.cxx
   CTest/cmCTestSleepCommand.cxx
+  CTest/cmCTestMemCheckHandler.cxx
   )
 
 INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Source/CTest)

+ 4 - 4
Source/CTest/cmCTestBuildHandler.cxx

@@ -192,20 +192,20 @@ void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile *mf)
 //----------------------------------------------------------------------
 //clearly it would be nice if this were broken up into a few smaller
 //functions and commented...
-int cmCTestBuildHandler::BuildDirectory()
+int cmCTestBuildHandler::ProcessHandler()
 {
   std::cout << "Build project" << std::endl;
   std::string makeCommand = m_CTest->GetDartConfiguration("MakeCommand");
   if ( makeCommand.size() == 0 )
     {
     std::cerr << "Cannot find MakeCommand key in the DartConfiguration.tcl" << std::endl;
-    return 1;
+    return -1;
     }
   std::string buildDirectory = m_CTest->GetDartConfiguration("BuildDirectory");
   if ( buildDirectory.size() == 0 )
     {
     std::cerr << "Cannot find BuildDirectory  key in the DartConfiguration.tcl" << std::endl;
-    return 1;
+    return -1;
     }
 
   cmGeneratedFileStream ofs;
@@ -438,7 +438,7 @@ int cmCTestBuildHandler::BuildDirectory()
   if( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), "Build.xml", xofs, true) )
     {
     std::cerr << "Cannot create build XML file" << std::endl;
-    return 1;
+    return -1;
     }
   this->GenerateDartBuildOutput(xofs, errorsWarnings, elapsed_build_time);
   return 0;

+ 1 - 1
Source/CTest/cmCTestBuildHandler.h

@@ -37,7 +37,7 @@ public:
   /*
    * The main entry point for this class
    */
-  int BuildDirectory();
+  int ProcessHandler();
   
   cmCTestBuildHandler();
   

+ 4 - 4
Source/CTest/cmCTestConfigureHandler.cxx

@@ -34,7 +34,7 @@ cmCTestConfigureHandler::cmCTestConfigureHandler()
 //----------------------------------------------------------------------
 //clearly it would be nice if this were broken up into a few smaller
 //functions and commented...
-int cmCTestConfigureHandler::ConfigureDirectory()
+int cmCTestConfigureHandler::ProcessHandler()
 {
   std::cout << "Configure project" << std::endl;
   std::string cCommand = m_CTest->GetDartConfiguration("ConfigureCommand");
@@ -42,14 +42,14 @@ int cmCTestConfigureHandler::ConfigureDirectory()
     {
     std::cerr << "Cannot find ConfigureCommand key in the DartConfiguration.tcl" 
               << std::endl;
-    return 1;
+    return -1;
     }
 
   std::string buildDirectory = m_CTest->GetDartConfiguration("BuildDirectory");
   if ( buildDirectory.size() == 0 )
     {
     std::cerr << "Cannot find BuildDirectory  key in the DartConfiguration.tcl" << std::endl;
-    return 1;
+    return -1;
     }
 
   double elapsed_time_start = cmSystemTools::GetTime();
@@ -107,7 +107,7 @@ int cmCTestConfigureHandler::ConfigureDirectory()
   if (! res || retVal )
     {
     std::cerr << "Error(s) when updating the project" << std::endl;
-    return 1;
+    return -1;
     }
   return 0;
 }

+ 1 - 1
Source/CTest/cmCTestConfigureHandler.h

@@ -33,7 +33,7 @@ public:
   /*
    * The main entry point for this class
    */
-  int ConfigureDirectory();
+  int ProcessHandler();
   
   cmCTestConfigureHandler();
 };

+ 9 - 5
Source/CTest/cmCTestCoverageHandler.cxx

@@ -154,7 +154,7 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(const char* file, const char* src
 //----------------------------------------------------------------------
 //clearly it would be nice if this were broken up into a few smaller
 //functions and commented...
-int cmCTestCoverageHandler::CoverageDirectory()
+int cmCTestCoverageHandler::ProcessHandler()
 {
   int error = 0;
 
@@ -330,7 +330,7 @@ int cmCTestCoverageHandler::CoverageDirectory()
       "Coverage.xml", covSumFile, true))
     {
     std::cerr << "Cannot open coverage summary file: Coverage.xml" << std::endl;
-    return 1;
+    return -1;
     }
 
   m_CTest->StartXML(covSumFile);
@@ -341,7 +341,7 @@ int cmCTestCoverageHandler::CoverageDirectory()
   int logFileCount = 0;
   if ( !this->StartLogFile(covLogFile, logFileCount) )
     {
-    return 1;
+    return -1;
     }
   totalCoverageMap::iterator fileIterator;
   int cnt = 0;
@@ -360,7 +360,7 @@ int cmCTestCoverageHandler::CoverageDirectory()
       logFileCount ++;
       if ( !this->StartLogFile(covLogFile, logFileCount) )
         {
-        return 1;
+        return -1;
         }
       }
     const std::string fullFileName = fileIterator->first;
@@ -503,5 +503,9 @@ int cmCTestCoverageHandler::CoverageDirectory()
 
   cmSystemTools::ChangeDirectory(currentDirectory.c_str());
 
-  return error;
+  if ( error )
+    {
+    return -1;
+    }
+  return 0;
 }

+ 1 - 1
Source/CTest/cmCTestCoverageHandler.h

@@ -35,7 +35,7 @@ public:
   /*
    * The main entry point for this class
    */
-  int CoverageDirectory();
+  int ProcessHandler();
   
   cmCTestCoverageHandler();
   

+ 5 - 0
Source/CTest/cmCTestGenericHandler.cxx

@@ -23,3 +23,8 @@ cmCTestGenericHandler::cmCTestGenericHandler()
   m_CTest = 0;
 }
 
+cmCTestGenericHandler::~cmCTestGenericHandler()
+{
+}
+
+

+ 8 - 1
Source/CTest/cmCTestGenericHandler.h

@@ -39,7 +39,13 @@ public:
   /**
    * Populate internals from CTest custom scripts
    */
-  void PopulateCustomVectors(cmMakefile *) {}
+  virtual void PopulateCustomVectors(cmMakefile *) {}
+
+  /**
+   * Do the actual processing. Subclass has to override it.
+   * Return < 0 if error.
+   */
+  virtual int ProcessHandler() = 0;
 
   /**
    * Set the CTest instance
@@ -50,6 +56,7 @@ public:
    * Construct handler
    */
   cmCTestGenericHandler();
+  virtual ~cmCTestGenericHandler();
 
 protected:
   bool m_Verbose;

+ 548 - 0
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -0,0 +1,548 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#include "cmCTestMemCheckHandler.h"
+
+#include "cmCTest.h"
+#include "cmake.h"
+#include "cmGeneratedFileStream.h"
+#include <cmsys/Process.h>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/Base64.h>
+#include "cmMakefile.h"
+
+#include <stdlib.h> 
+#include <math.h>
+#include <float.h>
+
+//----------------------------------------------------------------------
+static const char* cmCTestMemCheckResultStrings[] = {
+  "ABR",
+  "ABW",
+  "ABWL",
+  "COR",
+  "EXU",
+  "FFM",
+  "FIM",
+  "FMM",
+  "FMR",
+  "FMW",
+  "FUM",
+  "IPR",
+  "IPW",
+  "MAF",
+  "MLK",
+  "MPK",
+  "NPR",
+  "ODS",
+  "PAR",
+  "PLK",
+  "UMC",
+  "UMR",
+  0
+};
+
+//----------------------------------------------------------------------
+static const char* cmCTestMemCheckResultLongStrings[] = {
+  "Threading Problem",
+  "ABW",
+  "ABWL",
+  "COR",
+  "EXU",
+  "FFM",
+  "FIM",
+  "Mismatched deallocation",
+  "FMR",
+  "FMW",
+  "FUM",
+  "IPR",
+  "IPW",
+  "MAF",
+  "Memory Leak",
+  "Potential Memory Leak",
+  "NPR",
+  "ODS",
+  "Invalid syscall param",
+  "PLK",
+  "Uninitialized Memory Conditional",
+  "Uninitialized Memory Read",
+  0
+};
+
+
+//----------------------------------------------------------------------
+cmCTestMemCheckHandler::cmCTestMemCheckHandler()
+{
+  m_MemCheck = true;
+}
+
+//----------------------------------------------------------------------
+int cmCTestMemCheckHandler::PreProcessHandler()
+{
+  if ( !this->InitializeMemoryChecking() )
+    {
+    return 0;
+    }
+
+  if ( !this->ExecuteCommands(m_CustomPreMemCheck) )
+    {
+    std::cerr << "Problem executing pre-memcheck command(s)." << std::endl;
+    return 0;
+    }
+  return 1;
+}
+
+//----------------------------------------------------------------------
+int cmCTestMemCheckHandler::PostProcessHandler()
+{
+  if ( !this->ExecuteCommands(m_CustomPostMemCheck) )
+    {
+    std::cerr << "Problem executing post-memcheck command(s)." << std::endl;
+    return 0;
+    }
+  return 1;
+}
+
+//----------------------------------------------------------------------
+void cmCTestMemCheckHandler::GenerateTestCommand(std::vector<const char*>& args)
+{
+  std::vector<cmStdString>::size_type pp;
+  args.push_back(m_MemoryTester.c_str());
+  std::string memcheckcommand = "";
+  memcheckcommand = m_MemoryTester;
+  for ( pp = 0; pp < m_MemoryTesterOptionsParsed.size(); pp ++ )
+    {
+    args.push_back(m_MemoryTesterOptionsParsed[pp].c_str());
+    memcheckcommand += " ";
+    memcheckcommand += cmSystemTools::EscapeSpaces(m_MemoryTesterOptionsParsed[pp].c_str());
+    }
+  if ( m_Verbose )
+    {
+    std::cout << "Memory check command: " << memcheckcommand << std::endl;
+    }
+}
+
+//----------------------------------------------------------------------
+void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
+{
+  this->cmCTestTestHandler::PopulateCustomVectors(mf);
+  cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK", 
+                                m_CustomPreMemCheck);
+  cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK", 
+                                m_CustomPostMemCheck);
+
+  cmCTest::PopulateCustomVector(mf, 
+                             "CTEST_CUSTOM_MEMCHECK_IGNORE", 
+                             m_CustomTestsIgnore);
+}
+
+//----------------------------------------------------------------------
+void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
+{
+  if ( !m_CTest->GetProduceXML() )
+    {
+    return;
+    }
+
+  m_CTest->StartXML(os);
+  os << "<DynamicAnalysis Checker=\"";
+  switch ( m_MemoryTesterStyle )
+    {
+    case cmCTestMemCheckHandler::VALGRIND:
+      os << "Valgrind";
+      break;
+    case cmCTestMemCheckHandler::PURIFY:
+      os << "Purify";
+      break;
+    case cmCTestMemCheckHandler::BOUNDS_CHECKER:
+      os << "BoundsChecker";
+      break;
+    default:
+      os << "Unknown";
+    }
+  os << "\">" << std::endl;
+
+  os << "\t<StartDateTime>" << m_StartTest << "</StartDateTime>\n"
+    << "\t<TestList>\n";
+  tm_TestResultsVector::size_type cc;
+  for ( cc = 0; cc < m_TestResults.size(); cc ++ )
+    {
+    cmCTestTestResult *result = &m_TestResults[cc];
+    std::string testPath = result->m_Path + "/" + result->m_Name;
+    os << "\t\t<Test>" << cmCTest::MakeXMLSafe(
+      m_CTest->GetShortPathToFile(testPath.c_str()))
+      << "</Test>" << std::endl;
+    }
+  os << "\t</TestList>\n";
+  std::cout << "-- Processing memory checking output: ";
+  unsigned int total = m_TestResults.size();
+  unsigned int step = total / 10;
+  unsigned int current = 0;
+  for ( cc = 0; cc < m_TestResults.size(); cc ++ )
+    {
+    cmCTestTestResult *result = &m_TestResults[cc];
+    std::string memcheckstr;
+    int memcheckresults[cmCTestMemCheckHandler::NO_MEMORY_FAULT];
+    int kk;
+    bool res = this->ProcessMemCheckOutput(result->m_Output, memcheckstr, memcheckresults);
+    if ( res && result->m_Status == cmCTestMemCheckHandler::COMPLETED )
+      {
+      continue;
+      }
+    os << "\t<Test Status=\"";
+    if ( result->m_Status == cmCTestMemCheckHandler::COMPLETED )
+      {
+      os << "passed";
+      }
+    else if ( result->m_Status == cmCTestMemCheckHandler::NOT_RUN )
+      {
+      os << "notrun";
+      }
+    else
+      {
+      os << "failed";
+      }
+    std::string testPath = result->m_Path + "/" + result->m_Name;
+    os << "\">\n"
+      << "\t\t<Name>" << cmCTest::MakeXMLSafe(result->m_Name) << "</Name>\n"
+      << "\t\t<Path>" << cmCTest::MakeXMLSafe(
+        m_CTest->GetShortPathToFile(result->m_Path.c_str())) << "</Path>\n"
+      << "\t\t<FullName>" << cmCTest::MakeXMLSafe(
+        m_CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
+      << "\t\t<FullCommandLine>" 
+      << cmCTest::MakeXMLSafe(result->m_FullCommandLine) 
+      << "</FullCommandLine>\n"
+      << "\t\t<Results>" << std::endl;
+    for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
+      {
+      if ( memcheckresults[kk] )
+        {
+        os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk] << "\">"
+           << memcheckresults[kk] 
+           << "</Defect>" << std::endl;
+        }
+      m_MemoryTesterGlobalResults[kk] += memcheckresults[kk];
+      }
+    os 
+      << "\t\t</Results>\n"
+      << "\t<Log>\n" << memcheckstr << std::endl
+      << "\t</Log>\n"
+      << "\t</Test>" << std::endl;
+    if ( current < cc )
+      {
+      std::cout << "#";
+      std::cout.flush();
+      current += step;
+      }
+    }
+  std::cout << std::endl;
+  std::cerr << "Memory checking results:" << std::endl;
+  os << "\t<DefectList>" << std::endl;
+  for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+    {
+    if ( m_MemoryTesterGlobalResults[cc] )
+      {
+      std::cerr.width(35);
+      std::cerr << cmCTestMemCheckResultLongStrings[cc] << " - " 
+        << m_MemoryTesterGlobalResults[cc] << std::endl;
+      os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc] << "\"/>" << std::endl;
+      }
+    }
+  os << "\t</DefectList>" << std::endl;
+
+  os << "\t<EndDateTime>" << m_EndTest << "</EndDateTime>" << std::endl;
+  os << "<ElapsedMinutes>" 
+     << static_cast<int>(m_ElapsedTestingTime/6)/10.0 
+     << "</ElapsedMinutes>\n";
+  
+  os << "</DynamicAnalysis>" << std::endl;
+  m_CTest->EndXML(os);
+
+
+}
+
+//----------------------------------------------------------------------
+bool cmCTestMemCheckHandler::InitializeMemoryChecking()
+{
+  // Setup the command
+  if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("MemoryCheckCommand").c_str()) )
+    {
+    m_MemoryTester 
+      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("MemoryCheckCommand").c_str());
+    }
+  else if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("PurifyCommand").c_str()) )
+    {
+    m_MemoryTester 
+      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("PurifyCommand").c_str());
+    }
+  else if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("ValgrindCommand").c_str()) )
+    {
+    m_MemoryTester 
+      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("ValgrindCommand").c_str());
+    }
+  else
+    {
+    std::cerr << "Memory checker (MemoryCheckCommand) not set, or cannot find the specified program." 
+      << std::endl;
+    return false;
+    }
+
+  if ( m_MemoryTester[0] == '\"' && m_MemoryTester[m_MemoryTester.size()-1] == '\"' )
+    {
+    m_MemoryTester = m_MemoryTester.substr(1, m_MemoryTester.size()-2);
+    }
+
+  // Setup the options
+  if ( m_CTest->GetDartConfiguration("MemoryCheckCommandOptions").size() )
+    {
+    m_MemoryTesterOptions = m_CTest->GetDartConfiguration("MemoryCheckCommandOptions");
+    }
+  else if ( m_CTest->GetDartConfiguration("ValgrindCommandOptions").size() )
+    {
+    m_MemoryTesterOptions = m_CTest->GetDartConfiguration("ValgrindCommandOptions");
+    }
+
+  m_MemoryTesterOutputFile = m_CTest->GetToplevelPath() + "/Testing/Temporary/MemoryChecker.log";
+  m_MemoryTesterOutputFile = cmSystemTools::EscapeSpaces(m_MemoryTesterOutputFile.c_str());
+
+  if ( m_MemoryTester.find("valgrind") != std::string::npos )
+    {
+    m_MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+    if ( !m_MemoryTesterOptions.size() )
+      {
+      m_MemoryTesterOptions = "-q --skin=memcheck --leak-check=yes --show-reachable=yes --workaround-gcc296-bugs=yes --num-callers=100";
+      }
+    if ( m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").size() )
+      {
+      if ( !cmSystemTools::FileExists(m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str()) )
+        {
+        std::cerr << "Cannot find memory checker suppression file: " 
+          << m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str() << std::endl;
+        return false;
+        }
+      m_MemoryTesterOptions += " --suppressions=" + cmSystemTools::EscapeSpaces(m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str()) + "";
+      }
+    }
+  else if ( m_MemoryTester.find("purify") != std::string::npos )
+    {
+    m_MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
+#ifdef _WIN32
+    m_MemoryTesterOptions += " /SAVETEXTDATA=" + m_MemoryTesterOutputFile;
+#else
+    m_MemoryTesterOptions += " -log-file=" + m_MemoryTesterOutputFile;
+#endif
+    }
+  else if ( m_MemoryTester.find("boundschecker") != std::string::npos )
+    {
+    m_MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+    std::cerr << "Bounds checker not yet implemented" << std::endl;
+    return false;
+    }
+  else
+    {
+    std::cerr << "Do not understand memory checker: " << m_MemoryTester.c_str() << std::endl;
+    return false;
+    }
+
+  m_MemoryTesterOptionsParsed = cmSystemTools::ParseArguments(m_MemoryTesterOptions.c_str());
+  std::vector<cmStdString>::size_type cc;
+  for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
+    {
+    m_MemoryTesterGlobalResults[cc] = 0;
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------
+bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str, 
+                                               std::string& log, int* results)
+{
+  std::string::size_type cc;
+  for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
+    {
+    results[cc] = 0;
+    }
+
+  if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
+    {
+    return this->ProcessMemCheckValgrindOutput(str, log, results);
+    }
+  else if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY )
+    {
+    return this->ProcessMemCheckPurifyOutput(str, log, results);
+    }
+  else if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER )
+    {
+    log.append("\nMemory checking style used was: ");
+    log.append("Bounds Checker");
+    }
+  else
+    {
+    log.append("\nMemory checking style used was: ");
+    log.append("None that I know");
+    log = str;
+    }
+
+
+  return true;
+}
+
+//----------------------------------------------------------------------
+bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
+  const std::string&, std::string& log, 
+  int* results)
+{
+  if ( !cmSystemTools::FileExists(m_MemoryTesterOutputFile.c_str()) )
+    {
+    log = "Cannot find Purify output file: " + m_MemoryTesterOutputFile;
+    std::cerr << log.c_str() << std::endl;
+    return false;
+    }
+
+  std::ifstream ifs(m_MemoryTesterOutputFile.c_str());
+  if ( !ifs )
+    {
+    log = "Cannot read Purify output file: " + m_MemoryTesterOutputFile;
+    std::cerr << log.c_str() << std::endl;
+    return false;
+    }
+
+  cmOStringStream ostr;
+  log = "";
+
+  cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
+
+  int defects = 0;
+
+  std::string line;
+  while ( cmSystemTools::GetLineFromStream(ifs, line) )
+    {
+    int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
+    if ( pfW.find(line) )
+      {
+      int cc;
+      for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
+        {
+        if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
+          {
+          failure = cc;
+          break;
+          }
+        }
+      if ( cc == cmCTestMemCheckHandler::NO_MEMORY_FAULT )
+        {
+        std::cerr<< "Unknown Purify memory fault: " << pfW.match(1) << std::endl;
+        ostr << "*** Unknown Purify memory fault: " << pfW.match(1) << std::endl;
+        }
+      }
+    if ( failure != NO_MEMORY_FAULT )
+      {
+      ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
+      results[failure] ++;
+      defects ++;
+      }
+    ostr << cmCTest::MakeXMLSafe(line) << std::endl;
+    }
+
+  log = ostr.str();
+  if ( defects )
+    {
+    return false;
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------
+bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
+  const std::string& str, std::string& log, 
+  int* results)
+{
+  std::vector<cmStdString> lines;
+  cmSystemTools::Split(str.c_str(), lines);
+ 
+  std::string::size_type cc;
+
+  cmOStringStream ostr;
+  log = "";
+
+  int defects = 0;
+
+  cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
+
+  cmsys::RegularExpression vgFIM(
+    "== .*Invalid free\\(\\) / delete / delete\\[\\]");
+  cmsys::RegularExpression vgFMM(
+    "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
+  cmsys::RegularExpression vgMLK(
+    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are definitely lost"
+    " in loss record [0-9][0-9]* of [0-9]");
+  cmsys::RegularExpression vgPAR(
+    "== .*Syscall param .* contains unaddressable byte\\(s\\)");
+  cmsys::RegularExpression vgMPK1(
+    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are possibly lost in"
+    " loss record [0-9][0-9]* of [0-9]");
+  cmsys::RegularExpression vgMPK2(
+    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are still reachable"
+    " in loss record [0-9][0-9]* of [0-9]");
+  cmsys::RegularExpression vgUMC(
+    "== .*Conditional jump or move depends on uninitialised value\\(s\\)");
+  cmsys::RegularExpression vgUMR1("== .*Use of uninitialised value of size [0-9][0-9]*");
+  cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9][0-9]*");
+  cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
+  cmsys::RegularExpression vgUMR4(
+    "== .*Syscall param .* contains uninitialised or unaddressable byte\\(s\\)");
+  cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9]");
+  cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is locked by a different thread");
+
+  //double sttime = cmSystemTools::GetTime();
+  //std::cout << "Start test: " << lines.size() << std::endl;
+  for ( cc = 0; cc < lines.size(); cc ++ )
+    {
+    if ( valgrindLine.find(lines[cc]) )
+      {
+      int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
+      if ( vgFIM.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::FIM; }
+      else if ( vgFMM.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::FMM; }
+      else if ( vgMLK.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::MLK; }
+      else if ( vgPAR.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::PAR; }
+      else if ( vgMPK1.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::MPK; }
+      else if ( vgMPK2.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::MPK; }
+      else if ( vgUMC.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::UMC; }
+      else if ( vgUMR1.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
+      else if ( vgUMR2.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
+      else if ( vgUMR3.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
+      else if ( vgUMR4.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
+      else if ( vgIPW.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::IPW; }
+      else if ( vgABR.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::ABR; }
+
+      if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
+        {
+        ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
+        results[failure] ++;
+        defects ++;
+        }
+      ostr << cmCTest::MakeXMLSafe(lines[cc]) << std::endl;
+      }
+    }
+  //std::cout << "End test (elapsed: " << (cmSystemTools::GetTime() - sttime) << std::endl;
+  log = ostr.str();
+  if ( defects )
+    {
+    return false;
+    }
+  return true;
+}

+ 122 - 0
Source/CTest/cmCTestMemCheckHandler.h

@@ -0,0 +1,122 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc. All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even 
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+
+#ifndef cmCTestMemCheckHandler_h
+#define cmCTestMemCheckHandler_h
+
+
+#include "cmCTestTestHandler.h"
+#include "cmListFileCache.h"
+
+class cmMakefile;
+
+/** \class cmCTestMemCheckHandler
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestMemCheckHandler : public cmCTestTestHandler
+{
+public:
+  void PopulateCustomVectors(cmMakefile *mf);
+  
+  cmCTestMemCheckHandler();
+
+protected:
+  virtual int PreProcessHandler();
+  virtual int PostProcessHandler();
+  virtual void GenerateTestCommand(std::vector<const char*>& args);
+
+private:
+
+  enum { // Memory checkers
+    UNKNOWN = 0,
+    VALGRIND,
+    PURIFY,
+    BOUNDS_CHECKER
+  };
+
+  enum { // Memory faults
+    ABR = 0,
+    ABW,
+    ABWL,
+    COR,
+    EXU,
+    FFM,
+    FIM,
+    FMM,
+    FMR,
+    FMW,
+    FUM,
+    IPR,
+    IPW,
+    MAF,
+    MLK,
+    MPK,
+    NPR,
+    ODS,
+    PAR,
+    PLK,
+    UMC,
+    UMR,
+    NO_MEMORY_FAULT
+  };
+  
+  enum { // Program statuses
+    NOT_RUN = 0,
+    TIMEOUT,
+    SEGFAULT,
+    ILLEGAL,
+    INTERRUPT,
+    NUMERICAL,
+    OTHER_FAULT,
+    FAILED,
+    BAD_COMMAND,
+    COMPLETED
+  };
+
+  std::string              m_MemoryTester;
+  std::vector<cmStdString> m_MemoryTesterOptionsParsed;
+  std::string              m_MemoryTesterOptions;
+  int                      m_MemoryTesterStyle;
+  std::string              m_MemoryTesterOutputFile;
+  int                      m_MemoryTesterGlobalResults[NO_MEMORY_FAULT];
+
+  ///! Initialize memory checking subsystem.
+  bool InitializeMemoryChecking();
+
+  /**
+   * Generate the Dart compatible output
+   */
+  void GenerateDartOutput(std::ostream& os);
+
+  std::vector<cmStdString> m_CustomPreMemCheck;
+  std::vector<cmStdString> m_CustomPostMemCheck;
+
+  //! Parse Valgrind/Purify/Bounds Checker result out of the output
+  //string. After running, log holds the output and results hold the
+  //different memmory errors.
+  bool ProcessMemCheckOutput(const std::string& str, 
+                             std::string& log, int* results);
+  bool ProcessMemCheckValgrindOutput(const std::string& str, 
+                                     std::string& log, int* results);
+  bool ProcessMemCheckPurifyOutput(const std::string& str, 
+                                   std::string& log, int* results);
+
+};
+
+#endif
+

+ 7 - 3
Source/CTest/cmCTestScriptHandler.cxx

@@ -124,7 +124,7 @@ void cmCTestScriptHandler::AddConfigurationScript(const char *script)
 //----------------------------------------------------------------------
 // the generic entry point for handling scripts, this routine will run all
 // the scripts provides a -S arguments
-int cmCTestScriptHandler::RunConfigurationScript()
+int cmCTestScriptHandler::ProcessHandler()
 {
   int res = 0;
   std::vector<cmStdString>::iterator it;
@@ -136,7 +136,11 @@ int cmCTestScriptHandler::RunConfigurationScript()
     res += this->RunConfigurationScript(
       cmSystemTools::CollapseFullPath(it->c_str()));
     }
-  return res;
+  if ( res )
+    {
+    return -1;
+    }
+  return 0;
 }
 
 void cmCTestScriptHandler::UpdateElapsedTime()
@@ -761,7 +765,7 @@ bool cmCTestScriptHandler::RunScript(cmCTest* ctest, const char *sname)
   cmCTestScriptHandler* sh = new cmCTestScriptHandler();
   sh->SetCTestInstance(ctest);
   sh->AddConfigurationScript(sname);
-  sh->RunConfigurationScript();
+  sh->ProcessHandler();
   delete sh;
   return true;
 }

+ 2 - 2
Source/CTest/cmCTestScriptHandler.h

@@ -70,11 +70,11 @@ public:
    * Add a script to run
    */
   void AddConfigurationScript(const char *);
-  
+
   /**
    * Run a dashboard using a specified confiuration script
    */
-  int RunConfigurationScript();
+  int ProcessHandler();
 
   /*
    * Run a script

+ 69 - 529
Source/CTest/cmCTestTestHandler.cxx

@@ -29,59 +29,7 @@
 #include <math.h>
 #include <float.h>
 
-static const char* cmCTestMemCheckResultStrings[] = {
-  "ABR",
-  "ABW",
-  "ABWL",
-  "COR",
-  "EXU",
-  "FFM",
-  "FIM",
-  "FMM",
-  "FMR",
-  "FMW",
-  "FUM",
-  "IPR",
-  "IPW",
-  "MAF",
-  "MLK",
-  "MPK",
-  "NPR",
-  "ODS",
-  "PAR",
-  "PLK",
-  "UMC",
-  "UMR",
-  0
-};
-
-static const char* cmCTestMemCheckResultLongStrings[] = {
-  "Threading Problem",
-  "ABW",
-  "ABWL",
-  "COR",
-  "EXU",
-  "FFM",
-  "FIM",
-  "Mismatched deallocation",
-  "FMR",
-  "FMW",
-  "FUM",
-  "IPR",
-  "IPW",
-  "MAF",
-  "Memory Leak",
-  "Potential Memory Leak",
-  "NPR",
-  "ODS",
-  "Invalid syscall param",
-  "PLK",
-  "Uninitialized Memory Conditional",
-  "Uninitialized Memory Read",
-  0
-};
-
-
+//----------------------------------------------------------------------
 bool TryExecutable(const char *dir, const char *file,
                    std::string *fullPath, const char *subdir)
 {
@@ -114,6 +62,7 @@ bool TryExecutable(const char *dir, const char *file,
   return false;
 }
 
+//----------------------------------------------------------------------
 // get the next number in a string with numbers separated by ,
 // pos is the start of the search and pos2 is the end of the search
 // pos becomes pos2 after a call to GetNextNumber.   
@@ -151,6 +100,7 @@ inline int GetNextNumber(std::string const& in,
     }
 }
 
+//----------------------------------------------------------------------
 // get the next number in a string with numbers separated by ,
 // pos is the start of the search and pos2 is the end of the search
 // pos becomes pos2 after a call to GetNextNumber.   
@@ -200,6 +150,8 @@ cmCTestTestHandler::cmCTestTestHandler()
 
   m_CustomMaximumPassedTestOutputSize = 1 * 1024;
   m_CustomMaximumFailedTestOutputSize = 300 * 1024;
+  
+  m_MemCheck = false;
 }
 
 //----------------------------------------------------------------------
@@ -209,17 +161,9 @@ void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
                                 m_CustomPreTest);
   cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_POST_TEST", 
                                 m_CustomPostTest);
-  cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK", 
-                                m_CustomPreMemCheck);
-  cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK", 
-                                m_CustomPostMemCheck);
-
   cmCTest::PopulateCustomVector(mf,
                              "CTEST_CUSTOM_TESTS_IGNORE", 
                              m_CustomTestsIgnore);
-  cmCTest::PopulateCustomVector(mf, 
-                             "CTEST_CUSTOM_MEMCHECK_IGNORE", 
-                             m_CustomMemCheckIgnore);
   cmCTest::PopulateCustomInteger(mf, 
                              "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE", 
                              m_CustomMaximumPassedTestOutputSize);
@@ -228,44 +172,46 @@ void cmCTestTestHandler::PopulateCustomVectors(cmMakefile *mf)
                              m_CustomMaximumFailedTestOutputSize);
 }
 
-
 //----------------------------------------------------------------------
-//clearly it would be nice if this were broken up into a few smaller
-//functions and commented...
-int cmCTestTestHandler::TestDirectory(bool memcheck)
+int cmCTestTestHandler::PreProcessHandler()
 {
-  m_TestResults.clear();
-  std::cout << (memcheck ? "Memory check" : "Test") << " project" << std::endl;
-  if ( memcheck )
+  if ( !this->ExecuteCommands(m_CustomPreTest) )
     {
-    if ( !this->InitializeMemoryChecking() )
-      {
-      return 1;
-      }
+    std::cerr << "Problem executing pre-test command(s)." << std::endl;
+    return 0;
     }
+  return 1;
+}
 
-  if ( memcheck )
+//----------------------------------------------------------------------
+int cmCTestTestHandler::PostProcessHandler()
+{
+  if ( !this->ExecuteCommands(m_CustomPostTest) )
     {
-    if ( !this->ExecuteCommands(m_CustomPreMemCheck) )
-      {
-      std::cerr << "Problem executing pre-memcheck command(s)." << std::endl;
-      return 1;
-      }
+    std::cerr << "Problem executing post-test command(s)." << std::endl;
+    return 0;
     }
-  else
+  return 1;
+}
+
+//----------------------------------------------------------------------
+//clearly it would be nice if this were broken up into a few smaller
+//functions and commented...
+int cmCTestTestHandler::ProcessHandler()
+{
+  m_TestResults.clear();
+
+  std::cout << (m_MemCheck ? "Memory check" : "Test") << " project" << std::endl;
+  if ( ! this->PreProcessHandler() )
     {
-    if ( !this->ExecuteCommands(m_CustomPreTest) )
-      {
-      std::cerr << "Problem executing pre-test command(s)." << std::endl;
-      return 1;
-      }
+    return -1;
     }
 
   std::vector<cmStdString> passed;
   std::vector<cmStdString> failed;
   int total;
 
-  this->ProcessDirectory(passed, failed, memcheck);
+  this->ProcessDirectory(passed, failed);
 
   total = int(passed.size()) + int(failed.size());
 
@@ -323,57 +269,42 @@ int cmCTestTestHandler::TestDirectory(bool memcheck)
     {
     cmGeneratedFileStream xmlfile;
     if( !m_CTest->OpenOutputFile(m_CTest->GetCurrentTag(), 
-        (memcheck ? "DynamicAnalysis.xml" : "Test.xml"), xmlfile, true) )
+        (m_MemCheck ? "DynamicAnalysis.xml" : "Test.xml"), xmlfile, true) )
       {
-      std::cerr << "Cannot create " << (memcheck ? "memory check" : "testing")
+      std::cerr << "Cannot create " << (m_MemCheck ? "memory check" : "testing")
         << " XML file" << std::endl;
       return 1;
       }
-    if ( memcheck )
-      {
-      this->GenerateDartMemCheckOutput(xmlfile);
-      }
-    else
-      {
-      this->GenerateDartTestOutput(xmlfile);
-      }
+    this->GenerateDartOutput(xmlfile);
     }
 
-  if ( memcheck )
+  if ( ! this->PostProcessHandler() )
     {
-    if ( !this->ExecuteCommands(m_CustomPostMemCheck) )
-      {
-      std::cerr << "Problem executing post-memcheck command(s)." << std::endl;
-      return 1;
-      }
+    return -1;
     }
-  else
+
+  if ( !failed.empty() )
     {
-    if ( !this->ExecuteCommands(m_CustomPostTest) )
-      {
-      std::cerr << "Problem executing post-test command(s)." << std::endl;
-      return 1;
-      }
+    return -1;
     }
-
-  return int(failed.size());
+  return 0;
 }
 
+//----------------------------------------------------------------------
 void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed, 
-                                          std::vector<cmStdString> &failed,
-                                          bool memcheck)
+                                          std::vector<cmStdString> &failed)
 {
   std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
   cmsys::RegularExpression dartStuff("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)");
   tm_ListOfTests testlist;
-  this->GetListOfTests(&testlist, memcheck);
+  this->GetListOfTests(&testlist);
   tm_ListOfTests::size_type tmsize = testlist.size();
 
   cmGeneratedFileStream ofs;
   cmGeneratedFileStream *olog = 0;
   if ( !m_CTest->GetShowOnly() && tmsize > 0 && 
     m_CTest->OpenOutputFile("Temporary", 
-      (memcheck?"LastMemCheck.log":"LastTest.log"), ofs) )
+      (m_MemCheck?"LastMemCheck.log":"LastTest.log"), ofs) )
     {
     olog = &ofs;
     }
@@ -479,7 +410,6 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
     // find the test executable
     std::string actualCommand = this->FindTheExecutable(args[1].Value.c_str());
     std::string testCommand = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
-    std::string memcheckcommand = "";
 
     // continue if we did not find the executable
     if (testCommand == "")
@@ -500,18 +430,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
     ++j;
     ++j;
     std::vector<const char*> arguments;
-    if ( memcheck )
-      {
-      std::vector<cmStdString>::size_type pp;
-      arguments.push_back(m_MemoryTester.c_str());
-      memcheckcommand = m_MemoryTester;
-      for ( pp = 0; pp < m_MemoryTesterOptionsParsed.size(); pp ++ )
-        {
-        arguments.push_back(m_MemoryTesterOptionsParsed[pp].c_str());
-        memcheckcommand += " ";
-        memcheckcommand += cmSystemTools::EscapeSpaces(m_MemoryTesterOptionsParsed[pp].c_str());
-        }
-      }
+    this->GenerateTestCommand(arguments);
     arguments.push_back(actualCommand.c_str());
     for(;j != args.end(); ++j)
       {
@@ -530,11 +449,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
 
     if ( m_Verbose )
       {
-      std::cout << std::endl << (memcheck?"MemCheck":"Test") << " command: " << testCommand << std::endl;
-      if ( memcheck )
-        {
-        std::cout << "Memory check command: " << memcheckcommand << std::endl;
-        }
+      std::cout << std::endl << (m_MemCheck?"MemCheck":"Test") << " command: " << testCommand << std::endl;
       }
     if ( olog )
       {
@@ -677,131 +592,13 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
   cmSystemTools::ChangeDirectory(current_dir.c_str());
 }
 
-void cmCTestTestHandler::GenerateDartMemCheckOutput(std::ostream& os)
+//----------------------------------------------------------------------
+void cmCTestTestHandler::GenerateTestCommand(std::vector<const char*>&)
 {
-  if ( !m_CTest->GetProduceXML() )
-    {
-    return;
-    }
-
-  m_CTest->StartXML(os);
-  os << "<DynamicAnalysis Checker=\"";
-  switch ( m_MemoryTesterStyle )
-    {
-    case cmCTestTestHandler::VALGRIND:
-      os << "Valgrind";
-      break;
-    case cmCTestTestHandler::PURIFY:
-      os << "Purify";
-      break;
-    case cmCTestTestHandler::BOUNDS_CHECKER:
-      os << "BoundsChecker";
-      break;
-    default:
-      os << "Unknown";
-    }
-  os << "\">" << std::endl;
-
-  os << "\t<StartDateTime>" << m_StartTest << "</StartDateTime>\n"
-    << "\t<TestList>\n";
-  tm_TestResultsVector::size_type cc;
-  for ( cc = 0; cc < m_TestResults.size(); cc ++ )
-    {
-    cmCTestTestResult *result = &m_TestResults[cc];
-    std::string testPath = result->m_Path + "/" + result->m_Name;
-    os << "\t\t<Test>" << cmCTest::MakeXMLSafe(
-      m_CTest->GetShortPathToFile(testPath.c_str()))
-      << "</Test>" << std::endl;
-    }
-  os << "\t</TestList>\n";
-  std::cout << "-- Processing memory checking output: ";
-  unsigned int total = m_TestResults.size();
-  unsigned int step = total / 10;
-  unsigned int current = 0;
-  for ( cc = 0; cc < m_TestResults.size(); cc ++ )
-    {
-    cmCTestTestResult *result = &m_TestResults[cc];
-    std::string memcheckstr;
-    int memcheckresults[cmCTestTestHandler::NO_MEMORY_FAULT];
-    int kk;
-    bool res = this->ProcessMemCheckOutput(result->m_Output, memcheckstr, memcheckresults);
-    if ( res && result->m_Status == cmCTestTestHandler::COMPLETED )
-      {
-      continue;
-      }
-    os << "\t<Test Status=\"";
-    if ( result->m_Status == cmCTestTestHandler::COMPLETED )
-      {
-      os << "passed";
-      }
-    else if ( result->m_Status == cmCTestTestHandler::NOT_RUN )
-      {
-      os << "notrun";
-      }
-    else
-      {
-      os << "failed";
-      }
-    std::string testPath = result->m_Path + "/" + result->m_Name;
-    os << "\">\n"
-      << "\t\t<Name>" << cmCTest::MakeXMLSafe(result->m_Name) << "</Name>\n"
-      << "\t\t<Path>" << cmCTest::MakeXMLSafe(
-        m_CTest->GetShortPathToFile(result->m_Path.c_str())) << "</Path>\n"
-      << "\t\t<FullName>" << cmCTest::MakeXMLSafe(
-        m_CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
-      << "\t\t<FullCommandLine>" 
-      << cmCTest::MakeXMLSafe(result->m_FullCommandLine) 
-      << "</FullCommandLine>\n"
-      << "\t\t<Results>" << std::endl;
-    for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
-      {
-      if ( memcheckresults[kk] )
-        {
-        os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk] << "\">"
-           << memcheckresults[kk] 
-           << "</Defect>" << std::endl;
-        }
-      m_MemoryTesterGlobalResults[kk] += memcheckresults[kk];
-      }
-    os 
-      << "\t\t</Results>\n"
-      << "\t<Log>\n" << memcheckstr << std::endl
-      << "\t</Log>\n"
-      << "\t</Test>" << std::endl;
-    if ( current < cc )
-      {
-      std::cout << "#";
-      std::cout.flush();
-      current += step;
-      }
-    }
-  std::cout << std::endl;
-  std::cerr << "Memory checking results:" << std::endl;
-  os << "\t<DefectList>" << std::endl;
-  for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
-    {
-    if ( m_MemoryTesterGlobalResults[cc] )
-      {
-      std::cerr.width(35);
-      std::cerr << cmCTestMemCheckResultLongStrings[cc] << " - " 
-        << m_MemoryTesterGlobalResults[cc] << std::endl;
-      os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc] << "\"/>" << std::endl;
-      }
-    }
-  os << "\t</DefectList>" << std::endl;
-
-  os << "\t<EndDateTime>" << m_EndTest << "</EndDateTime>" << std::endl;
-  os << "<ElapsedMinutes>" 
-     << static_cast<int>(m_ElapsedTestingTime/6)/10.0 
-     << "</ElapsedMinutes>\n";
-  
-  os << "</DynamicAnalysis>" << std::endl;
-  m_CTest->EndXML(os);
-
-
 }
 
-void cmCTestTestHandler::GenerateDartTestOutput(std::ostream& os)
+//----------------------------------------------------------------------
+void cmCTestTestHandler::GenerateDartOutput(std::ostream& os)
 {
   if ( !m_CTest->GetProduceXML() )
     {
@@ -886,97 +683,7 @@ void cmCTestTestHandler::GenerateDartTestOutput(std::ostream& os)
   m_CTest->EndXML(os);
 }
 
-bool cmCTestTestHandler::InitializeMemoryChecking()
-{
-  // Setup the command
-  if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("MemoryCheckCommand").c_str()) )
-    {
-    m_MemoryTester 
-      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("MemoryCheckCommand").c_str());
-    }
-  else if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("PurifyCommand").c_str()) )
-    {
-    m_MemoryTester 
-      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("PurifyCommand").c_str());
-    }
-  else if ( cmSystemTools::FileExists(m_CTest->GetDartConfiguration("ValgrindCommand").c_str()) )
-    {
-    m_MemoryTester 
-      = cmSystemTools::ConvertToOutputPath(m_CTest->GetDartConfiguration("ValgrindCommand").c_str());
-    }
-  else
-    {
-    std::cerr << "Memory checker (MemoryCheckCommand) not set, or cannot find the specified program." 
-      << std::endl;
-    return false;
-    }
-
-  if ( m_MemoryTester[0] == '\"' && m_MemoryTester[m_MemoryTester.size()-1] == '\"' )
-    {
-    m_MemoryTester = m_MemoryTester.substr(1, m_MemoryTester.size()-2);
-    }
-
-  // Setup the options
-  if ( m_CTest->GetDartConfiguration("MemoryCheckCommandOptions").size() )
-    {
-    m_MemoryTesterOptions = m_CTest->GetDartConfiguration("MemoryCheckCommandOptions");
-    }
-  else if ( m_CTest->GetDartConfiguration("ValgrindCommandOptions").size() )
-    {
-    m_MemoryTesterOptions = m_CTest->GetDartConfiguration("ValgrindCommandOptions");
-    }
-
-  m_MemoryTesterOutputFile = m_CTest->GetToplevelPath() + "/Testing/Temporary/MemoryChecker.log";
-  m_MemoryTesterOutputFile = cmSystemTools::EscapeSpaces(m_MemoryTesterOutputFile.c_str());
-
-  if ( m_MemoryTester.find("valgrind") != std::string::npos )
-    {
-    m_MemoryTesterStyle = cmCTestTestHandler::VALGRIND;
-    if ( !m_MemoryTesterOptions.size() )
-      {
-      m_MemoryTesterOptions = "-q --skin=memcheck --leak-check=yes --show-reachable=yes --workaround-gcc296-bugs=yes --num-callers=100";
-      }
-    if ( m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").size() )
-      {
-      if ( !cmSystemTools::FileExists(m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str()) )
-        {
-        std::cerr << "Cannot find memory checker suppression file: " 
-          << m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str() << std::endl;
-        return false;
-        }
-      m_MemoryTesterOptions += " --suppressions=" + cmSystemTools::EscapeSpaces(m_CTest->GetDartConfiguration("MemoryCheckSuppressionFile").c_str()) + "";
-      }
-    }
-  else if ( m_MemoryTester.find("purify") != std::string::npos )
-    {
-    m_MemoryTesterStyle = cmCTestTestHandler::PURIFY;
-#ifdef _WIN32
-    m_MemoryTesterOptions += " /SAVETEXTDATA=" + m_MemoryTesterOutputFile;
-#else
-    m_MemoryTesterOptions += " -log-file=" + m_MemoryTesterOutputFile;
-#endif
-    }
-  else if ( m_MemoryTester.find("boundschecker") != std::string::npos )
-    {
-    m_MemoryTesterStyle = cmCTestTestHandler::BOUNDS_CHECKER;
-    std::cerr << "Bounds checker not yet implemented" << std::endl;
-    return false;
-    }
-  else
-    {
-    std::cerr << "Do not understand memory checker: " << m_MemoryTester.c_str() << std::endl;
-    return false;
-    }
-
-  m_MemoryTesterOptionsParsed = cmSystemTools::ParseArguments(m_MemoryTesterOptions.c_str());
-  std::vector<cmStdString>::size_type cc;
-  for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
-    {
-    m_MemoryTesterGlobalResults[cc] = 0;
-    }
-  return true;
-}
-
+//----------------------------------------------------------------------
 int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
 {
   std::vector<cmStdString>::iterator it;
@@ -998,6 +705,7 @@ int cmCTestTestHandler::ExecuteCommands(std::vector<cmStdString>& vec)
 }
 
 
+//----------------------------------------------------------------------
 std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
 {
   std::string fullPath = "";
@@ -1070,8 +778,8 @@ std::string cmCTestTestHandler::FindTheExecutable(const char *exe)
 }
 
 
-void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist, 
-                                        bool memcheck)
+//----------------------------------------------------------------------
+void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist)
 {
   // does the DartTestfile.txt exist ?
   if(!cmSystemTools::FileExists("DartTestfile.txt"))
@@ -1108,7 +816,7 @@ void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist,
         if (cmSystemTools::FileIsDirectory(nwd.c_str()))
           {
           cmSystemTools::ChangeDirectory(nwd.c_str());
-          this->GetListOfTests(testlist, memcheck);
+          this->GetListOfTests(testlist);
           }
         }
       // return to the original directory
@@ -1124,12 +832,12 @@ void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist,
         {
         continue;
         }
-      if ( memcheck )
+      if ( m_MemCheck )
         {
         std::vector<cmStdString>::iterator it;
         bool found = false;
-        for ( it = m_CustomMemCheckIgnore.begin(); 
-          it != m_CustomMemCheckIgnore.end(); ++ it )
+        for ( it = m_CustomTestsIgnore.begin(); 
+          it != m_CustomTestsIgnore.end(); ++ it )
           {
           if ( *it == testname )
             {
@@ -1189,18 +897,20 @@ void cmCTestTestHandler::GetListOfTests(tm_ListOfTests* testlist,
     }
 }
 
-
+//----------------------------------------------------------------------
 void cmCTestTestHandler::UseIncludeRegExp()
 {
   this->m_UseIncludeRegExp = true;  
 }
 
+//----------------------------------------------------------------------
 void cmCTestTestHandler::UseExcludeRegExp()
 {
   this->m_UseExcludeRegExp = true;
   this->m_UseExcludeRegExpFirst = this->m_UseIncludeRegExp ? false : true;
 }
   
+//----------------------------------------------------------------------
 const char* cmCTestTestHandler::GetTestStatus(int status)
 {
   static const char statuses[][100] = {
@@ -1224,6 +934,7 @@ const char* cmCTestTestHandler::GetTestStatus(int status)
   return statuses[status];
 }
 
+//----------------------------------------------------------------------
 void cmCTestTestHandler::ExpandTestsToRunInformation(int numTests)
 {
   if (this->TestsToRunString.empty())
@@ -1293,8 +1004,10 @@ void cmCTestTestHandler::ExpandTestsToRunInformation(int numTests)
   m_TestsToRun.erase(new_end, m_TestsToRun.end());
 }
 
+//----------------------------------------------------------------------
+// Just for convenience
 #define SPACE_REGEX "[ \t\r\n]"
-
+//----------------------------------------------------------------------
 std::string cmCTestTestHandler::GenerateRegressionImages(
   const std::string& xml)
 {
@@ -1453,193 +1166,19 @@ std::string cmCTestTestHandler::GenerateRegressionImages(
   return ostr.str();
 }
 
-bool cmCTestTestHandler::ProcessMemCheckOutput(const std::string& str, 
-                                               std::string& log, int* results)
-{
-  std::string::size_type cc;
-  for ( cc = 0; cc < cmCTestTestHandler::NO_MEMORY_FAULT; cc ++ )
-    {
-    results[cc] = 0;
-    }
-
-  if ( m_MemoryTesterStyle == cmCTestTestHandler::VALGRIND )
-    {
-    return this->ProcessMemCheckValgrindOutput(str, log, results);
-    }
-  else if ( m_MemoryTesterStyle == cmCTestTestHandler::PURIFY )
-    {
-    return this->ProcessMemCheckPurifyOutput(str, log, results);
-    }
-  else if ( m_MemoryTesterStyle == cmCTestTestHandler::BOUNDS_CHECKER )
-    {
-    log.append("\nMemory checking style used was: ");
-    log.append("Bounds Checker");
-    }
-  else
-    {
-    log.append("\nMemory checking style used was: ");
-    log.append("None that I know");
-    log = str;
-    }
-
-
-  return true;
-}
-
-bool cmCTestTestHandler::ProcessMemCheckPurifyOutput(
-  const std::string&, std::string& log, 
-  int* results)
-{
-  if ( !cmSystemTools::FileExists(m_MemoryTesterOutputFile.c_str()) )
-    {
-    log = "Cannot find Purify output file: " + m_MemoryTesterOutputFile;
-    std::cerr << log.c_str() << std::endl;
-    return false;
-    }
-
-  std::ifstream ifs(m_MemoryTesterOutputFile.c_str());
-  if ( !ifs )
-    {
-    log = "Cannot read Purify output file: " + m_MemoryTesterOutputFile;
-    std::cerr << log.c_str() << std::endl;
-    return false;
-    }
-
-  cmOStringStream ostr;
-  log = "";
-
-  cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
-
-  int defects = 0;
-
-  std::string line;
-  while ( cmSystemTools::GetLineFromStream(ifs, line) )
-    {
-    int failure = cmCTestTestHandler::NO_MEMORY_FAULT;
-    if ( pfW.find(line) )
-      {
-      int cc;
-      for ( cc = 0; cc < cmCTestTestHandler::NO_MEMORY_FAULT; cc ++ )
-        {
-        if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
-          {
-          failure = cc;
-          break;
-          }
-        }
-      if ( cc == cmCTestTestHandler::NO_MEMORY_FAULT )
-        {
-        std::cerr<< "Unknown Purify memory fault: " << pfW.match(1) << std::endl;
-        ostr << "*** Unknown Purify memory fault: " << pfW.match(1) << std::endl;
-        }
-      }
-    if ( failure != NO_MEMORY_FAULT )
-      {
-      ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
-      results[failure] ++;
-      defects ++;
-      }
-    ostr << cmCTest::MakeXMLSafe(line) << std::endl;
-    }
-
-  log = ostr.str();
-  if ( defects )
-    {
-    return false;
-    }
-  return true;
-}
-
-bool cmCTestTestHandler::ProcessMemCheckValgrindOutput(
-  const std::string& str, std::string& log, 
-  int* results)
-{
-  std::vector<cmStdString> lines;
-  cmSystemTools::Split(str.c_str(), lines);
- 
-  std::string::size_type cc;
-
-  cmOStringStream ostr;
-  log = "";
-
-  int defects = 0;
-
-  cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
-
-  cmsys::RegularExpression vgFIM(
-    "== .*Invalid free\\(\\) / delete / delete\\[\\]");
-  cmsys::RegularExpression vgFMM(
-    "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
-  cmsys::RegularExpression vgMLK(
-    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are definitely lost"
-    " in loss record [0-9][0-9]* of [0-9]");
-  cmsys::RegularExpression vgPAR(
-    "== .*Syscall param .* contains unaddressable byte\\(s\\)");
-  cmsys::RegularExpression vgMPK1(
-    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are possibly lost in"
-    " loss record [0-9][0-9]* of [0-9]");
-  cmsys::RegularExpression vgMPK2(
-    "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are still reachable"
-    " in loss record [0-9][0-9]* of [0-9]");
-  cmsys::RegularExpression vgUMC(
-    "== .*Conditional jump or move depends on uninitialised value\\(s\\)");
-  cmsys::RegularExpression vgUMR1("== .*Use of uninitialised value of size [0-9][0-9]*");
-  cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9][0-9]*");
-  cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
-  cmsys::RegularExpression vgUMR4(
-    "== .*Syscall param .* contains uninitialised or unaddressable byte\\(s\\)");
-  cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9]");
-  cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is locked by a different thread");
-
-  //double sttime = cmSystemTools::GetTime();
-  //std::cout << "Start test: " << lines.size() << std::endl;
-  for ( cc = 0; cc < lines.size(); cc ++ )
-    {
-    if ( valgrindLine.find(lines[cc]) )
-      {
-      int failure = cmCTestTestHandler::NO_MEMORY_FAULT;
-      if ( vgFIM.find(lines[cc]) ) { failure = cmCTestTestHandler::FIM; }
-      else if ( vgFMM.find(lines[cc]) ) { failure = cmCTestTestHandler::FMM; }
-      else if ( vgMLK.find(lines[cc]) ) { failure = cmCTestTestHandler::MLK; }
-      else if ( vgPAR.find(lines[cc]) ) { failure = cmCTestTestHandler::PAR; }
-      else if ( vgMPK1.find(lines[cc]) ){ failure = cmCTestTestHandler::MPK; }
-      else if ( vgMPK2.find(lines[cc]) ){ failure = cmCTestTestHandler::MPK; }
-      else if ( vgUMC.find(lines[cc]) ) { failure = cmCTestTestHandler::UMC; }
-      else if ( vgUMR1.find(lines[cc]) ){ failure = cmCTestTestHandler::UMR; }
-      else if ( vgUMR2.find(lines[cc]) ){ failure = cmCTestTestHandler::UMR; }
-      else if ( vgUMR3.find(lines[cc]) ){ failure = cmCTestTestHandler::UMR; }
-      else if ( vgUMR4.find(lines[cc]) ){ failure = cmCTestTestHandler::UMR; }
-      else if ( vgIPW.find(lines[cc]) ) { failure = cmCTestTestHandler::IPW; }
-      else if ( vgABR.find(lines[cc]) ) { failure = cmCTestTestHandler::ABR; }
-
-      if ( failure != cmCTestTestHandler::NO_MEMORY_FAULT )
-        {
-        ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
-        results[failure] ++;
-        defects ++;
-        }
-      ostr << cmCTest::MakeXMLSafe(lines[cc]) << std::endl;
-      }
-    }
-  //std::cout << "End test (elapsed: " << (cmSystemTools::GetTime() - sttime) << std::endl;
-  log = ostr.str();
-  if ( defects )
-    {
-    return false;
-    }
-  return true;
-}
-
+//----------------------------------------------------------------------
 void cmCTestTestHandler::SetIncludeRegExp(const char *arg)
 {
   m_IncludeRegExp = arg;
 }
 
+//----------------------------------------------------------------------
 void cmCTestTestHandler::SetExcludeRegExp(const char *arg)
 {
   m_ExcludeRegExp = arg;
 }
 
+//----------------------------------------------------------------------
 void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
 {
   this->TestsToRunString = in;
@@ -1655,6 +1194,7 @@ void cmCTestTestHandler::SetTestsToRunInformation(const char* in)
     }
 }
 
+//----------------------------------------------------------------------
 bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t remove_threshold)
 {
   if ( remove_threshold == 0 )

+ 38 - 86
Source/CTest/cmCTestTestHandler.h

@@ -32,18 +32,21 @@ class cmCTestTestHandler : public cmCTestGenericHandler
 {
 public:
 
-  /*
+  /**
    * The main entry point for this class
    */
-  int TestDirectory(bool memcheck);
+  int ProcessHandler();
   
-  /*
+  /**
    * When both -R and -I are used should te resulting test list be the
    * intersection or the union of the lists. By default it is the
    * intersection.
    */
   void SetUseUnion(bool val) { m_UseUnion = val; }
 
+  /**
+   * This method is called when reading CTest custom file
+   */
   void PopulateCustomVectors(cmMakefile *mf);
   
   ///! Control the use of the regular expresisons, call these methods to turn
@@ -53,69 +56,13 @@ public:
   void SetIncludeRegExp(const char *);
   void SetExcludeRegExp(const char *);
   
-  cmCTestTestHandler();
 
   ///! pass the -I argument down
   void SetTestsToRunInformation(const char*);
 
-  typedef std::vector<cmListFileArgument> tm_VectorOfListFileArgs;
-  
-private:
-
-  enum { // Memory checkers
-    UNKNOWN = 0,
-    VALGRIND,
-    PURIFY,
-    BOUNDS_CHECKER
-  };
-
-  enum { // Memory faults
-    ABR = 0,
-    ABW,
-    ABWL,
-    COR,
-    EXU,
-    FFM,
-    FIM,
-    FMM,
-    FMR,
-    FMW,
-    FUM,
-    IPR,
-    IPW,
-    MAF,
-    MLK,
-    MPK,
-    NPR,
-    ODS,
-    PAR,
-    PLK,
-    UMC,
-    UMR,
-    NO_MEMORY_FAULT
-  };
-  
-  enum { // Program statuses
-    NOT_RUN = 0,
-    TIMEOUT,
-    SEGFAULT,
-    ILLEGAL,
-    INTERRUPT,
-    NUMERICAL,
-    OTHER_FAULT,
-    FAILED,
-    BAD_COMMAND,
-    COMPLETED
-  };
-
-  std::string              m_MemoryTester;
-  std::vector<cmStdString> m_MemoryTesterOptionsParsed;
-  std::string              m_MemoryTesterOptions;
-  int                      m_MemoryTesterStyle;
-  std::string              m_MemoryTesterOutputFile;
-  int                      m_MemoryTesterGlobalResults[NO_MEMORY_FAULT];
+  cmCTestTestHandler();
 
-  
+protected:
   struct cmCTestTestResult
   {
     std::string m_Name;
@@ -130,26 +77,48 @@ private:
     int         m_TestCount;
   };
 
+  typedef std::vector<cmListFileArgument> tm_VectorOfListFileArgs;
+
+  virtual int PreProcessHandler();
+  virtual int PostProcessHandler();
+  virtual void GenerateTestCommand(std::vector<const char*>& args);
+  int ExecuteCommands(std::vector<cmStdString>& vec);
+
+  double                  m_ElapsedTestingTime;
+
   typedef std::vector<cmCTestTestResult> tm_TestResultsVector;
   tm_TestResultsVector    m_TestResults;
 
-  int ExecuteCommands(std::vector<cmStdString>& vec);
+  std::vector<cmStdString> m_CustomTestsIgnore;
+  std::string             m_StartTest;
+  std::string             m_EndTest;
+  bool m_MemCheck;
+
+private:
+  enum { // Program statuses
+    NOT_RUN = 0,
+    TIMEOUT,
+    SEGFAULT,
+    ILLEGAL,
+    INTERRUPT,
+    NUMERICAL,
+    OTHER_FAULT,
+    FAILED,
+    BAD_COMMAND,
+    COMPLETED
+  };
 
-  ///! Initialize memory checking subsystem.
-  bool InitializeMemoryChecking();
 
   /**
    * Generate the Dart compatible output
    */
-  void GenerateDartTestOutput(std::ostream& os);
-  void GenerateDartMemCheckOutput(std::ostream& os);
+  virtual void GenerateDartOutput(std::ostream& os);
 
   /**
    * Run the test for a directory and any subdirectories
    */
   void ProcessDirectory(std::vector<cmStdString> &passed, 
-                        std::vector<cmStdString> &failed,
-                        bool memcheck);
+                        std::vector<cmStdString> &failed);
   
   struct cmCTestTestProperties
   {
@@ -163,7 +132,7 @@ private:
   /**
    * Get the list of tests in directory and subdirectories.
    */
-  void GetListOfTests(tm_ListOfTests* testlist, bool memcheck);
+  void GetListOfTests(tm_ListOfTests* testlist);
 
   /**
    * Find the executable for a test
@@ -175,17 +144,10 @@ private:
 
   std::vector<cmStdString> m_CustomPreTest;
   std::vector<cmStdString> m_CustomPostTest;
-  std::vector<cmStdString> m_CustomPreMemCheck;
-  std::vector<cmStdString> m_CustomPostMemCheck;
-  std::vector<cmStdString> m_CustomTestsIgnore;
-  std::vector<cmStdString> m_CustomMemCheckIgnore;
 
   int m_CustomMaximumPassedTestOutputSize;
   int m_CustomMaximumFailedTestOutputSize;
 
-  std::string             m_StartTest;
-  std::string             m_EndTest;
-  double                  m_ElapsedTestingTime;
   std::vector<int>        m_TestsToRun;
 
   bool m_UseIncludeRegExp;
@@ -196,16 +158,6 @@ private:
 
   std::string GenerateRegressionImages(const std::string& xml);
 
-  //! Parse Valgrind/Purify/Bounds Checker result out of the output
-  //string. After running, log holds the output and results hold the
-  //different memmory errors.
-  bool ProcessMemCheckOutput(const std::string& str, 
-                             std::string& log, int* results);
-  bool ProcessMemCheckValgrindOutput(const std::string& str, 
-                                     std::string& log, int* results);
-  bool ProcessMemCheckPurifyOutput(const std::string& str, 
-                                   std::string& log, int* results);
-
   //! Clean test output to specified length
   bool CleanTestOutput(std::string& output, size_t length);
 

+ 1 - 1
Source/CTest/cmCTestUpdateHandler.cxx

@@ -49,7 +49,7 @@ cmCTestUpdateHandler::cmCTestUpdateHandler()
 //----------------------------------------------------------------------
 //clearly it would be nice if this were broken up into a few smaller
 //functions and commented...
-int cmCTestUpdateHandler::UpdateDirectory()
+int cmCTestUpdateHandler::ProcessHandler()
 {
   int count = 0;
   std::string::size_type cc, kk;

+ 1 - 1
Source/CTest/cmCTestUpdateHandler.h

@@ -33,7 +33,7 @@ public:
   /*
    * The main entry point for this class
    */
-  int UpdateDirectory();
+  int ProcessHandler();
   
   cmCTestUpdateHandler();
   

+ 61 - 53
Source/cmCTest.cxx

@@ -27,11 +27,12 @@
 #include "cmGeneratedFileStream.h"
 
 #include "cmCTestBuildHandler.h"
+#include "cmCTestConfigureHandler.h"
 #include "cmCTestCoverageHandler.h"
+#include "cmCTestMemCheckHandler.h"
 #include "cmCTestScriptHandler.h"
 #include "cmCTestTestHandler.h"
 #include "cmCTestUpdateHandler.h"
-#include "cmCTestConfigureHandler.h"
 
 #include "cmCTestSubmit.h"
 #include "cmVersion.h"
@@ -240,29 +241,29 @@ cmCTest::cmCTest()
     }
   m_ShortDateFormat        = true;
 
-  this->BuildHandler     = new cmCTestBuildHandler;
-  this->CoverageHandler  = new cmCTestCoverageHandler;
-  this->ScriptHandler    = new cmCTestScriptHandler;
-  this->TestHandler      = new cmCTestTestHandler;
-  this->UpdateHandler    = new cmCTestUpdateHandler;
-  this->ConfigureHandler = new cmCTestConfigureHandler;
-
-  this->BuildHandler->SetCTestInstance(this);
-  this->CoverageHandler->SetCTestInstance(this);
-  this->ScriptHandler->SetCTestInstance(this);
-  this->TestHandler->SetCTestInstance(this);
-  this->UpdateHandler->SetCTestInstance(this);
-  this->ConfigureHandler->SetCTestInstance(this);
+  m_TestingHandlers["build"]     = new cmCTestBuildHandler;
+  m_TestingHandlers["coverage"]  = new cmCTestCoverageHandler;
+  m_TestingHandlers["script"]    = new cmCTestScriptHandler;
+  m_TestingHandlers["test"]      = new cmCTestTestHandler;
+  m_TestingHandlers["update"]    = new cmCTestUpdateHandler;
+  m_TestingHandlers["configure"] = new cmCTestConfigureHandler;
+  m_TestingHandlers["memcheck"]  = new cmCTestMemCheckHandler;
+
+  cmCTest::t_TestingHandlers::iterator it;
+  for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
+    {
+    it->second->SetCTestInstance(this);
+    }
 }
 
 cmCTest::~cmCTest() 
 { 
-  delete this->BuildHandler;
-  delete this->CoverageHandler;
-  delete this->ScriptHandler;
-  delete this->TestHandler;
-  delete this->UpdateHandler;
-  delete this->ConfigureHandler;
+  cmCTest::t_TestingHandlers::iterator it;
+  for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
+    {
+    delete it->second;
+    it->second = 0;
+    }
 }
 
 int cmCTest::Initialize()
@@ -727,7 +728,7 @@ int cmCTest::ProcessTests()
     }
   if ( m_Tests[UPDATE_TEST] || m_Tests[ALL_TEST] )
     {
-    update_count = this->UpdateHandler->UpdateDirectory(); 
+    update_count = m_TestingHandlers["update"]->ProcessHandler(); 
     if ( update_count < 0 )
       {
       res |= cmCTest::UPDATE_ERRORS;
@@ -739,7 +740,7 @@ int cmCTest::ProcessTests()
     }
   if ( m_Tests[CONFIGURE_TEST] || m_Tests[ALL_TEST] )
     {
-    if (this->ConfigureHandler->ConfigureDirectory())
+    if (m_TestingHandlers["configure"]->ProcessHandler() < 0)
       {
       res |= cmCTest::CONFIGURE_ERRORS;
       }
@@ -747,7 +748,7 @@ int cmCTest::ProcessTests()
   if ( m_Tests[BUILD_TEST] || m_Tests[ALL_TEST] )
     {
     this->UpdateCTestConfiguration();
-    if (this->BuildHandler->BuildDirectory())
+    if (m_TestingHandlers["build"]->ProcessHandler() < 0)
       {
       res |= cmCTest::BUILD_ERRORS;
       }
@@ -755,7 +756,7 @@ int cmCTest::ProcessTests()
   if ( m_Tests[TEST_TEST] || m_Tests[ALL_TEST] || notest )
     {
     this->UpdateCTestConfiguration();
-    if (this->TestHandler->TestDirectory(false))
+    if (m_TestingHandlers["test"]->ProcessHandler() < 0)
       {
       res |= cmCTest::TEST_ERRORS;
       }
@@ -763,7 +764,7 @@ int cmCTest::ProcessTests()
   if ( m_Tests[COVERAGE_TEST] || m_Tests[ALL_TEST] )
     {
     this->UpdateCTestConfiguration();
-    if (this->CoverageHandler->CoverageDirectory())
+    if (m_TestingHandlers["coverage"]->ProcessHandler() < 0)
       {
       res |= cmCTest::COVERAGE_ERRORS;
       }
@@ -771,7 +772,7 @@ int cmCTest::ProcessTests()
   if ( m_Tests[MEMCHECK_TEST] || m_Tests[ALL_TEST] )
     {
     this->UpdateCTestConfiguration();
-    if (this->TestHandler->TestDirectory(true))
+    if (m_TestingHandlers["memcheck"]->ProcessHandler() < 0)
       {
       res |= cmCTest::MEMORY_ERRORS;
       }
@@ -1181,12 +1182,11 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
     if( arg.find("-V",0) == 0 || arg.find("--verbose",0) == 0 )
       {
       this->m_Verbose = true;
-      this->BuildHandler->SetVerbose(this->m_Verbose);
-      this->ConfigureHandler->SetVerbose(this->m_Verbose);
-      this->CoverageHandler->SetVerbose(this->m_Verbose);
-      this->ScriptHandler->SetVerbose(this->m_Verbose);
-      this->TestHandler->SetVerbose(this->m_Verbose);
-      this->UpdateHandler->SetVerbose(this->m_Verbose);
+      cmCTest::t_TestingHandlers::iterator it;
+      for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
+        {
+        it->second->SetVerbose(this->m_Verbose);
+        }
       }
 
     if( arg.find("-N",0) == 0 || arg.find("--show-only",0) == 0 )
@@ -1198,7 +1198,8 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
       {
       this->m_RunConfigurationScript = true;
       i++;
-      this->ScriptHandler->AddConfigurationScript(args[i].c_str());
+      cmCTestScriptHandler* ch = static_cast<cmCTestScriptHandler*>(m_TestingHandlers["script"]);
+      ch->AddConfigurationScript(args[i].c_str());
       }
 
     if( arg.find("--tomorrow-tag",0) == 0 )
@@ -1468,24 +1469,28 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
     if(arg.find("-I",0) == 0 && i < args.size() - 1)
       {
       i++;
-      this->TestHandler->SetTestsToRunInformation(args[i].c_str());
-      }
-    if(arg.find("-U",0) == 0)
-      {
-      this->TestHandler->SetUseUnion(true);
-      }
-    if(arg.find("-R",0) == 0 && i < args.size() - 1)
-      {
-      this->TestHandler->UseIncludeRegExp();
+      cmCTestTestHandler* th = static_cast<cmCTestTestHandler*>(m_TestingHandlers["test"]);
+      th->SetTestsToRunInformation(args[i].c_str());          
+      }                                                       
+    if(arg.find("-U",0) == 0)                                 
+      {                                                       
+      cmCTestTestHandler* th = static_cast<cmCTestTestHandler*>(m_TestingHandlers["test"]);
+      th->SetUseUnion(true);                                  
+      }                                                       
+    if(arg.find("-R",0) == 0 && i < args.size() - 1)          
+      {                                                       
+      cmCTestTestHandler* th = static_cast<cmCTestTestHandler*>(m_TestingHandlers["test"]);
+      th->UseIncludeRegExp();                                 
+      i++;                                                    
+      th->SetIncludeRegExp(args[i].c_str());                  
+      }                                                       
+                                                              
+    if(arg.find("-E",0) == 0 && i < args.size() - 1)          
+      {                                                       
+      cmCTestTestHandler* th = static_cast<cmCTestTestHandler*>(m_TestingHandlers["test"]);
+      th->UseExcludeRegExp();
       i++;
-      this->TestHandler->SetIncludeRegExp(args[i].c_str());
-      }
-
-    if(arg.find("-E",0) == 0 && i < args.size() - 1)
-      {
-      this->TestHandler->UseExcludeRegExp();
-      i++;
-      this->TestHandler->SetExcludeRegExp(args[i].c_str());
+      th->SetExcludeRegExp(args[i].c_str());
       }
 
     if(arg.find("-A",0) == 0 && i < args.size() - 1)
@@ -1607,7 +1612,7 @@ int cmCTest::Run(std::vector<std::string>const& args, std::string* output)
     // call process directory
     if (this->m_RunConfigurationScript)
       {
-      res = this->ScriptHandler->RunConfigurationScript();
+      res = m_TestingHandlers["script"]->ProcessHandler();
       }
     else
       {
@@ -2138,8 +2143,11 @@ int cmCTest::ReadCustomConfigurationFileTree(const char* dir)
     dirs.insert(dirs.end(), ndirs.begin(), ndirs.end());
     }
 
-  this->BuildHandler->PopulateCustomVectors(mf);
-  this->TestHandler->PopulateCustomVectors(mf);
+  cmCTest::t_TestingHandlers::iterator it;
+  for ( it = m_TestingHandlers.begin(); it != m_TestingHandlers.end(); ++ it )
+    {
+    it->second->PopulateCustomVectors(mf);
+    }
   
   return 1;
 }

+ 3 - 12
Source/cmCTest.h

@@ -24,12 +24,7 @@
 #include <time.h>
 
 class cmMakefile;
-class cmCTestBuildHandler;
-class cmCTestConfigureHandler;
-class cmCTestCoverageHandler;
-class cmCTestScriptHandler;
-class cmCTestTestHandler;
-class cmCTestUpdateHandler;
+class cmCTestGenericHandler;
 class cmGeneratedFileStream;
 
 class cmCTest
@@ -194,12 +189,8 @@ public:
 
 private:
   // these are helper classes
-  cmCTestBuildHandler     *BuildHandler;
-  cmCTestCoverageHandler  *CoverageHandler;
-  cmCTestScriptHandler    *ScriptHandler;
-  cmCTestTestHandler      *TestHandler;
-  cmCTestUpdateHandler    *UpdateHandler;
-  cmCTestConfigureHandler *ConfigureHandler;
+  typedef std::map<cmStdString,cmCTestGenericHandler*> t_TestingHandlers;
+  t_TestingHandlers m_TestingHandlers;
   
   bool m_ShowOnly;