From 8ffd8d0a03d68241ce4f5f8a9fd266bee1032e1d Mon Sep 17 00:00:00 2001
From: Zach Mullen <zach.mullen@kitware.com>
Date: Wed, 26 Aug 2009 12:09:06 -0400
Subject: ENH: refactored ctest.  All testing is now parallel.  If no -j option
 is specified, defaults to a MP level of 1 (non parallel)

---
 Source/CTest/cmCTestMultiProcessHandler.cxx | 158 +++------
 Source/CTest/cmCTestMultiProcessHandler.h   |  32 +-
 Source/CTest/cmCTestRunTest.cxx             | 481 ++++++++++++----------------
 Source/CTest/cmCTestRunTest.h               |  46 +--
 Source/CTest/cmCTestTestHandler.cxx         | 103 ++----
 Source/CTest/cmCTestTestHandler.h           |   6 +-
 Source/cmCTest.cxx                          |   7 +-
 Source/cmCTest.h                            |   2 +-
 8 files changed, 329 insertions(+), 506 deletions(-)

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 70ca4c0..328e2e5 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -23,12 +23,11 @@
 cmCTestMultiProcessHandler::cmCTestMultiProcessHandler()
 {
   this->ParallelLevel = 1;
-  this->ProcessId = 0;
 }
   // Set the tests
 void 
 cmCTestMultiProcessHandler::SetTests(TestMap& tests,
-                                     std::map<int,cmStdString>& testNames)
+                                     PropertiesMap& properties)
 {
   // set test run map to false for all
   for(TestMap::iterator i = this->Tests.begin();
@@ -38,15 +37,14 @@ cmCTestMultiProcessHandler::SetTests(TestMap& tests,
     this->TestFinishMap[i->first] = false;
     }
   this->Tests = tests;
-  this->TestNames = testNames;
+  this->Properties = properties;
 }
   // Set the max number of tests that can be run at the same time.
-void cmCTestMultiProcessHandler::SetParallelLevel(size_t l)
+void cmCTestMultiProcessHandler::SetParallelLevel(size_t level)
 {
-  this->ParallelLevel = l;
+  this->ParallelLevel = level < 1 ? 1 : level;
 }
 
-
 void cmCTestMultiProcessHandler::RunTests()
 {
   this->StartNextTests();
@@ -59,65 +57,28 @@ void cmCTestMultiProcessHandler::RunTests()
   while(this->CheckOutput())
     {
     }
-  
-  for(std::map<int, cmStdString>::iterator i =
-        this->TestOutput.begin();
-      i != this->TestOutput.end(); ++i)
-    {
-    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
-               i->second << std::endl);
-    }
-      
 }
 
 void cmCTestMultiProcessHandler::StartTestProcess(int test)
 {
-  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
-            " test " << test << "\n");
+  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, test << ": "
+            << " test " << test << "\n");
   this->TestRunningMap[test] = true; // mark the test as running
   // now remove the test itself
   this->Tests.erase(test);
-  // now run the test
-  cmProcess* newp = new cmProcess;
-  newp->SetId(this->ProcessId);
-  newp->SetId(test);
-  newp->SetCommand(this->CTestCommand.c_str());
-  std::vector<std::string> args;
-  cmOStringStream width;
-  if(this->CTest->GetMaxTestNameWidth())
-    {
-    args.push_back("-W");
-    width << this->CTest->GetMaxTestNameWidth();
-    args.push_back(width.str().c_str());
-    }
-  args.push_back("-I");
-  cmOStringStream strm;
-  strm << test << "," << test;
-  args.push_back(strm.str());
-  args.push_back("--parallel-cache");
-  args.push_back(this->CTestCacheFile.c_str());
-  args.push_back("--internal-ctest-parallel"); 
-  cmOStringStream strm2;
-  strm2 << test;
-  args.push_back(strm2.str());
-  if(this->CTest->GetExtraVerbose())
-    {
-    args.push_back("-VV");
-    }
-  newp->SetCommandArguments(args);
-  if(!newp->StartProcess())
+  cmCTestRunTest* testRun = new cmCTestRunTest;
+  testRun->SetCTest(this->CTest);
+  testRun->SetTestHandler(this->TestHandler);
+  testRun->SetIndex(test);
+  testRun->SetTestProperties(this->Properties[test]);
+  if(testRun->StartTest())
     {
-     cmCTestLog(this->CTest, ERROR_MESSAGE, 
-                "Error starting " << newp->GetCommand() << "\n");
-    this->EndTest(newp);
+    this->RunningTests.insert(testRun);
     }
   else
     {
-    this->RunningTests.insert(newp);
+    testRun->EndTest();
     }
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
-            "ctest -I " << test << "\n");
- this->ProcessId++;
 }
 
 bool cmCTestMultiProcessHandler::StartTest(int test)
@@ -160,7 +121,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test)
     }
   // This test was not able to start because it is waiting 
   // on depends to run
-  return false;  
+  return false;
 }
 
 void cmCTestMultiProcessHandler::StartNextTests()
@@ -195,7 +156,6 @@ void cmCTestMultiProcessHandler::StartNextTests()
     }
 }
 
