ctest: Honor --interactive-debug-mode in dashboard and script modes

ctest_start() and -D/-M were resetting the mode through SetTestModel,
so an explicit --interactive-debug-mode got lost.  We now keep the
user's value separately and GetInteractiveDebugMode() prefers it.
Also made ProcessSteps go through the same getter, so under -T ctest
and its tests no longer end up in different modes.

Fixes: #28107
This commit is contained in:
15daksh-2003 committed 2026-09-23 21:14:35 +05:30
1 parent de8a69ce2d
commit 273ef22e84
5 files changed
+133 -7

No files matched your search

+16 -7
View File
@@ -183,7 +183,9 @@ struct cmCTest::Private
std::string NotesFiles;
// Default for the current mode; an explicit user choice takes precedence.
bool InteractiveDebugMode = true;
cm::optional<bool> InteractiveDebugModeCli;
bool ShortDateFormat = true;
@@ -451,7 +453,7 @@ void cmCTest::Initialize(std::string const& binary_dir)
this->Impl->Parts[p].SubmitFiles.clear();
}
if (!this->Impl->InteractiveDebugMode) {
if (!this->GetInteractiveDebugMode()) {
this->BlockTestErrorDiagnostics();
} else {
cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
@@ -766,12 +768,18 @@ int cmCTest::ProcessSteps()
this->Impl->ExtraVerbose = this->Impl->Verbose;
this->Impl->Verbose = true;
this->Impl->ProduceXML = true;
// Dashboard mode defaults to non-interactive even if no model is set.
this->Impl->InteractiveDebugMode = false;
// Minimal dashboard client script configuration.
this->SetCTestConfiguration("BuildDirectory", this->Impl->BinaryDir);
this->UpdateCTestConfiguration();
this->BlockTestErrorDiagnostics();
if (!this->GetInteractiveDebugMode()) {
this->BlockTestErrorDiagnostics();
} else {
cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
}
if (this->GetCTestConfiguration("TimeOut").empty()) {
this->SetCTestConfiguration(
@@ -1834,8 +1842,8 @@ bool cmCTest::SetArgsFromPreset(cmCMakePresetsArgs const& args)
}
if (expandedPreset->Execution->InteractiveDebugging) {
this->Impl->InteractiveDebugMode =
*expandedPreset->Execution->InteractiveDebugging;
this->Impl->InteractiveDebugModeCli =
expandedPreset->Execution->InteractiveDebugging;
}
if (expandedPreset->Execution->ScheduleRandom.value_or(false)) {
@@ -2461,7 +2469,7 @@ int cmCTest::Run(std::vector<std::string> const& args)
CommandArgument{ "--max-width", CommandArgument::Values::One, dashW },
CommandArgument{ "--interactive-debug-mode", CommandArgument::Values::One,
[this](std::string const& idm) -> bool {
this->Impl->InteractiveDebugMode = cmIsOn(idm);
this->Impl->InteractiveDebugModeCli = cmIsOn(idm);
return true;
} },
CommandArgument{ "--http-header", CommandArgument::Values::One,
@@ -2780,7 +2788,7 @@ int cmCTest::ExecuteTests(std::vector<std::string> const& args)
this->Impl->Verbose = true;
cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
if (!this->Impl->InteractiveDebugMode) {
if (!this->GetInteractiveDebugMode()) {
this->BlockTestErrorDiagnostics();
} else {
cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
@@ -3244,7 +3252,8 @@ bool cmCTest::GetExtraVerbose() const
bool cmCTest::GetInteractiveDebugMode() const
{
return this->Impl->InteractiveDebugMode;
return this->Impl->InteractiveDebugModeCli.value_or(
this->Impl->InteractiveDebugMode);
}
bool cmCTest::GetLabelSummary() const
+5
View File
@@ -1263,6 +1263,11 @@ set(CTestCommandLine_ARGS
if(NOT CMake_TEST_EXTERNAL_CMAKE)
list(APPEND CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>)
endif()
# Tests inherit ctest's error mode only through a flag of the bundled libuv.
if(WIN32 AND NOT CMAKE_USE_SYSTEM_LIBUV)
add_executable(testErrorMode testErrorMode.c)
list(APPEND CTestCommandLine_ARGS -DTEST_ERROR_MODE=$<TARGET_FILE:testErrorMode>)
endif()
add_executable(print_stdin print_stdin.c)
add_RunCMake_test(CTestCommandLine -DTEST_PRINT_STDIN=$<TARGET_FILE:print_stdin>)
add_RunCMake_test(CacheNewline)
@@ -0,0 +1,18 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"binaryDir": "${sourceDir}"
}
],
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"execution": {
"interactiveDebugging": false
}
}
]
}
@@ -1072,6 +1072,59 @@ block()
-T Test)
endblock()
# CTest itself and the tests it runs must agree on the debug mode: tests see
# only that mode's environment marker and, on Windows, its error mode.
function(run_InteractiveDebugMode case mode)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/InteractiveDebugMode-${case})
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
if(mode STREQUAL "interactive")
set(expect_env "CTEST_INTERACTIVE_DEBUG_MODE=1")
set(reject_env "DASHBOARD_TEST_FROM_CTEST=")
else()
set(expect_env "DASHBOARD_TEST_FROM_CTEST=")
set(reject_env "CTEST_INTERACTIVE_DEBUG_MODE=")
endif()
set(tests "
add_test(env \"${CMAKE_COMMAND}\" -E environment)
set_tests_properties(env PROPERTIES
PASS_REGULAR_EXPRESSION \"${expect_env}\"
FAIL_REGULAR_EXPRESSION \"${reject_env}\")
")
if(TEST_ERROR_MODE)
string(APPEND tests "add_test(error-mode \"${TEST_ERROR_MODE}\" ${mode})\n")
endif()
file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "${tests}")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/DartConfiguration.tcl"
"BuildDirectory: ${RunCMake_TEST_BINARY_DIR}\n"
"SourceDirectory: ${RunCMake_TEST_BINARY_DIR}\n")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/script.cmake" "
set(CTEST_SOURCE_DIRECTORY \"${RunCMake_TEST_BINARY_DIR}\")
set(CTEST_BINARY_DIRECTORY \"${RunCMake_TEST_BINARY_DIR}\")
ctest_start(Experimental)
ctest_test(RETURN_VALUE rv)
if(rv)
message(FATAL_ERROR \"ctest_test failed: \${rv}\")
endif()
")
set(presets "${RunCMake_SOURCE_DIR}/InteractiveDebugMode-${case}-CMakePresets.json.in")
if(EXISTS "${presets}")
configure_file("${presets}" "${RunCMake_TEST_BINARY_DIR}/CMakePresets.json" @ONLY)
endif()
# CTest never unsets these, so an outer CTest would leak them into the case.
unset(ENV{DASHBOARD_TEST_FROM_CTEST})
unset(ENV{DART_TEST_FROM_DART})
unset(ENV{CTEST_INTERACTIVE_DEBUG_MODE})
run_cmake_command(InteractiveDebugMode-${case} ${CMAKE_CTEST_COMMAND} ${ARGN})
endfunction()
run_InteractiveDebugMode(Default interactive)
run_InteractiveDebugMode(PresetOff non-interactive --preset=default)
run_InteractiveDebugMode(Script non-interactive -S script.cmake)
run_InteractiveDebugMode(ScriptOn interactive -S script.cmake --interactive-debug-mode 1)
run_InteractiveDebugMode(DashT non-interactive -T Test)
run_InteractiveDebugMode(OnDashD interactive --interactive-debug-mode 1 -D ExperimentalTest)
# Test --output-junit
function(run_output_junit)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/output-junit)
+41
View File
@@ -0,0 +1,41 @@
#if defined(_MSC_VER) && _MSC_VER >= 1928
# pragma warning(disable : 5105) /* macro expansion warning in windows.h */
#endif
#include <windows.h>
#include <stdio.h>
#include <string.h>
/* Verify that a test process inherited the error mode of its CTest mode. */
int main(int argc, char** argv)
{
UINT mode;
int expectSuppressed;
int suppressed;
if (argc != 2) {
fprintf(stderr, "usage: testErrorMode interactive|non-interactive\n");
return 2;
}
if (strcmp(argv[1], "interactive") == 0) {
expectSuppressed = 0;
} else if (strcmp(argv[1], "non-interactive") == 0) {
expectSuppressed = 1;
} else {
fprintf(stderr, "unknown mode: %s\n", argv[1]);
return 2;
}
/* Older MinGW-w64 headers declare GetErrorMode only for Vista+. */
mode = SetErrorMode(0);
SetErrorMode(mode);
suppressed = (mode & SEM_NOGPFAULTERRORBOX) != 0;
if (suppressed != expectSuppressed) {
fprintf(stderr, "SEM_NOGPFAULTERRORBOX is %s, expected %s\n",
suppressed ? "set" : "clear", expectSuppressed ? "set" : "clear");
return 1;
}
return 0;
}