CTest: Track one run number for a repeating test

cmCTestRunTest counted the repetitions of a test with two members whose
meaning overlapped: how many runs were left, and how many there were in
total.  The "(run N/M)" suffix then had to recover N by subtracting one
from the other, and the rule deciding which run prints the "completed/total"
prefix read as a pair of conditions on the remaining count.

Count up instead.  Keep the number of the run being made and the number of
runs the test may be given, and let the rule say which run the prefix
belongs to.
This commit is contained in:
Taylor Braun-Jones
2026-09-18 08:28:41 -04:00
committed by Brad King
parent 670f62d10d
commit 32b25b94d6
3 changed files with 36 additions and 28 deletions
+1 -1
View File
@@ -274,7 +274,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test)
if (this->RepeatMode != cmCTest::Repeat::Never) {
testRun->SetRepeatMode(this->RepeatMode);
testRun->SetNumberOfRuns(this->RepeatCount);
testRun->SetRunNumber(1, this->RepeatCount);
}
if (this->UseResourceSpec) {
testRun->SetUseAllocatedResources(true);
+26 -21
View File
@@ -424,8 +424,7 @@ bool cmCTestRunTest::StartAgain(std::unique_ptr<cmCTestRunTest> runner,
bool cmCTestRunTest::NeedsToRepeat()
{
this->NumberOfRunsLeft--;
if (this->NumberOfRunsLeft == 0) {
if (this->RunNumber == this->RunCount) {
return false;
}
// If a test is marked as NOT_RUN it will not be repeated
@@ -433,9 +432,8 @@ bool cmCTestRunTest::NeedsToRepeat()
if (this->TestResult.Status == cmCTestTestHandler::NOT_RUN) {
return false;
}
// if number of runs left is not 0, and we are running until
// we find a failed (or passed) test, then return true so the test can be
// restarted
// The test has runs left, so run it again if we are running until we find
// a failed (or passed) test.
if ((this->RepeatMode == cmCTest::Repeat::UntilFail &&
this->TestResult.Status == cmCTestTestHandler::COMPLETED) ||
(this->RepeatMode == cmCTest::Repeat::UntilPass &&
@@ -443,6 +441,7 @@ bool cmCTestRunTest::NeedsToRepeat()
(this->RepeatMode == cmCTest::Repeat::AfterTimeout &&
this->TestResult.Status == cmCTestTestHandler::TIMEOUT)) {
this->RunAgain = true;
this->RunNumber++;
return true;
}
return false;
@@ -559,11 +558,10 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
{
this->TotalNumberOfTests = total; // save for rerun case
std::string runIterationSuffix{};
if (this->NumberOfRunsTotal > 1) {
std::string runIterationSuffix;
if (this->RunCount > 1) {
runIterationSuffix =
cmStrCat(" (run ", 1 + this->NumberOfRunsTotal - this->NumberOfRunsLeft,
'/', this->NumberOfRunsTotal, ')');
cmStrCat(" (run ", this->RunNumber, '/', this->RunCount, ')');
}
if (!this->CTest->GetTestProgressOutput()) {
cmCTestLog(
@@ -999,18 +997,25 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
{
std::ostringstream outputStream;
// If this is the last or only run of this test, or progress output is
// requested, then print out completed / total.
// Only issue is if a test fails and we are running until fail
// then it will never print out the completed / total, same would
// got for run until pass. Trick is when this is called we don't
// yet know if we are passing or failing.
bool const progressOnLast =
(this->RepeatMode != cmCTest::Repeat::UntilPass &&
this->RepeatMode != cmCTest::Repeat::AfterTimeout);
if ((progressOnLast && this->NumberOfRunsLeft == 1) ||
(!progressOnLast && this->NumberOfRunsLeft == this->NumberOfRunsTotal) ||
this->CTest->GetTestProgressOutput()) {
// Print "completed/total" on the run whose result is the one recorded for
// the test, and blanks on its other runs. Which run that is has to be
// decided before the run finishes: with until-fail it is the last run, and
// with until-pass and after-timeout the repetitions may end early, so it
// is the first.
bool countThisRun = true;
switch (this->RepeatMode) {
case cmCTest::Repeat::Never:
break;
case cmCTest::Repeat::UntilFail:
countThisRun = this->RunNumber == this->RunCount;
break;
case cmCTest::Repeat::UntilPass:
CM_FALLTHROUGH;
case cmCTest::Repeat::AfterTimeout:
countThisRun = this->RunNumber == 1;
break;
}
if (countThisRun || this->CTest->GetTestProgressOutput()) {
outputStream << std::setw(getNumWidth(total)) << completed << "/";
outputStream << std::setw(getNumWidth(total)) << total << " ";
}
+9 -6
View File
@@ -30,10 +30,13 @@ class cmCTestRunTest
public:
explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler, int index);
void SetNumberOfRuns(int n)
// Report this run as run `number` of `count` in the test's "(run N/M)"
// suffix. A test that repeats on its own starts at run 1 and counts up
// itself.
void SetRunNumber(int number, int count)
{
this->NumberOfRunsLeft = n;
this->NumberOfRunsTotal = n;
this->RunNumber = number;
this->RunCount = count;
}
void SetRepeatMode(cmCTest::Repeat r) { this->RepeatMode = r; }
@@ -158,9 +161,9 @@ private:
std::string, std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>>
AllocatedResources;
cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
int NumberOfRunsLeft = 1; // default to 1 run of the test
int NumberOfRunsTotal = 1; // default to 1 run of the test
bool RunAgain = false; // default to not having to run again
int RunNumber = 1; // which run of the test this is
int RunCount = 1; // how many runs it may be given
bool RunAgain = false;
bool UseLLVMCov = false;
size_t TotalNumberOfTests;
};