-
 bool cmCTestMultiProcessHandler::CheckOutput()
 {
   // no more output we are done
@@ -203,82 +163,48 @@ bool cmCTestMultiProcessHandler::CheckOutput()
     {
     return false;
     }
-  std::vector<cmProcess*> finished;
+  std::vector<cmCTestRunTest*> finished;
   std::string out, err;
-  for(std::set<cmProcess*>::const_iterator i = this->RunningTests.begin();
+  for(std::set<cmCTestRunTest*>::const_iterator i = this->RunningTests.begin();
       i != this->RunningTests.end(); ++i)
     {
-    cmProcess* p = *i;
-    int pipe = p->CheckOutput(.1, out, err);
-    if(pipe == cmsysProcess_Pipe_STDOUT)
-      {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, 
-                 p->GetId() << ": " << out << std::endl);
-      this->TestOutput[ p->GetId() ] += out;
-      this->TestOutput[ p->GetId() ] += "\n";
-      }
-    else if(pipe == cmsysProcess_Pipe_STDERR)
-      {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, 
-                 p->GetId() << ": " << err << std::endl);
-      this->TestOutput[ p->GetId() ] += err;
-      this->TestOutput[ p->GetId() ] += "\n";
-      }
+    cmCTestRunTest* p = *i;
+    p->CheckOutput(); //reads and stores the process output
+    
     if(!p->IsRunning())
       {
       finished.push_back(p);
       }
     }
-  for( std::vector<cmProcess*>::iterator i = finished.begin();
-       i != finished.end(); ++i)
-    {
-    cmProcess* p = *i;
-    this->EndTest(p);
-    }
-  return true;
-}
 
-void cmCTestMultiProcessHandler::EndTest(cmProcess* p)
-{
-  // Should have a way of getting this stuff from the 
-  // launched ctest, maybe a temp file or some extra xml
-  // stuff in the stdout
-  // Need things like Reason and ExecutionTime, Path, etc.
-  int test = p->GetId();
-  int exitVal = p->GetExitValue();
-  cmCTestTestHandler::cmCTestTestResult cres;
-  cres.Properties = 0;
-  cres.ExecutionTime = p->GetTotalTime();
-  cres.ReturnValue = exitVal;
-  cres.Status = cmCTestTestHandler::COMPLETED;
-  cres.TestCount = test;  
-  cres.Name = this->TestNames[test];
-  cres.Path = "";
-  if(exitVal)
+  for( std::vector<cmCTestRunTest*>::iterator i = finished.begin();
+       i != finished.end(); ++i)
     {
-    cres.Status = cmCTestTestHandler::FAILED;
-    this->Failed->push_back(this->TestNames[test]);
-    }
-  else
+    cmCTestRunTest* p = *i;
+    int test = p->GetIndex();
+    
+    if(p->EndTest())
+      {
+        this->Passed->push_back(p->GetTestProperties()->Name);
+      }
+    else
+      {
+        this->Failed->push_back(p->GetTestProperties()->Name);
+      }
+    for(TestMap::iterator j = this->Tests.begin();
+       j!=  this->Tests.end(); ++j)
     {
-    this->Passed->push_back(this->TestNames[test]);
+    j->second.erase(test);
     }
-  this->TestResults->push_back(cres);
-  // remove test from depend of all other tests
-  for(TestMap::iterator i = this->Tests.begin();
-       i!=  this->Tests.end(); ++i)
-    {
-    i->second.erase(test);
+    this->TestFinishMap[test] = true;
+    this->TestRunningMap[test] = false;
+    this->RunningTests.erase(p);
+
+    delete p;
     }
-  this->TestFinishMap[test] = true;
-  this->TestRunningMap[test] = false;
-  this->RunningTests.erase(p);
-  delete p;
-  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
-             "finish test " << test << "\n");
+  return true;
 }
 
