cmCTestTestCommand: Factor out preset resolution

Prepare for a future commit which will reuse this functionality. Add a
structure to hold the resolved fields so that we can more easily
distinguish between errors during preset resolution and cases when
presets simply aren't used.
This commit is contained in:
Tyler Yankee
2026-09-16 09:05:32 -04:00
parent 81b46d87ba
commit 277236a99a
2 changed files with 70 additions and 39 deletions
+55 -39
View File
@@ -28,47 +28,48 @@
using TestPreset = cmCMakePresetsGraph::TestPreset;
std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
HandlerArguments& arguments, cmExecutionStatus& status) const
cm::optional<cmCTestTestCommand::ResolvedTestPreset>
cmCTestTestCommand::ResolveTestPreset(cmMakefile& mf,
std::string const& presetArg,
std::string const& presetsFileArg,
cmExecutionStatus& status) const
{
cmMakefile& mf = status.GetMakefile();
auto& args = static_cast<TestArguments&>(arguments);
std::string const sourceDirectory =
mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
ResolvedTestPreset resolved;
resolved.SourceDirectory = mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
// Presets file is set according to the following priority order:
// 1) The PRESETS_FILE option to ctest_test()
// 2) CTEST_PRESETS_FILE script variable
std::string const rawPresetsFile = !args.PresetsFile.empty()
? args.PresetsFile
std::string const rawPresetsFile = !presetsFileArg.empty()
? presetsFileArg
: mf.GetSafeDefinition("CTEST_PRESETS_FILE");
std::string const presetsFile = rawPresetsFile.empty()
resolved.PresetsFile = rawPresetsFile.empty()
? ""
: cmSystemTools::CollapseFullPath(rawPresetsFile, sourceDirectory);
: cmSystemTools::CollapseFullPath(rawPresetsFile,
resolved.SourceDirectory);
// Preset name is set according to the following priority order:
// 1) The PRESET option to ctest_test()
// 2) CTEST_TEST_PRESET script variable
// 3) CTEST_PRESET script variable (a warning is emitted if no test preset
// exists with this name)
std::string effectivePreset = !args.Preset.empty() ? args.Preset
resolved.EffectivePreset = !presetArg.empty() ? presetArg
: cmNonempty(mf.GetDefinition("CTEST_TEST_PRESET"))
? *mf.GetDefinition("CTEST_TEST_PRESET")
: "";
if (effectivePreset.empty()) {
if (resolved.EffectivePreset.empty()) {
cmValue v = mf.GetDefinition("CTEST_PRESET");
if (cmNonempty(v)) {
std::string presetError;
auto presetCheck =
TestPresetExists(*v, sourceDirectory, presetsFile, presetError);
auto presetCheck = TestPresetExists(*v, resolved.SourceDirectory,
resolved.PresetsFile, presetError);
if (presetCheck == PresetCheckResult::ReadError) {
status.SetError(cmStrCat('\n', presetError));
return nullptr;
return cm::nullopt;
}
if (presetCheck == PresetCheckResult::Found) {
effectivePreset = *v;
resolved.EffectivePreset = *v;
} else {
cmCTestLog(this->CTest, WARNING,
"No test preset named \""
@@ -77,30 +78,45 @@ std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
}
}
std::unique_ptr<cmCMakePresetsGraph> presetsGraph;
TestPreset const* expandedPreset = nullptr;
if (!effectivePreset.empty()) {
presetsGraph = cm::make_unique<cmCMakePresetsGraph>();
if (!presetsGraph->ReadProjectPresets(sourceDirectory, presetsFile)) {
status.SetError(cmStrCat("\n Could not read presets from \"",
sourceDirectory, "\":\n ",
presetsGraph->parseState.GetErrorMessage()));
return nullptr;
}
auto resolveResult =
presetsGraph->ResolvePreset(effectivePreset, presetsGraph->TestPresets);
auto resolveError = cmCMakePresetsGraph::FormatPresetError<TestPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
sourceDirectory);
if (resolveError) {
status.SetError(*resolveError);
return nullptr;
}
expandedPreset = resolveResult.Preset;
if (resolved.EffectivePreset.empty()) {
return cm::optional<ResolvedTestPreset>(std::move(resolved));
}
resolved.PresetsGraph = cm::make_unique<cmCMakePresetsGraph>();
if (!resolved.PresetsGraph->ReadProjectPresets(resolved.SourceDirectory,
resolved.PresetsFile)) {
status.SetError(
cmStrCat("\n Could not read presets from \"", resolved.SourceDirectory,
"\":\n ", resolved.PresetsGraph->parseState.GetErrorMessage()));
return cm::nullopt;
}
auto resolveResult = resolved.PresetsGraph->ResolvePreset(
resolved.EffectivePreset, resolved.PresetsGraph->TestPresets);
auto resolveError = cmCMakePresetsGraph::FormatPresetError<TestPreset>(
resolveResult.StatusCode, resolveResult.ErrorPresetName,
resolved.SourceDirectory);
if (resolveError) {
status.SetError(*resolveError);
return cm::nullopt;
}
resolved.ExpandedPreset = resolveResult.Preset;
return cm::optional<ResolvedTestPreset>(std::move(resolved));
}
std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
HandlerArguments& arguments, cmExecutionStatus& status) const
{
cmMakefile& mf = status.GetMakefile();
auto& args = static_cast<TestArguments&>(arguments);
auto resolvedPreset =
ResolveTestPreset(mf, args.Preset, args.PresetsFile, status);
if (!resolvedPreset) {
return nullptr;
}
TestPreset const* expandedPreset = resolvedPreset->ExpandedPreset;
cmValue ctestTimeout = mf.GetDefinition("CTEST_TEST_TIMEOUT");
cmDuration timeout;
+15
View File
@@ -13,10 +13,12 @@
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmCMakePresetsGraph.h"
#include "cmCTestHandlerCommand.h"
class cmExecutionStatus;
class cmCTestTestHandler;
class cmMakefile;
class cmCTestTestCommand : public cmCTestHandlerCommand
{
@@ -86,6 +88,19 @@ protected:
private:
std::string GetName() const override { return "ctest_test"; }
struct ResolvedTestPreset
{
std::string SourceDirectory;
std::string PresetsFile;
std::string EffectivePreset;
std::unique_ptr<cmCMakePresetsGraph> PresetsGraph;
cmCMakePresetsGraph::TestPreset const* ExpandedPreset = nullptr;
};
cm::optional<ResolvedTestPreset> ResolveTestPreset(
cmMakefile& mf, std::string const& presetArg,
std::string const& presetsFileArg, cmExecutionStatus& status) const;
virtual std::unique_ptr<cmCTestTestHandler> InitializeActualHandler(
HandlerArguments& arguments, cmExecutionStatus& status) const;