summaryrefslogtreecommitdiffstats
path: root/Source/CTest/cmCTestRunTest.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest/cmCTestRunTest.cxx')
-rw-r--r--Source/CTest/cmCTestRunTest.cxx212
1 files changed, 117 insertions, 95 deletions
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 0c4269e..a056f4b 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -1,5 +1,9 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#ifdef _WIN32
+/* windows.h defines min() and max() macros that interfere. */
+#define NOMINMAX
+#endif
#include "cmCTestRunTest.h"
#include "cmCTest.h"
@@ -9,12 +13,13 @@
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
-#include "cmConfigure.h"
#include "cm_curl.h"
#include "cm_zlib.h"
#include "cmsys/Base64.h"
#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
+#include <chrono>
#include <iomanip>
#include <sstream>
#include <stdio.h>
@@ -25,14 +30,14 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
{
this->CTest = handler->CTest;
this->TestHandler = handler;
- this->TestProcess = CM_NULLPTR;
- this->TestResult.ExecutionTime = 0;
+ this->TestProcess = nullptr;
+ this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
this->TestResult.ReturnValue = 0;
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
this->TestResult.TestCount = 0;
- this->TestResult.Properties = CM_NULLPTR;
- this->ProcessOutput = "";
- this->CompressedOutput = "";
+ this->TestResult.Properties = nullptr;
+ this->ProcessOutput.clear();
+ this->CompressedOutput.clear();
this->CompressionRatio = 2;
this->StopTimePassed = false;
this->NumberOfRunsLeft = 1; // default to 1 run of the test
@@ -47,10 +52,11 @@ cmCTestRunTest::~cmCTestRunTest()
bool cmCTestRunTest::CheckOutput()
{
// Read lines for up to 0.1 seconds of total time.
- double timeout = 0.1;
- double timeEnd = cmSystemTools::GetTime() + timeout;
+ std::chrono::duration<double> timeout = std::chrono::milliseconds(100);
+ auto timeEnd = std::chrono::steady_clock::now() + timeout;
std::string line;
- while ((timeout = timeEnd - cmSystemTools::GetTime(), timeout > 0)) {
+ while ((timeout = timeEnd - std::chrono::steady_clock::now(),
+ timeout > std::chrono::seconds(0))) {
int p = this->TestProcess->GetNextOutputLine(line, timeout);
if (p == cmsysProcess_Pipe_None) {
// Process has terminated and all output read.
@@ -65,16 +71,14 @@ bool cmCTestRunTest::CheckOutput()
// Check for TIMEOUT_AFTER_MATCH property.
if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
- std::vector<
- std::pair<cmsys::RegularExpression, std::string> >::iterator regIt;
- for (regIt = this->TestProperties->TimeoutRegularExpressions.begin();
- regIt != this->TestProperties->TimeoutRegularExpressions.end();
- ++regIt) {
- if (regIt->first.find(this->ProcessOutput.c_str())) {
+ for (auto& reg : this->TestProperties->TimeoutRegularExpressions) {
+ if (reg.first.find(this->ProcessOutput.c_str())) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
<< ": "
<< "Test timeout changed to "
- << this->TestProperties->AlternateTimeout
+ << std::chrono::duration_cast<std::chrono::seconds>(
+ this->TestProperties->AlternateTimeout)
+ .count()
<< std::endl);
this->TestProcess->ResetStartTime();
this->TestProcess->ChangeTimeout(
@@ -164,18 +168,14 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
int res =
started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error;
int retVal = this->TestProcess->GetExitValue();
- std::vector<std::pair<cmsys::RegularExpression, std::string> >::iterator
- passIt;
bool forceFail = false;
bool skipped = false;
bool outputTestErrorsToConsole = false;
if (!this->TestProperties->RequiredRegularExpressions.empty() &&
this->FailedDependencies.empty()) {
bool found = false;
- for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
- passIt != this->TestProperties->RequiredRegularExpressions.end();
- ++passIt) {
- if (passIt->first.find(this->ProcessOutput.c_str())) {
+ for (auto& pass : this->TestProperties->RequiredRegularExpressions) {
+ if (pass.first.find(this->ProcessOutput.c_str())) {
found = true;
reason = "Required regular expression found.";
break;
@@ -186,23 +186,19 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
forceFail = true;
}
reason += "Regex=[";
- for (passIt = this->TestProperties->RequiredRegularExpressions.begin();
- passIt != this->TestProperties->RequiredRegularExpressions.end();
- ++passIt) {
- reason += passIt->second;
+ for (auto& pass : this->TestProperties->RequiredRegularExpressions) {
+ reason += pass.second;
reason += "\n";
}
reason += "]";
}
if (!this->TestProperties->ErrorRegularExpressions.empty() &&
this->FailedDependencies.empty()) {
- for (passIt = this->TestProperties->ErrorRegularExpressions.begin();
- passIt != this->TestProperties->ErrorRegularExpressions.end();
- ++passIt) {
- if (passIt->first.find(this->ProcessOutput.c_str())) {
+ for (auto& pass : this->TestProperties->ErrorRegularExpressions) {
+ if (pass.first.find(this->ProcessOutput.c_str())) {
reason = "Error regular expression found in output.";
reason += " Regex=[";
- reason += passIt->second;
+ reason += pass.second;
reason += "]";
forceFail = true;
break;
@@ -237,6 +233,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
} else if (res == cmsysProcess_State_Exception) {
outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
+ this->TestResult.ExceptionStatus =
+ this->TestProcess->GetExitExceptionString();
switch (this->TestProcess->GetExitException()) {
case cmsysProcess_Exception_Fault:
cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
@@ -255,7 +253,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
this->TestResult.Status = cmCTestTestHandler::NUMERICAL;
break;
default:
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Other");
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ this->TestResult.ExceptionStatus);
this->TestResult.Status = cmCTestTestHandler::OTHER_FAULT;
}
} else if ("Disabled" == this->TestResult.CompletionStatus) {
@@ -267,7 +266,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED;
char buf[1024];
- sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime());
+ sprintf(buf, "%6.2f sec",
+ double(std::chrono::duration_cast<std::chrono::milliseconds>(
+ this->TestProcess->GetTotalTime())
+ .count()) /
+ 1000.0);
cmCTestLog(this->CTest, HANDLER_OUTPUT, buf << "\n");
if (outputTestErrorsToConsole) {
@@ -303,12 +306,16 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
reasonType = "Test Fail Reason";
pass = false;
}
- 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;
+ auto ttime = this->TestProcess->GetTotalTime();
+ auto hours = std::chrono::duration_cast<std::chrono::hours>(ttime);
+ ttime -= hours;
+ auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ttime);
+ ttime -= minutes;
+ auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ttime);
char buffer[100];
- sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+ sprintf(buffer, "%02d:%02d:%02d", static_cast<unsigned>(hours.count()),
+ static_cast<unsigned>(minutes.count()),
+ static_cast<unsigned>(seconds.count()));
*this->TestHandler->LogFile
<< "----------------------------------------------------------"
<< std::endl;
@@ -388,7 +395,11 @@ void cmCTestRunTest::ComputeWeightedCost()
{
double prev = static_cast<double>(this->TestProperties->PreviousRuns);
double avgcost = static_cast<double>(this->TestProperties->Cost);
- double current = this->TestResult.ExecutionTime;
+ double current =
+ double(std::chrono::duration_cast<std::chrono::milliseconds>(
+ this->TestResult.ExecutionTime)
+ .count()) /
+ 1000.0;
if (this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
this->TestProperties->Cost =
@@ -426,7 +437,7 @@ bool cmCTestRunTest::StartTest(size_t total)
// Return immediately if test is disabled
if (this->TestProperties->Disabled) {
this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = 0;
+ this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
this->TestResult.CompressOutput = false;
this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Disabled";
@@ -436,14 +447,12 @@ bool cmCTestRunTest::StartTest(size_t total)
this->TestResult.Path = this->TestProperties->Directory;
this->TestProcess = new cmProcess;
this->TestResult.Output = "Disabled";
- this->TestResult.FullCommandLine = "";
+ this->TestResult.FullCommandLine.clear();
return false;
}
- this->ComputeArguments();
- std::vector<std::string>& args = this->TestProperties->Args;
this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = 0;
+ this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
this->TestResult.CompressOutput = false;
this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Failed to start";
@@ -452,23 +461,27 @@ bool cmCTestRunTest::StartTest(size_t total)
this->TestResult.Name = this->TestProperties->Name;
this->TestResult.Path = this->TestProperties->Directory;
+ // Check for failed fixture dependencies before we even look at the command
+ // arguments because if we are not going to run the test, the command and
+ // its arguments are irrelevant. This matters for the case where a fixture
+ // dependency might be creating the executable we want to run.
if (!this->FailedDependencies.empty()) {
this->TestProcess = new cmProcess;
std::string msg = "Failed test dependencies:";
- for (std::set<std::string>::const_iterator it =
- this->FailedDependencies.begin();
- it != this->FailedDependencies.end(); ++it) {
- msg += " " + *it;
+ for (std::string const& failedDep : this->FailedDependencies) {
+ msg += " " + failedDep;
}
*this->TestHandler->LogFile << msg << std::endl;
cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl);
this->TestResult.Output = msg;
- this->TestResult.FullCommandLine = "";
+ this->TestResult.FullCommandLine.clear();
this->TestResult.CompletionStatus = "Fixture dependency failed";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
}
+ this->ComputeArguments();
+ std::vector<std::string>& args = this->TestProperties->Args;
if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") {
this->TestProcess = new cmProcess;
std::string msg;
@@ -483,18 +496,14 @@ bool cmCTestRunTest::StartTest(size_t total)
*this->TestHandler->LogFile << msg << std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl);
this->TestResult.Output = msg;
- this->TestResult.FullCommandLine = "";
+ this->TestResult.FullCommandLine.clear();
this->TestResult.CompletionStatus = "Missing Configuration";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
}
// Check if all required files exist
- for (std::vector<std::string>::iterator i =
- this->TestProperties->RequiredFiles.begin();
- i != this->TestProperties->RequiredFiles.end(); ++i) {
- std::string file = *i;
-
+ for (std::string const& file : this->TestProperties->RequiredFiles) {
if (!cmSystemTools::FileExists(file.c_str())) {
// Required file was not found
this->TestProcess = new cmProcess;
@@ -503,14 +512,14 @@ bool cmCTestRunTest::StartTest(size_t total)
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Unable to find required file: " << file << std::endl);
this->TestResult.Output = "Unable to find required file: " + file;
- this->TestResult.FullCommandLine = "";
+ this->TestResult.FullCommandLine.clear();
this->TestResult.CompletionStatus = "Required Files Missing";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
}
}
// log and return if we did not find the executable
- if (this->ActualCommand == "") {
+ if (this->ActualCommand.empty()) {
// if the command was not found create a TestResult object
// that has that information
this->TestProcess = new cmProcess;
@@ -519,14 +528,14 @@ bool cmCTestRunTest::StartTest(size_t total)
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Unable to find executable: " << args[1] << std::endl);
this->TestResult.Output = "Unable to find executable: " + args[1];
- this->TestResult.FullCommandLine = "";
+ this->TestResult.FullCommandLine.clear();
this->TestResult.CompletionStatus = "Unable to find executable";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
}
this->StartTime = this->CTest->CurrentTime();
- double timeout = this->ResolveTimeout();
+ auto timeout = this->ResolveTimeout();
if (this->StopTimePassed) {
return false;
@@ -558,10 +567,9 @@ void cmCTestRunTest::ComputeArguments()
// Prepends memcheck args to our command string
this->TestHandler->GenerateTestCommand(this->Arguments, this->Index);
- for (std::vector<std::string>::iterator i = this->Arguments.begin();
- i != this->Arguments.end(); ++i) {
+ for (std::string const& arg : this->Arguments) {
testCommand += " \"";
- testCommand += *i;
+ testCommand += arg;
testCommand += "\"";
}
@@ -585,10 +593,8 @@ void cmCTestRunTest::ComputeArguments()
<< ": "
<< "Environment variables: " << std::endl);
}
- for (std::vector<std::string>::const_iterator e =
- this->TestProperties->Environment.begin();
- e != this->TestProperties->Environment.end(); ++e) {
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " << *e
+ for (std::string const& env : this->TestProperties->Environment) {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " << env
<< std::endl);
}
}
@@ -610,15 +616,15 @@ void cmCTestRunTest::DartProcessing()
}
}
-double cmCTestRunTest::ResolveTimeout()
+std::chrono::duration<double> cmCTestRunTest::ResolveTimeout()
{
- double timeout = this->TestProperties->Timeout;
+ auto timeout = this->TestProperties->Timeout;
- if (this->CTest->GetStopTime() == "") {
+ if (this->CTest->GetStopTime().empty()) {
return timeout;
}
struct tm* lctime;
- time_t current_time = time(CM_NULLPTR);
+ time_t current_time = time(nullptr);
lctime = gmtime(&current_time);
int gm_hour = lctime->tm_hour;
time_t gm_time = mktime(lctime);
@@ -642,31 +648,37 @@ double cmCTestRunTest::ResolveTimeout()
lctime->tm_mon + 1, lctime->tm_mday,
this->CTest->GetStopTime().c_str(), tzone_offset);
- time_t stop_time = curl_getdate(buf, &current_time);
- if (stop_time == -1) {
+ time_t stop_time_t = curl_getdate(buf, &current_time);
+ if (stop_time_t == -1) {
return timeout;
}
+ auto stop_time = std::chrono::system_clock::from_time_t(stop_time_t);
+
// the stop time refers to the next day
if (this->CTest->NextDayStopTime) {
- stop_time += 24 * 60 * 60;
+ stop_time += std::chrono::hours(24);
}
- int stop_timeout =
- static_cast<int>(stop_time - current_time) % (24 * 60 * 60);
+ auto stop_timeout =
+ (stop_time - std::chrono::system_clock::from_time_t(current_time)) %
+ std::chrono::hours(24);
this->CTest->LastStopTimeout = stop_timeout;
- if (stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout) {
+ if (stop_timeout <= std::chrono::duration<double>::zero() ||
+ stop_timeout > this->CTest->LastStopTimeout) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
"Stopping all tests."
<< std::endl);
this->StopTimePassed = true;
- return 0;
+ return std::chrono::duration<double>::zero();
}
- return timeout == 0 ? stop_timeout
- : (timeout < stop_timeout ? timeout : stop_timeout);
+ return timeout == std::chrono::duration<double>::zero()
+ ? stop_timeout
+ : (timeout < stop_timeout ? timeout : stop_timeout);
}
-bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout,
+bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
+ bool explicitTimeout,
std::vector<std::string>* environment)
{
this->TestProcess = new cmProcess;
@@ -677,26 +689,37 @@ bool cmCTestRunTest::ForkProcess(double testTimeOut, bool explicitTimeout,
this->TestProcess->SetCommandArguments(this->Arguments);
// determine how much time we have
- double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
- if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout) {
+ std::chrono::duration<double> timeout =
+ std::min<std::chrono::duration<double>>(
+ this->CTest->GetRemainingTimeAllowed(), std::chrono::minutes(2));
+ if (this->CTest->GetTimeOut() > std::chrono::duration<double>::zero() &&
+ this->CTest->GetTimeOut() < timeout) {
timeout = this->CTest->GetTimeOut();
}
- if (testTimeOut > 0 &&
+ if (testTimeOut > std::chrono::duration<double>::zero() &&
testTimeOut < this->CTest->GetRemainingTimeAllowed()) {
timeout = testTimeOut;
}
// always have at least 1 second if we got to here
- if (timeout <= 0) {
- timeout = 1;
+ if (timeout <= std::chrono::duration<double>::zero()) {
+ timeout = std::chrono::seconds(1);
}
// handle timeout explicitly set to 0
- if (testTimeOut == 0 && explicitTimeout) {
- timeout = 0;
- }
- cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
- << ": "
- << "Test timeout computed to be: " << timeout << "\n",
- this->TestHandler->GetQuiet());
+ if (testTimeOut == std::chrono::duration<double>::zero() &&
+ explicitTimeout) {
+ timeout = std::chrono::duration<double>::zero();
+ }
+ cmCTestOptionalLog(
+ this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index
+ << ": "
+ << "Test timeout computed to be: "
+ << (timeout == std::chrono::duration<double>::max()
+ ? std::string("infinite")
+ : std::to_string(
+ std::chrono::duration_cast<std::chrono::seconds>(timeout)
+ .count()))
+ << "\n",
+ this->TestHandler->GetQuiet());
this->TestProcess->SetTimeout(timeout);
@@ -762,9 +785,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
<< std::endl;
*this->TestHandler->LogFile << "Command: \"" << this->ActualCommand << "\"";
- for (std::vector<std::string>::iterator i = this->Arguments.begin();
- i != this->Arguments.end(); ++i) {
- *this->TestHandler->LogFile << " \"" << *i << "\"";
+ for (std::string const& arg : this->Arguments) {
+ *this->TestHandler->LogFile << " \"" << arg << "\"";
}
*this->TestHandler->LogFile
<< std::endl