-
 void cmCTestMultiProcessHandler::PrintTests()
 {
 #undef cout
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 75be542..413bff2 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -17,9 +17,9 @@
 #ifndef cmCTestMultiProcessHandler_h
 #define cmCTestMultiProcessHandler_h
 
-class cmProcess;
 #include <cmStandardIncludes.h>
 #include <cmCTestTestHandler.h>
+#include <cmCTestRunTest.h>
 
 /** \class cmCTestMultiProcessHandler
  * \brief run parallel ctest
@@ -31,16 +31,18 @@ class cmCTestMultiProcessHandler
 public:
   struct TestSet : public std::set<int> {};
   struct TestMap : public std::map<int, TestSet> {};
+  struct PropertiesMap : public 
+     std::map<int, cmCTestTestHandler::cmCTestTestProperties*> {};
+
   cmCTestMultiProcessHandler();
   // Set the tests
-  void SetTests(TestMap& tests,
-                std::map<int, cmStdString>& testNames);
+  void SetTests(TestMap& tests, PropertiesMap& properties);
   // Set the max number of tests that can be run at the same time.
   void SetParallelLevel(size_t);
   void RunTests();
   void PrintTests();
-  void SetCTestCommand(const char* c) { this->CTestCommand = c;}
-  void SetTestCacheFile(const char* c) { this->CTestCacheFile = c;}
+  //void SetCTestCommand(const char* c) { this->CTestCommand = c;}
+  //void SetTestCacheFile(const char* c) { this->CTestCacheFile = c;}
   void SetPassFailVectors(std::vector<cmStdString>* passed,
                           std::vector<cmStdString>* failed)
     {
@@ -51,7 +53,14 @@ public:
     {
       this->TestResults = r;
     }
+
   void SetCTest(cmCTest* ctest) { this->CTest = ctest;}
+
+  void SetTestHandler(cmCTestTestHandler * handler)
+  { this->TestHandler = handler; }
+
+  cmCTestTestHandler * GetTestHandler()
+  { return this->TestHandler; }
 protected:  
   cmCTest* CTest;
   // Start the next test or tests as many as are allowed by
@@ -59,24 +68,25 @@ protected:
   void StartNextTests();
   void StartTestProcess(int test);
   bool StartTest(int test);
-  void EndTest(cmProcess*);
+  //void EndTest(cmProcess*);
   // Return true if there are still tests running
   // check all running processes for output and exit case
   bool CheckOutput();
   // map from test number to set of depend tests
   TestMap Tests;
-  std::map<int, cmStdString> TestNames;
+  //list of test properties (indices concurrent to the test map)
+  PropertiesMap Properties;
   std::map<int, bool> TestRunningMap;
   std::map<int, bool> TestFinishMap;
   std::map<int, cmStdString> TestOutput;
-  std::string CTestCommand;
-  std::string CTestCacheFile;
+  //std::string CTestCommand;
+  //std::string CTestCacheFile;
   std::vector<cmStdString>* Passed;
   std::vector<cmStdString>* Failed;
   std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
-  int ProcessId;
   size_t ParallelLevel; // max number of process that can be run at once
-  std::set<cmProcess*> RunningTests;  // current running tests
+  std::set<cmCTestRunTest*> RunningTests;  // current running tests
+  cmCTestTestHandler * TestHandler;
 };
 
 #endif
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index cd6112d..d444249 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -21,150 +21,52 @@
 
 cmCTestRunTest::cmCTestRunTest()
 {
-  this->OptimizeForCTest = true;
-  cmCTestTestHandler::cmCTestTestResult result;
-  this->TestResult = result;
 }
 
 cmCTestRunTest::~cmCTestRunTest()
 {
 }
 
-void cmCTestRunTest::SetTestHandler(cmCTestTestHandler * handler)
+bool cmCTestRunTest::IsRunning()
 {
-  this->TestHandler = handler;
-  this->CTest = handler->CTest;
+  return this->TestProcess->IsRunning();
 }
 
-//----------------------------------------------------------------------
-// Executes a test.  Returns whether it passed or failed
-bool cmCTestRunTest::Execute()
+//---------------------------------------------------------
+//waits .1 sec for output from this process.
+void cmCTestRunTest::CheckOutput()
 {
-  const std::string& testname = this->TestProperties->Name;
-  std::vector<std::string>& args = this->TestProperties->Args;
-  this->TestResult.Properties = this->TestProperties;
-  this->TestResult.ExecutionTime = 0;
-  this->TestResult.ReturnValue = -1;
-  this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
-  this->TestResult.TestCount = this->TestProperties->Index;  
-  this->TestResult.Name = testname;
-  this->TestResult.Path = this->TestProperties->Directory.c_str();
-
-  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
-             << this->TestProperties->Index << "/");
-  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
-             << this->TestHandler->TotalNumberOfTests << " ");
-  if ( this->TestHandler->MemCheck )
-    {
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
-    }
-  else
-    {
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
-    }
-  cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
-  const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
-  std::string outname = testname + " ";
-  outname.resize(maxTestNameWidth, '.');
-  *this->TestHandler->LogFile << this->TestProperties->Index << "/" 
-    << this->TestHandler->TotalNumberOfTests << " Testing: " 
-    << testname << std::endl;
-
-  if ( this->CTest->GetShowOnly() )
-    {
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
-    }
-  else
-    {
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
-    }
-
-  cmCTestLog(this->CTest, DEBUG, "Testing " << args[0].c_str() << " ... ");
-  // find the test executable
-  std::string actualCommand 
-    = this->TestHandler->FindTheExecutable(args[1].c_str());
-  std::string testCommand
-    = cmSystemTools::ConvertToOutputPath(actualCommand.c_str());
-
-  // continue if we did not find the executable
-  if (testCommand == "")
-    {
-    *this->TestHandler->LogFile << "Unable to find executable: " 
-                   << args[1].c_str() << std::endl;
-    cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
-               << args[1].c_str() << std::endl);
-    this->TestResult.Output = "Unable to find executable: " + args[1];
-    if ( !this->CTest->GetShowOnly() )
-      {
-      this->TestResult.FullCommandLine = actualCommand;
-      this->TestHandler->TestResults.push_back( this->TestResult );
-      return false;
-      }
-    }
-
-  // add the arguments
-  std::vector<std::string>::const_iterator j = args.begin();
-  ++j; // skip test name
-  ++j; // skip command as it is in actualCommand
-  std::vector<const char*> arguments;
-  this->TestHandler->GenerateTestCommand(arguments);
-  arguments.push_back(actualCommand.c_str());
-  for(;j != args.end(); ++j)
+  std::string out, err;
+  int pipe = this->TestProcess->CheckOutput(.1, out, err);
+  if(pipe == cmsysProcess_Pipe_STDOUT)
     {
-    testCommand += " ";
-    testCommand += cmSystemTools::EscapeSpaces(j->c_str());
-    arguments.push_back(j->c_str());
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
+               this->GetIndex() << ": " << out << std::endl);
+    this->ProcessOutput += out;
+    this->ProcessOutput += "\n";
     }
-  arguments.push_back(0);
-
-  /**
-   * Run an executable command and put the stdout in output.
-   */
-  std::string output;
-  int retVal = 0;
-
-  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
-             << (this->TestHandler->MemCheck?"MemCheck":"Test") 
-             << " command: " << testCommand
-             << std::endl);
-  *this->TestHandler->LogFile << this->TestProperties->Index << "/" 
-                 << this->TestHandler->TotalNumberOfTests
-                 << " Test: " << testname.c_str() << std::endl;
-  *this->TestHandler->LogFile << "Command: ";
-  std::vector<cmStdString>::size_type ll;
-  for ( ll = 0; ll < arguments.size()-1; ll ++ )
+  else if(pipe == cmsysProcess_Pipe_STDERR)
     {
-    *this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, 
+               this->GetIndex() << ": " << err << std::endl);
+    this->ProcessOutput += err;
+    this->ProcessOutput += "\n";
     }
-  *this->TestHandler->LogFile
-    << std::endl
-    << "Directory: " << this->TestProperties->Directory << std::endl
-    << "\"" << testname.c_str() << "\" start time: "
-    << this->CTest->CurrentTime() << std::endl
-    << "Output:" << std::endl
-    << "----------------------------------------------------------"
-    << std::endl;
-  int res = 0;
-  double clock_start, clock_finish;
-  clock_start = cmSystemTools::GetTime();
+}
 
-  if ( !this->CTest->GetShowOnly() )
+//---------------------------------------------------------
+bool cmCTestRunTest::EndTest()
+{
+  //restore the old environment
+  if (this->ModifyEnv)
     {
-    res = this->RunTestProcess(arguments, &output, &retVal,
-                               this->TestHandler->LogFile,
-                               this->TestProperties->Timeout,
-                               &this->TestProperties->Environment);
-    this->ProcessOutput = output; //save process output in the object
+    cmSystemTools::RestoreEnv(this->OrigEnv);
     }
-
-  clock_finish = cmSystemTools::GetTime();  
-
-  this->TestResult.ExecutionTime = (double)(clock_finish - clock_start);
-  this->TestResult.FullCommandLine = testCommand;
+  this->WriteLogOutputTop();
   std::string reason;
-
   bool passed = true;
-
+  int res = this->TestProcess->GetProcessStatus();
+  int retVal = this->TestProcess->GetExitValue();
   if ( !this->CTest->GetShowOnly() )
     {
     std::vector<std::pair<cmsys::RegularExpression,
@@ -177,7 +79,7 @@ bool cmCTestRunTest::Execute()
             passIt != this->TestProperties->RequiredRegularExpressions.end();
             ++ passIt )
         {
-        if ( passIt->first.find(output.c_str()) )
+        if ( passIt->first.find(this->ProcessOutput.c_str()) )
           {
           found = true;
           reason = "Required regular expression found.";
@@ -204,7 +106,7 @@ bool cmCTestRunTest::Execute()
             passIt != this->TestProperties->ErrorRegularExpressions.end();
             ++ passIt )
         {
-        if ( passIt->first.find(output.c_str()) )
+        if ( passIt->first.find(this->ProcessOutput.c_str()) )
           {
           reason = "Error regular expression found in output.";
           reason += " Regex=[";
@@ -214,7 +116,6 @@ bool cmCTestRunTest::Execute()
           }
         }
       }
-
     if (res == cmsysProcess_State_Exited)
       {
       bool success = 
@@ -224,13 +125,12 @@ bool cmCTestRunTest::Execute()
         || (!success && this->TestProperties->WillFail))
         {
         this->TestResult.Status = cmCTestTestHandler::COMPLETED;
-        cmCTestLog(this->CTest, HANDLER_OUTPUT,   "   Passed  " );
+        cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Passed  " );
         }
       else
         {
         this->TestResult.Status = cmCTestTestHandler::FAILED;
-        cmCTestLog(this->CTest, HANDLER_OUTPUT,
-                   "***Failed  " << reason );
+        cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed  " << reason );
         }
       }
     else if ( res == cmsysProcess_State_Expired )
@@ -273,28 +173,29 @@ bool cmCTestRunTest::Execute()
     passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
 
     char buf[1024];
-    sprintf(buf, "%6.2f sec", this->TestResult.ExecutionTime);
+    sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime());
     cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n" );
     if ( this->TestHandler->LogFile )
       {
-      *this->TestHandler->LogFile << "\nTest time = " << buf << std::endl;
+      *this->TestHandler->LogFile << "Test time = " << buf << std::endl;
       }
-    this->DartProcessing(output);
+    this->DartProcessing();
     } 
-
   // if this is doing MemCheck then all the output needs to be put into
   // Output since that is what is parsed by cmCTestMemCheckHandler
   if(!this->TestHandler->MemCheck)
     {
     if ( this->TestResult.Status == cmCTestTestHandler::COMPLETED )
       {
-      this->TestHandler->CleanTestOutput(output, static_cast<size_t>
-                     (this->TestHandler->CustomMaximumPassedTestOutputSize));
+      this->TestHandler->CleanTestOutput(this->ProcessOutput, 
+          static_cast<size_t>
+          (this->TestHandler->CustomMaximumPassedTestOutputSize));
       }
     else
       {
-      this->TestHandler->CleanTestOutput(output, static_cast<size_t>
-                     (this->TestHandler->CustomMaximumFailedTestOutputSize));
+      this->TestHandler->CleanTestOutput(this->ProcessOutput,
+          static_cast<size_t>
+          (this->TestHandler->CustomMaximumFailedTestOutputSize));
       }
     }
   this->TestResult.Reason = reason;
@@ -308,7 +209,7 @@ bool cmCTestRunTest::Execute()
       reasonType = "Test Fail Reason";
       pass = false;
       }
-    double ttime = clock_finish - clock_start;
+    double ttime = this->TestProcess->GetTotalTime();
     int hours = static_cast<int>(ttime / (60 * 60));
     int minutes = static_cast<int>(ttime / 60) % 60;
     int seconds = static_cast<int>(ttime) % 60;
@@ -333,34 +234,99 @@ bool cmCTestRunTest::Execute()
         *this->TestHandler->LogFile << "Test Failed.\n";
         }
       }
-    *this->TestHandler->LogFile << "\"" << testname.c_str() << "\" end time: "
-      << this->CTest->CurrentTime() << std::endl
-      << "\"" << testname.c_str() << "\" time elapsed: "
+    *this->TestHandler->LogFile << "\"" << this->TestProperties->Name.c_str()
+      << "\" end time: " << this->CTest->CurrentTime() << std::endl
+      << "\"" << this->TestProperties->Name.c_str() << "\" time elapsed: "
       << buffer << std::endl
       << "----------------------------------------------------------"
       << std::endl << std::endl;
     }
-  this->TestResult.Output = output;
-  this->TestResult.ReturnValue = retVal;
+  this->TestResult.Output = this->ProcessOutput;
+  this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
   this->TestResult.CompletionStatus = "Completed";
+  this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
   this->TestHandler->TestResults.push_back( this->TestResult );
 
+  delete this->TestProcess;
   return passed;
 }
 
+void cmCTestRunTest::SetTestHandler(cmCTestTestHandler * handler)
+{
+  this->TestHandler = handler;
+  this->CTest = handler->CTest;
+}
+
+//----------------------------------------------------------------------
+// Starts the execution of a test.  Returns once it has started
+bool cmCTestRunTest::StartTest()
+{
+  std::vector<std::string>& args = this->TestProperties->Args;
+  this->TestResult.Properties = this->TestProperties;
+  this->TestResult.ExecutionTime = 0;
+  this->TestResult.ReturnValue = -1;
+  this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
+  this->TestResult.TestCount = this->TestProperties->Index;  
+  this->TestResult.Name = this->TestProperties->Name;
+  this->TestResult.Path = this->TestProperties->Directory.c_str();
+  
+  // find the test executable
+  this->ActualCommand 
+    = this->TestHandler->FindTheExecutable(args[1].c_str());
+  this->TestCommand
+    = cmSystemTools::ConvertToOutputPath(this->ActualCommand.c_str());
+
+  // continue if we did not find the executable
+  if (this->TestCommand == "")
+    {
+    *this->TestHandler->LogFile << "Unable to find executable: " 
+                   << args[1].c_str() << std::endl;
+    cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to find executable: "
+               << args[1].c_str() << std::endl);
+    this->TestResult.Output = "Unable to find executable: " + args[1];
+    if ( !this->CTest->GetShowOnly() )
+      {
+      this->TestResult.FullCommandLine = this->ActualCommand;
+      this->TestHandler->TestResults.push_back( this->TestResult );
+      return false;
+      }
+    }
+
+  /**
+   * Run an executable command and put the stdout in output.
+   */
+  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl
+             << this->Index << ": "
+             << (this->TestHandler->MemCheck?"MemCheck":"Test") 
+             << " command: " << this->TestCommand
+             << std::endl);
+
+  this->StartTime = this->CTest->CurrentTime();
+
+  if ( !this->CTest->GetShowOnly() )
+    {
+    return this->CreateProcess(this->ActualCommand,
+                               this->TestProperties->Args,
+                               this->TestProperties->Timeout,
+                               &this->TestProperties->Environment);
+    }
+  return true;
+}
+
 //----------------------------------------------------------------------
-void cmCTestRunTest::DartProcessing(std::string& output)
+void cmCTestRunTest::DartProcessing()
 {
-  if (!output.empty() && output.find("<DartMeasurement") != output.npos)
+  if (!this->ProcessOutput.empty() && 
+     this->ProcessOutput.find("<DartMeasurement") != this->ProcessOutput.npos)
     {
-    if (this->TestHandler->DartStuff.find(output.c_str()))
+    if (this->TestHandler->DartStuff.find(this->ProcessOutput.c_str()))
       {
       std::string dartString = this->TestHandler->DartStuff.match(1);
       // keep searching and replacing until none are left
-      while (this->TestHandler->DartStuff1.find(output.c_str()))
+      while (this->TestHandler->DartStuff1.find(this->ProcessOutput.c_str()))
         {
         // replace the exact match for the string
-        cmSystemTools::ReplaceString(output,
+        cmSystemTools::ReplaceString(this->ProcessOutput,
                          this->TestHandler->DartStuff1.match(1).c_str(), "");
         }
       this->TestResult.RegressionImages
@@ -370,13 +336,27 @@ void cmCTestRunTest::DartProcessing(std::string& output)
 }
 
 //----------------------------------------------------------------------
-int cmCTestRunTest::RunTestProcess(std::vector<const char*> argv,
-                     std::string* output, int *retVal,
-                     std::ostream* log, double testTimeOut,
+bool cmCTestRunTest::CreateProcess(std::string command,
+                     std::vector<std::string> args,
+                     double testTimeOut,
                      std::vector<std::string>* environment)
 {
+  std::vector<std::string> commandArgs;
+  std::vector<std::string>::iterator i = args.begin();
+
+  ++i; //skip test name
+  ++i; //skip executable name
+  for(; i != args.end(); ++i)
+    {
+    commandArgs.push_back(*i);
+    }
+  this->TestProcess = new cmProcess;
+  this->TestProcess->SetId(this->Index);
+  this->TestProcess->SetCommand(command.c_str());
+  this->TestProcess->SetCommandArguments(commandArgs);
+
   std::vector<std::string> origEnv;
-  bool modifyEnv = (environment && environment->size()>0);
+  this->ModifyEnv = (environment && environment->size()>0);
 
   // determine how much time we have
   double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
@@ -395,154 +375,89 @@ int cmCTestRunTest::RunTestProcess(std::vector<const char*> argv,
     {
     timeout = 1;
     }
-  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-             "Test timeout computed to be: " << timeout << "\n");
-
-  if(cmSystemTools::SameFile(argv[0], this->CTest->CTestSelf.c_str()) &&
-     !this->CTest->ForceNewCTestProcess &&
-     this->OptimizeForCTest)
-    {
-    cmCTest inst;
-    inst.ConfigType = this->CTest->ConfigType;
-    inst.TimeOut = timeout;
-
-    // Capture output of the child ctest.
-    cmOStringStream oss;
-    inst.SetStreams(&oss, &oss);
-
-    std::vector<std::string> args;
-    for(unsigned int i =0; i < argv.size(); ++i)
-      {
-      if(argv[i])
-        {
-        // make sure we pass the timeout in for any build and test 
-        // invocations. Since --build-generator is required this is a 
-        // good place to check for it, and to add the arguments in
-        if (strcmp(argv[i],"--build-generator") == 0 && timeout)
-          {
-          args.push_back("--test-timeout");
-          cmOStringStream msg;
-          msg << timeout;
-          args.push_back(msg.str());
-          }
-        args.push_back(argv[i]);
-        }
-      }
-    if ( log )
-      {
-      *log << "* Run internal CTest" << std::endl;
-      }
-    std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory();
-
-    if (modifyEnv)
-      {
-      origEnv = cmSystemTools::AppendEnv(environment);
-      }
-
-    *retVal = inst.Run(args, output);
-    *output += oss.str();
-    if ( log )
-      {
-      *log << output->c_str();
-      }
-    cmSystemTools::ChangeDirectory(oldpath.c_str());
-
-    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-      "Internal cmCTest object used to run test." << std::endl
-      <<  *output << std::endl);
-
-    if (modifyEnv)
-      {
-      cmSystemTools::RestoreEnv(origEnv);
-      }
+  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": "
+             << "Test timeout computed to be: " << timeout << "\n");
 
-    return cmsysProcess_State_Exited;
-    }
-  std::vector<char> tempOutput;
-  if ( output )
+  if (this->ModifyEnv)
     {
-    *output = "";
+    this->OrigEnv = cmSystemTools::AppendEnv(environment);
     }
 
-  if (modifyEnv)
+  return this->TestProcess->StartProcess();
+}
+
+void cmCTestRunTest::WriteLogOutputTop()
+{
+  /* Not sure whether we want to prepend the test index anymore
+  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3)
+             << this->Index << ": ");*/
+  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
+             << this->TestProperties->Index << "/");
+  cmCTestLog(this->CTest, HANDLER_OUTPUT, std::setw(3) 
+             << this->TestHandler->TotalNumberOfTests << " ");
+  if ( this->TestHandler->MemCheck )
     {
-    origEnv = cmSystemTools::AppendEnv(environment);
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory Check");
     }
-
-  cmsysProcess* cp = cmsysProcess_New();
-  cmsysProcess_SetCommand(cp, &*argv.begin());
-  cmCTestLog(this->CTest, DEBUG, "Command is: " << argv[0] << std::endl);
-  if(cmSystemTools::GetRunCommandHideConsole())
+  else
     {
-    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, "Testing");
     }
+  cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+  const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
+  std::string outname = this->TestProperties->Name + " ";
+  outname.resize(maxTestNameWidth, '.');
 
-  cmsysProcess_SetTimeout(cp, timeout);
-  cmsysProcess_Execute(cp);
-
-  char* data;
-  int length;
-  while(cmsysProcess_WaitForData(cp, &data, &length, 0))
+  // add the arguments
+  std::vector<std::string>::const_iterator j = 
+    this->TestProperties->Args.begin();
+  ++j; // skip test name
+  ++j; // skip command as it is in actualCommand
+  std::vector<const char*> arguments;
+  this->TestHandler->GenerateTestCommand(arguments);
+  arguments.push_back(this->ActualCommand.c_str());
+  for(;j != this->TestProperties->Args.end(); ++j)
     {
-    if ( output )
-      {
-      tempOutput.insert(tempOutput.end(), data, data+length);
-      }
-    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-      cmCTestLogWrite(data, length));
-    if ( log )
-      {
-      log->write(data, length);
-      }
+    this->TestCommand += " ";
+    this->TestCommand += cmSystemTools::EscapeSpaces(j->c_str());
+    arguments.push_back(j->c_str());
     }
+  arguments.push_back(0);
+  this->TestResult.FullCommandLine = this->TestCommand;
 
-  cmsysProcess_WaitForExit(cp, 0);
-  if(output && tempOutput.begin() != tempOutput.end())
+  *this->TestHandler->LogFile << this->TestProperties->Index << "/" 
+    << this->TestHandler->TotalNumberOfTests << " Testing: " 
+    << this->TestProperties->Name << std::endl;
+  *this->TestHandler->LogFile << this->TestProperties->Index << "/" 
+    << this->TestHandler->TotalNumberOfTests
+    << " Test: " << this->TestProperties->Name.c_str() << std::endl;
+  *this->TestHandler->LogFile << "Command: ";
+  std::vector<cmStdString>::size_type ll;
+  for ( ll = 0; ll < arguments.size()-1; ll ++ )
     {
-    //We are waiting for exit before finally appending to the output
-    output->append(&*tempOutput.begin(), tempOutput.size());
+    *this->TestHandler->LogFile << "\"" << arguments[ll] << "\" ";
     }
-  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "-- Process completed"
-    << std::endl);
+  *this->TestHandler->LogFile << std::endl
+    << "Directory: " << this->TestProperties->Directory << std::endl
+    << "\"" << this->TestProperties->Name.c_str() << "\" start time: "
+    << this->StartTime << std::endl;
 
-  int result = cmsysProcess_GetState(cp);
+  *this->TestHandler->LogFile
+    << "Output:" << std::endl
+    << "----------------------------------------------------------"
+    << std::endl;
+  *this->TestHandler->LogFile
+    << this->ProcessOutput.c_str() << "<end of output>" << std::endl;
 
-  if(result == cmsysProcess_State_Exited)
-    {
-    *retVal = cmsysProcess_GetExitValue(cp);
-    if(*retVal != 0 && this->CTest->OutputTestOutputOnTestFailure)
-      {
-        this->CTest->OutputTestErrors(tempOutput);
-      }
-    }
-  else if(result == cmsysProcess_State_Exception)
-    {
-    if(this->CTest->OutputTestOutputOnTestFailure)
-      {
-        this->CTest->OutputTestErrors(tempOutput);
-      }
-    *retVal = cmsysProcess_GetExitException(cp);
-    std::string outerr = "\n*** Exception executing: ";
-    outerr += cmsysProcess_GetExceptionString(cp);
-    *output += outerr;
-    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str()
-      << std::endl << std::flush);
-    }
-  else if(result == cmsysProcess_State_Error)
+  if ( this->CTest->GetShowOnly() )
     {
-    std::string outerr = "\n*** ERROR executing: ";
-    outerr += cmsysProcess_GetErrorString(cp);
-    *output += outerr;
-    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, outerr.c_str()
-      << std::endl << std::flush);
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str() << std::endl);
     }
-  cmsysProcess_Delete(cp);
-
-  if (modifyEnv)
+  else
     {
-    cmSystemTools::RestoreEnv(origEnv);
+    cmCTestLog(this->CTest, HANDLER_OUTPUT, outname.c_str());
     }
 
-  return result;
+  cmCTestLog(this->CTest, DEBUG, "Testing " 
+             << this->TestProperties->Name.c_str() << " ... ");
 }
-
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 1438a60..72a108a 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -19,6 +19,7 @@
 
 #include <cmStandardIncludes.h>
 #include <cmCTestTestHandler.h>
+#include <cmProcess.h>
 
 /** \class cmRunTest
  * \brief represents a single test to be run
@@ -38,44 +39,53 @@ public:
   { return this->TestProperties; }
   
   void SetTestHandler(cmCTestTestHandler * handler);
-  
-  void SetOptimizeForCTest(bool optimize)
-  { this->OptimizeForCTest = optimize; }
 
-  bool GetOptimizeForCTest()
-  { return this->OptimizeForCTest; }
+  void SetIndex(int i) { this->Index = i; }
+
+  void SetCTest(cmCTest * ct) { this->CTest = ct; }
 
-  std::string GetProcessOutput()
-  { return this->ProcessOutput; }
+  int GetIndex() { return this->Index; }
 
-  //Provides a handle to the log stream in case someone wants
-  // to asynchronously process the log
-  std::ostream * GetLogStream()
-  { return this->TestHandler->LogFile; }
+  std::string GetProcessOutput() { return this->ProcessOutput; }
 
   cmCTestTestHandler::cmCTestTestResult GetTestResults()
   { return this->TestResult; }
 
-  //Runs the test
-  bool Execute();
+  bool IsRunning();
+  void CheckOutput();
+  //launch the test process, return whether it started correctly
+  bool StartTest();
+  //capture the test results and send them back to the test handler
+  bool EndTest();
 protected:
-  void DartProcessing(std::string& output);
-  int RunTestProcess(std::vector<const char*> argv,
-                     std::string* output, int *retVal,
-                     std::ostream* log, double testTimeOut,
+  void DartProcessing();
+  bool CreateProcess(std::string executable,
+                     std::vector<std::string> args,
+                     double testTimeOut,
                      std::vector<std::string>* environment);
 private:
   cmCTestTestHandler::cmCTestTestProperties * TestProperties;
   //Pointer back to the "parent"; the handler that invoked this test run
   cmCTestTestHandler * TestHandler;
   cmCTest * CTest;
+  cmProcess * TestProcess;
   //If the executable to run is ctest, don't create a new process; 
   //just instantiate a new cmTest.  (Can be disabled for a single test
   //if this option is set to false.)
-  bool OptimizeForCTest;
+  //bool OptimizeForCTest;
+
+  //flag for whether the env was modified for this run
+  bool ModifyEnv;
+  //stores the original environment if we are modifying it
+  std::vector<std::string> OrigEnv;
   std::string ProcessOutput;
   //The test results
   cmCTestTestHandler::cmCTestTestResult TestResult;
+  int Index;
+  std::string StartTime;
+  std::string TestCommand;
+  std::string ActualCommand;
+  void WriteLogOutputTop();
 };
 
 #endif
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 62b111f..6df925c 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -543,8 +543,15 @@ int cmCTestTestHandler::ProcessHandler()
   std::vector<cmStdString> passed;
   std::vector<cmStdString> failed;
   int total;
+
+  //start the real time clock
+  double clock_start, clock_finish;
+  clock_start = cmSystemTools::GetTime();
+
   this->ProcessDirectory(passed, failed);
 
+  clock_finish = cmSystemTools::GetTime();
+
   total = int(passed.size()) + int(failed.size());
 
   if (total == 0)
@@ -591,10 +598,15 @@ int cmCTestTestHandler::ProcessHandler()
         totalTestTime += result->ExecutionTime;
         }
       
-      char buf[1024];
-      sprintf(buf, "%6.2f sec", totalTestTime); 
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time = " 
-                 <<  buf << "\n" );
+      char realBuf[1024];
+      sprintf(realBuf, "%6.2f sec", (double)(clock_finish - clock_start));
+      cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = "
+                 << realBuf << "\n" );
+
+      char totalBuf[1024];
+      sprintf(totalBuf, "%6.2f sec", totalTestTime); 
+      cmCTestLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (parallel) = " 
+                 <<  totalBuf << "\n" );
       
       }
 
@@ -1528,21 +1540,28 @@ std::string cmCTestTestHandler::SaveTestList()
   return fname;
 }
 
-void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
+void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
                                          std::vector<cmStdString> &failed)
 {
   this->ComputeTestList();
   cmCTestMultiProcessHandler parallel;
   parallel.SetCTest(this->CTest);
-  parallel.SetParallelLevel(this->CTest->GetParallelLevel()); 
+  parallel.SetParallelLevel(this->CTest->GetParallelLevel());
+  parallel.SetTestHandler(this);
+
+  *this->LogFile << "Start testing: "
+    << this->CTest->CurrentTime() << std::endl
+    << "----------------------------------------------------------"
+    << std::endl;
+
   cmCTestMultiProcessHandler::TestSet depends;
   cmCTestMultiProcessHandler::TestMap tests;
-  std::map<int, cmStdString> testnames;
+  cmCTestMultiProcessHandler::PropertiesMap properties;
   for (ListOfTests::iterator it = this->TestList.begin();
        it != this->TestList.end(); it ++ )
     { 
     cmCTestTestProperties& p = *it;
-    testnames[p.Index] = p.Name;
+    
     if(p.Depends.size())
       {
       for(std::vector<std::string>::iterator i = p.Depends.begin();
@@ -1560,76 +1579,16 @@ void cmCTestTestHandler::ProcessParallel(std::vector<cmStdString> &passed,
         }
       }
     tests[it->Index] = depends;
+    properties[it->Index] = &*it;
     }
-  parallel.SetCTestCommand(this->CTest->GetCTestExecutable());
-  parallel.SetTests(tests, testnames);
-  std::string fname = this->SaveTestList();
-  parallel.SetTestCacheFile(fname.c_str());
+  parallel.SetTests(tests, properties);
   parallel.SetPassFailVectors(&passed, &failed);
   this->TestResults.clear();
   parallel.SetTestResults(&this->TestResults);
   parallel.RunTests();
-  cmSystemTools::RemoveFile(fname.c_str());
-}
-
-
-//----------------------------------------------------------------------
-void cmCTestTestHandler::ProcessDirectory(std::vector<cmStdString> &passed,
-                                          std::vector<cmStdString> &failed)
-{
-  if(this->CTest->GetParallelLevel() > 0)
-    {
-    this->ProcessParallel(passed, failed);
-    return;
-    }
-  // save the current working directory
-  std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory();
-  // compute the list of tests to run
-  this->ComputeTestList();
-  this->StartTest = this->CTest->CurrentTime();
-  this->StartTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
-  double elapsed_time_start = cmSystemTools::GetTime();
-  *this->LogFile << "Start testing: " << this->StartTest << std::endl
-    << "----------------------------------------------------------"
-    << std::endl;
-  std::string last_directory = "";
 
-  // run each test
-  for (ListOfTests::iterator it = this->TestList.begin();
-       it != this->TestList.end(); it ++ )
-    {
-    if (!(last_directory == it->Directory))
-      {
-      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-                 "Changing directory into " << it->Directory.c_str() << "\n");
-      *this->LogFile << "Changing directory into: " << it->Directory.c_str()
-                     << std::endl;
-      last_directory = it->Directory;
-      cmSystemTools::ChangeDirectory(it->Directory.c_str());
-      }
-    // process this one test
-    cmCTestRunTest testRun;
-    testRun.SetTestProperties(&(*it));
-    testRun.SetTestHandler(this);
-
-    bool testPassed = testRun.Execute(); //run the test
-    if(testPassed && !this->CTest->GetShowOnly())
-      {
-      passed.push_back(it->Name);
-      }
-    else if(!testPassed)
-      {
-      failed.push_back(it->Name);
-      }
-    }  
-  this->EndTest = this->CTest->CurrentTime();
-  this->EndTestTime = static_cast<unsigned int>(cmSystemTools::GetTime());
-  this->ElapsedTestingTime = cmSystemTools::GetTime() - elapsed_time_start;
-  if ( this->LogFile )
-    {
-    *this->LogFile << "End testing: " << this->EndTest << std::endl;
-    }
-  cmSystemTools::ChangeDirectory(current_dir.c_str());
+  *this->LogFile << "End testing: "
+     << this->CTest->CurrentTime() << std::endl;
 }
 
 //----------------------------------------------------------------------
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 03ce285..a6b8e8e 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -31,6 +31,7 @@ class cmMakefile;
 class cmCTestTestHandler : public cmCTestGenericHandler
 {
   friend class cmCTestRunTest;
+  friend class cmCTestMultiProcessHandler;
 public:
   cmTypeMacro(cmCTestTestHandler, cmCTestGenericHandler);
 
@@ -129,6 +130,7 @@ public:
                                     std::vector<std::string> &extraPaths,
                                     std::vector<std::string> &failed);
 
+  typedef std::vector<cmCTestTestProperties> ListOfTests;
 protected:
   // comput a final test list
   virtual int PreProcessHandler();
@@ -193,7 +195,6 @@ private:
   void ProcessDirectory(std::vector<cmStdString> &passed,
                         std::vector<cmStdString> &failed);
 
-  typedef std::vector<cmCTestTestProperties> ListOfTests;
   /**
    * Get the list of tests in directory and subdirectories.
    */
@@ -221,9 +222,6 @@ private:
   bool GetValue(const char* tag,
                 double& value,
                 std::ifstream& fin);
-  // run in -j N mode
-  void ProcessParallel(std::vector<cmStdString> &passed,
-                       std::vector<cmStdString> &failed);
   /**
    * Find the executable for a test
    */
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index abf47a2..7590772 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -209,7 +209,7 @@ std::string cmCTest::DecodeURL(const std::string& in)
 cmCTest::cmCTest()
 {
   this->ParallelSubprocess     = false;
-  this->ParallelLevel          = 0;
+  this->ParallelLevel          = 1;
   this->SubmitIndex            = 0;
   this->ForceNewCTestProcess   = false;
   this->TomorrowTag            = false;
@@ -292,6 +292,11 @@ cmCTest::~cmCTest()
   this->SetOutputLogFileName(0);
 }
 
+void cmCTest::SetParallelLevel(int level)
+{
+  this->ParallelLevel = level < 1 ? 1 : level;
+}
+
 //----------------------------------------------------------------------------
 cmCTest::Part cmCTest::GetPartFromName(const char* name)
 {
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 2a0d4bf..91a0fc6 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -136,7 +136,7 @@ public:
   void SetTimeOut(double t) { this->TimeOut = t; }
   // how many test to run at the same time
   int GetParallelLevel() { return this->ParallelLevel; }
-  void SetParallelLevel(int t) { this->ParallelLevel = t; }
+  void SetParallelLevel(int);
 
   bool GetParallelSubprocess() { return this->ParallelSubprocess; }
   void SetParallelSubprocess() { this->ParallelSubprocess = true; }
-- 
cgit v0.12