浏览代码

Refactor: Split JSON processing into configure, build, and test presets

Split up the file so that it won't be too big on some systems.
Kyle Edwards 3 年之前
父节点
当前提交
84d440caac

+ 3 - 0
Source/CMakeLists.txt

@@ -165,6 +165,9 @@ set(SRCS
   cmCMakePresetsGraph.h
   cmCMakePresetsGraphInternal.h
   cmCMakePresetsGraphReadJSON.cxx
+  cmCMakePresetsGraphReadJSONBuildPresets.cxx
+  cmCMakePresetsGraphReadJSONConfigurePresets.cxx
+  cmCMakePresetsGraphReadJSONTestPresets.cxx
   cmCommandArgumentParserHelper.cxx
   cmCommonTargetGenerator.cxx
   cmCommonTargetGenerator.h

+ 51 - 0
Source/cmCMakePresetsGraphInternal.h

@@ -1,8 +1,13 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/json/value.h>
 
 #include "cmCMakePresetsGraph.h"
+#include "cmJSONHelpers.h"
 
 #define CHECK_OK(expr)                                                        \
   do {                                                                        \
@@ -109,4 +114,50 @@ public:
 
   std::unique_ptr<Condition> SubCondition;
 };
+
+cmCMakePresetsGraph::ReadFileResult PresetStringHelper(
+  std::string& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper(
+  std::vector<std::string>& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out,
+                                                     const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper(
+  cm::optional<bool>& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out,
+                                                    const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper(
+  cm::optional<int>& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper(
+  std::vector<int>& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult ConfigurePresetsHelper(
+  std::vector<cmCMakePresetsGraph::ConfigurePreset>& out,
+  const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult BuildPresetsHelper(
+  std::vector<cmCMakePresetsGraph::BuildPreset>& out,
+  const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult TestPresetsHelper(
+  std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value);
+
+cmJSONHelper<std::nullptr_t, cmCMakePresetsGraph::ReadFileResult> VendorHelper(
+  cmCMakePresetsGraph::ReadFileResult error);
+
+cmCMakePresetsGraph::ReadFileResult PresetConditionHelper(
+  std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
+  const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult PresetVectorOneOrMoreStringHelper(
+  std::vector<std::string>& out, const Json::Value* value);
+
+cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
+  std::map<std::string, cm::optional<std::string>>& out,
+  const Json::Value* value);
 }

+ 104 - 599
Source/cmCMakePresetsGraphReadJSON.cxx

@@ -219,16 +219,6 @@ ReadFileResult ConditionHelper(
   return ReadFileResult::INVALID_CONDITION;
 }
 
-ReadFileResult PresetConditionHelper(
-  std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
-  const Json::Value* value)
-{
-  std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
-  auto result = ConditionHelper(ptr, value);
-  out = std::move(ptr);
-  return result;
-}
-
 ReadFileResult SubConditionHelper(
   std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
   const Json::Value* value)
@@ -242,20 +232,18 @@ ReadFileResult SubConditionHelper(
   return result;
 }
 
-cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
+ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
+                                 const Json::Value* value)
 {
-  return [error](std::nullptr_t& /*out*/,
-                 const Json::Value* value) -> ReadFileResult {
-    if (!value) {
-      return ReadFileResult::READ_OK;
-    }
-
-    if (!value->isObject()) {
-      return error;
-    }
-
+  if (!value || value->isNull()) {
+    out = cm::nullopt;
     return ReadFileResult::READ_OK;
-  };
+  }
+  if (value->isString()) {
+    out = value->asString();
+    return ReadFileResult::READ_OK;
+  }
+  return ReadFileResult::INVALID_PRESET;
 }
 
 auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
@@ -269,635 +257,152 @@ auto const RootVersionHelper =
                                           ReadFileResult::INVALID_ROOT)
     .Bind("version"_s, VersionHelper, false);
 
-auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
-
-ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
-{
-  if (!value) {
-    out.clear();
-    return ReadFileResult::READ_OK;
-  }
+auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
 
-  if (value->isBool()) {
-    out = value->asBool() ? "TRUE" : "FALSE";
-    return ReadFileResult::READ_OK;
-  }
+auto const CMakeVersionHelper =
+  cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
+    .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
+    .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
+    .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
 
-  return VariableStringHelper(out, value);
+auto const RootPresetsHelper =
+  cmJSONObjectHelper<RootPresets, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
+    .Bind<int>("version"_s, nullptr, VersionHelper)
+    .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
+          cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false)
+    .Bind("buildPresets"_s, &RootPresets::BuildPresets,
+          cmCMakePresetsGraphInternal::BuildPresetsHelper, false)
+    .Bind("testPresets"_s, &RootPresets::TestPresets,
+          cmCMakePresetsGraphInternal::TestPresetsHelper, false)
+    .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
+          CMakeVersionHelper, false)
+    .Bind<std::nullptr_t>(
+      "vendor"_s, nullptr,
+      cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
+      false);
 }
 
-auto const VariableObjectHelper =
-  cmJSONObjectHelper<CacheVariable, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
-    .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
-    .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
-
-ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
-                              const Json::Value* value)
+namespace cmCMakePresetsGraphInternal {
+cmCMakePresetsGraph::ReadFileResult PresetStringHelper(
+  std::string& out, const Json::Value* value)
 {
-  if (value->isBool()) {
-    out = CacheVariable{
-      /*Type=*/"BOOL",
-      /*Value=*/value->asBool() ? "TRUE" : "FALSE",
-    };
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isString()) {
-    out = CacheVariable{
-      /*Type=*/"",
-      /*Value=*/value->asString(),
-    };
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isObject()) {
-    out.emplace();
-    return VariableObjectHelper(*out, value);
-  }
-  if (value->isNull()) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-  return ReadFileResult::INVALID_VARIABLE;
-}
-
-auto const VariablesHelper =
-  cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
+  static auto const helper = cmJSONStringHelper<ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
 
-auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
-                                 const Json::Value* value)
-{
-  if (!value || value->isNull()) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isString()) {
-    out = value->asString();
-    return ReadFileResult::READ_OK;
-  }
-  return ReadFileResult::INVALID_PRESET;
+  return helper(out, value);
 }
 
-auto const EnvironmentMapHelper =
-  cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
+cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper(
+  std::vector<std::string>& out, const Json::Value* value)
+{
+  static auto const helper = cmJSONVectorHelper<std::string, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
-    EnvironmentHelper);
+    cmCMakePresetsGraphInternal::PresetStringHelper);
 
-auto const PresetVectorStringHelper =
-  cmJSONVectorHelper<std::string, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
-    PresetStringHelper);
+  return helper(out, value);
+}
 
-ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
-                                                 const Json::Value* value)
+cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out,
+                                                     const Json::Value* value)
 {
-  out.clear();
-  if (!value) {
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isString()) {
-    out.push_back(value->asString());
-    return ReadFileResult::READ_OK;
-  }
+  static auto const helper = cmJSONBoolHelper<ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
 
-  return PresetVectorStringHelper(out, value);
+  return helper(out, value);
 }
 
-auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-auto const PresetOptionalBoolHelper =
-  cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
-                                             PresetBoolHelper);
-
-auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
-  ReadFileResult::READ_OK, PresetIntHelper);
-
-auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
-
-auto const PresetWarningsHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
-    .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
-          PresetOptionalBoolHelper, false)
-    .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
-          PresetOptionalBoolHelper, false)
-    .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
-          PresetOptionalBoolHelper, false)
-    .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
-          PresetOptionalBoolHelper, false);
-
-auto const PresetErrorsHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
-    .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
-          PresetOptionalBoolHelper, false);
-
-auto const PresetDebugHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
-          false)
-    .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
-          PresetOptionalBoolHelper, false)
-    .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
-          false);
-
-ReadFileResult ArchToolsetStrategyHelper(
-  cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
+cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper(
+  cm::optional<bool>& out, const Json::Value* value)
 {
-  if (!value) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
+  static auto const helper = cmJSONOptionalHelper<bool, ReadFileResult>(
+    ReadFileResult::READ_OK, PresetBoolHelper);
 
-  if (value->asString() == "set") {
-    out = ArchToolsetStrategy::Set;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "external") {
-    out = ArchToolsetStrategy::External;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
+  return helper(out, value);
 }
 
-std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
-ArchToolsetHelper(
-  std::string ConfigurePreset::*valueField,
-  cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
+cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out,
+                                                    const Json::Value* value)
 {
-  auto const objectHelper =
-    cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-      .Bind("value", valueField, PresetStringHelper, false)
-      .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
-  return [valueField, strategyField, objectHelper](
-           ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
-    if (!value) {
-      (out.*valueField).clear();
-      out.*strategyField = cm::nullopt;
-      return ReadFileResult::READ_OK;
-    }
-
-    if (value->isString()) {
-      out.*valueField = value->asString();
-      out.*strategyField = cm::nullopt;
-      return ReadFileResult::READ_OK;
-    }
-
-    if (value->isObject()) {
-      return objectHelper(out, value);
-    }
+  static auto const helper = cmJSONIntHelper<ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
 
-    return ReadFileResult::INVALID_PRESET;
-  };
+  return helper(out, value);
 }
 
-auto const ArchitectureHelper = ArchToolsetHelper(
-  &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
-auto const ToolsetHelper = ArchToolsetHelper(
-  &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
-
-auto const ConfigurePresetHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &ConfigurePreset::Inherits,
-          PresetVectorOneOrMoreStringHelper, false)
-    .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
-          false)
-    .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
-          false)
-    .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
-          false)
-    .Bind("architecture"_s, ArchitectureHelper, false)
-    .Bind("toolset"_s, ToolsetHelper, false)
-    .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile,
-          PresetStringHelper, false)
-    .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
-          false)
-    .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper,
-          false)
-    .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
-    .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
-          VariablesHelper, false)
-    .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("warnings"_s, PresetWarningsHelper, false)
-    .Bind("errors"_s, PresetErrorsHelper, false)
-    .Bind("debug"_s, PresetDebugHelper, false)
-    .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
-          PresetConditionHelper, false);
-
-auto const BuildPresetHelper =
-  cmJSONObjectHelper<BuildPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &BuildPreset::Inherits,
-          PresetVectorOneOrMoreStringHelper, false)
-    .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
-          false)
-    .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
-          false)
-    .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
-          PresetStringHelper, false)
-    .Bind("inheritConfigureEnvironment"_s,
-          &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
-          false)
-    .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
-    .Bind("targets"_s, &BuildPreset::Targets,
-          PresetVectorOneOrMoreStringHelper, false)
-    .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
-          false)
-    .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
-          false)
-    .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
-    .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
-          PresetVectorStringHelper, false)
-    .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
-          PresetConditionHelper, false);
-
-ReadFileResult TestPresetOutputVerbosityHelper(
-  TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
+cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper(
+  cm::optional<int>& out, const Json::Value* value)
 {
-  if (!value) {
-    out = TestPreset::OutputOptions::VerbosityEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
+  static auto const helper = cmJSONOptionalHelper<int, ReadFileResult>(
+    ReadFileResult::READ_OK, PresetIntHelper);
 
-  if (value->asString() == "default") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "verbose") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "extra") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Extra;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
+  return helper(out, value);
 }
 
-auto const TestPresetOptionalOutputVerbosityHelper =
-  cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetOutputVerbosityHelper);
-
-auto const TestPresetOptionalOutputHelper =
-  cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-      .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
-            PresetOptionalBoolHelper, false)
-      .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
-            TestPresetOptionalOutputVerbosityHelper, false)
-      .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
-            PresetOptionalBoolHelper, false)
-      .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
-            PresetOptionalBoolHelper, false)
-      .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
-            PresetOptionalBoolHelper, false)
-      .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
-            PresetStringHelper, false)
-      .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
-            PresetOptionalBoolHelper, false)
-      .Bind("subprojectSummary"_s,
-            &TestPreset::OutputOptions::SubprojectSummary,
-            PresetOptionalBoolHelper, false)
-      .Bind("maxPassedTestOutputSize"_s,
-            &TestPreset::OutputOptions::MaxPassedTestOutputSize,
-            PresetOptionalIntHelper, false)
-      .Bind("maxFailedTestOutputSize"_s,
-            &TestPreset::OutputOptions::MaxFailedTestOutputSize,
-            PresetOptionalIntHelper, false)
-      .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
-            PresetOptionalIntHelper, false));
-
-auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
-  cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
-            PresetOptionalIntHelper, false)
-      .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
-            PresetOptionalIntHelper, false)
-      .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
-            PresetOptionalIntHelper, false)
-      .Bind("specificTests"_s,
-            &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
-            PresetVectorIntHelper, false));
-
-ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
-  cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
-  const Json::Value* value)
+cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper(
+  std::vector<int>& out, const Json::Value* value)
 {
-  if (!value) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isString()) {
-    out.emplace();
-    out->IndexFile = value->asString();
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isObject()) {
-    return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
-  }
+  static auto const helper = cmJSONVectorHelper<int, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
 
-  return ReadFileResult::INVALID_PRESET;
+  return helper(out, value);
 }
 
-auto const TestPresetOptionalFilterIncludeHelper =
-  cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
-            false)
-      .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
-            false)
-      .Bind("index"_s, &TestPreset::IncludeOptions::Index,
-            TestPresetOptionalFilterIncludeIndexHelper, false)
-      .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
-            PresetOptionalBoolHelper, false));
-
-auto const TestPresetOptionalFilterExcludeFixturesHelper =
-  cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
-            PresetStringHelper, false)
-      .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
-            PresetStringHelper, false)
-      .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
-            PresetStringHelper, false));
-
-auto const TestPresetOptionalFilterExcludeHelper =
-  cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
-            false)
-      .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
-            false)
-      .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
-            TestPresetOptionalFilterExcludeFixturesHelper, false));
-
-ReadFileResult TestPresetExecutionShowOnlyHelper(
-  TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
+cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
 {
-  if (!value || !value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
+  return [error](std::nullptr_t& /*out*/,
+                 const Json::Value* value) -> ReadFileResult {
+    if (!value) {
+      return ReadFileResult::READ_OK;
+    }
 
-  if (value->asString() == "human") {
-    out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
-    return ReadFileResult::READ_OK;
-  }
+    if (!value->isObject()) {
+      return error;
+    }
 
-  if (value->asString() == "json-v1") {
-    out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
     return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
+  };
 }
 
-auto const TestPresetOptionalExecutionShowOnlyHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetExecutionShowOnlyHelper);
-
-ReadFileResult TestPresetExecutionModeHelper(
-  TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
+ReadFileResult PresetConditionHelper(
+  std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
   const Json::Value* value)
 {
-  if (!value) {
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "until-fail") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "until-pass") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "after-timeout") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
+  std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
+  auto result = ConditionHelper(ptr, value);
+  out = std::move(ptr);
+  return result;
 }
 
-auto const TestPresetOptionalExecutionRepeatHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
-            TestPresetExecutionModeHelper, true)
-      .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
-            PresetIntHelper, true));
-
-ReadFileResult TestPresetExecutionNoTestsActionHelper(
-  TestPreset::ExecutionOptions::NoTestsActionEnum& out,
-  const Json::Value* value)
+ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
+                                                 const Json::Value* value)
 {
+  out.clear();
   if (!value) {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "default") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "error") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
     return ReadFileResult::READ_OK;
   }
 
-  if (value->asString() == "ignore") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
+  if (value->isString()) {
+    out.push_back(value->asString());
     return ReadFileResult::READ_OK;
   }
 
-  return ReadFileResult::INVALID_PRESET;
+  return PresetVectorStringHelper(out, value);
 }
 
-auto const TestPresetOptionalExecutionNoTestsActionHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetExecutionNoTestsActionHelper);
-
-auto const TestPresetExecutionHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
-            PresetOptionalBoolHelper, false)
-      .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
-            PresetOptionalBoolHelper, false)
-      .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
-            PresetOptionalIntHelper, false)
-      .Bind("resourceSpecFile"_s,
-            &TestPreset::ExecutionOptions::ResourceSpecFile,
-            PresetStringHelper, false)
-      .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
-            PresetOptionalIntHelper, false)
-      .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
-            TestPresetOptionalExecutionShowOnlyHelper, false)
-      .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
-            TestPresetOptionalExecutionRepeatHelper, false)
-      .Bind("interactiveDebugging"_s,
-            &TestPreset::ExecutionOptions::InteractiveDebugging,
-            PresetOptionalBoolHelper, false)
-      .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
-            PresetOptionalBoolHelper, false)
-      .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
-            PresetOptionalIntHelper, false)
-      .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
-            TestPresetOptionalExecutionNoTestsActionHelper, false));
-
-auto const TestPresetFilterHelper =
-  cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("include"_s, &TestPreset::FilterOptions::Include,
-            TestPresetOptionalFilterIncludeHelper, false)
-      .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
-            TestPresetOptionalFilterExcludeHelper, false));
-
-auto const TestPresetHelper =
-  cmJSONObjectHelper<TestPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &TestPreset::Inherits,
-          PresetVectorOneOrMoreStringHelper, false)
-    .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
-    .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
-    .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
-          PresetStringHelper, false)
-    .Bind("inheritConfigureEnvironment"_s,
-          &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
-          false)
-    .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
-          false)
-    .Bind("overwriteConfigurationFile"_s,
-          &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
-          false)
-    .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
-          false)
-    .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
-    .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
-          false)
-    .Bind("condition"_s, &TestPreset::ConditionEvaluator,
-          PresetConditionHelper, false);
-
-auto const ConfigurePresetsHelper =
-  cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
-    ConfigurePresetHelper);
-
-auto const BuildPresetsHelper =
-  cmJSONVectorHelper<BuildPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
-    BuildPresetHelper);
-
-auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
-
-auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
-
-auto const CMakeVersionHelper =
-  cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
-    .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
-    .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
-    .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
+cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
+  std::map<std::string, cm::optional<std::string>>& out,
+  const Json::Value* value)
+{
+  static auto const helper =
+    cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
+      EnvironmentHelper);
 
-auto const RootPresetsHelper =
-  cmJSONObjectHelper<RootPresets, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
-    .Bind<int>("version"_s, nullptr, VersionHelper)
-    .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
-          ConfigurePresetsHelper, false)
-    .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
-          false)
-    .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
-    .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
-          CMakeVersionHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_ROOT), false);
+  return helper(out, value);
+}
 }
 
 cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(

+ 75 - 0
Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx

@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmCMakePresetsGraph.h"
+#include "cmCMakePresetsGraphInternal.h"
+#include "cmJSONHelpers.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
+using BuildPreset = cmCMakePresetsGraph::BuildPreset;
+
+auto const BuildPresetHelper =
+  cmJSONObjectHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &BuildPreset::Name,
+          cmCMakePresetsGraphInternal::PresetStringHelper)
+    .Bind("inherits"_s, &BuildPreset::Inherits,
+          cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
+          false)
+    .Bind("hidden"_s, &BuildPreset::Hidden,
+          cmCMakePresetsGraphInternal::PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          cmCMakePresetsGraphInternal::VendorHelper(
+                            ReadFileResult::INVALID_PRESET),
+                          false)
+    .Bind("displayName"_s, &BuildPreset::DisplayName,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("description"_s, &BuildPreset::Description,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("environment"_s, &BuildPreset::Environment,
+          cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
+    .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &BuildPreset::InheritConfigureEnvironment,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("jobs"_s, &BuildPreset::Jobs,
+          cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+    .Bind("targets"_s, &BuildPreset::Targets,
+          cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
+          false)
+    .Bind("configuration"_s, &BuildPreset::Configuration,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("cleanFirst"_s, &BuildPreset::CleanFirst,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("verbose"_s, &BuildPreset::Verbose,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
+          cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
+    .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
+          cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+}
+
+namespace cmCMakePresetsGraphInternal {
+ReadFileResult BuildPresetsHelper(std::vector<BuildPreset>& out,
+                                  const Json::Value* value)
+{
+  static auto const helper = cmJSONVectorHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    BuildPresetHelper);
+
+  return helper(out, value);
+}
+}

+ 228 - 0
Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx

@@ -0,0 +1,228 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmCMakePresetsGraph.h"
+#include "cmCMakePresetsGraphInternal.h"
+#include "cmJSONHelpers.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
+using CacheVariable = cmCMakePresetsGraph::CacheVariable;
+using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
+using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
+
+ReadFileResult ArchToolsetStrategyHelper(
+  cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "set") {
+    out = ArchToolsetStrategy::Set;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "external") {
+    out = ArchToolsetStrategy::External;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
+ArchToolsetHelper(
+  std::string ConfigurePreset::*valueField,
+  cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
+{
+  auto const objectHelper =
+    cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("value", valueField,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
+  return [valueField, strategyField, objectHelper](
+           ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
+    if (!value) {
+      (out.*valueField).clear();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isString()) {
+      out.*valueField = value->asString();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isObject()) {
+      return objectHelper(out, value);
+    }
+
+    return ReadFileResult::INVALID_PRESET;
+  };
+}
+
+auto const ArchitectureHelper = ArchToolsetHelper(
+  &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
+auto const ToolsetHelper = ArchToolsetHelper(
+  &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
+
+auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
+
+ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
+{
+  if (!value) {
+    out.clear();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isBool()) {
+    out = value->asBool() ? "TRUE" : "FALSE";
+    return ReadFileResult::READ_OK;
+  }
+
+  return VariableStringHelper(out, value);
+}
+
+auto const VariableObjectHelper =
+  cmJSONObjectHelper<CacheVariable, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
+    .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
+    .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
+
+ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
+                              const Json::Value* value)
+{
+  if (value->isBool()) {
+    out = CacheVariable{
+      /*Type=*/"BOOL",
+      /*Value=*/value->asBool() ? "TRUE" : "FALSE",
+    };
+    return ReadFileResult::READ_OK;
+  }
+  if (value->isString()) {
+    out = CacheVariable{
+      /*Type=*/"",
+      /*Value=*/value->asString(),
+    };
+    return ReadFileResult::READ_OK;
+  }
+  if (value->isObject()) {
+    out.emplace();
+    return VariableObjectHelper(*out, value);
+  }
+  if (value->isNull()) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+  return ReadFileResult::INVALID_VARIABLE;
+}
+
+auto const VariablesHelper =
+  cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
+
+auto const PresetWarningsHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("dev"_s, &ConfigurePreset::WarnDev,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
+
+auto const PresetErrorsHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("dev"_s, &ConfigurePreset::ErrorDev,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
+
+auto const PresetDebugHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("output"_s, &ConfigurePreset::DebugOutput,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("find"_s, &ConfigurePreset::DebugFind,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
+
+auto const ConfigurePresetHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &ConfigurePreset::Name,
+          cmCMakePresetsGraphInternal::PresetStringHelper)
+    .Bind("inherits"_s, &ConfigurePreset::Inherits,
+          cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
+          false)
+    .Bind("hidden"_s, &ConfigurePreset::Hidden,
+          cmCMakePresetsGraphInternal::PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          cmCMakePresetsGraphInternal::VendorHelper(
+                            ReadFileResult::INVALID_PRESET),
+                          false)
+    .Bind("displayName"_s, &ConfigurePreset::DisplayName,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("description"_s, &ConfigurePreset::Description,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("generator"_s, &ConfigurePreset::Generator,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("architecture"_s, ArchitectureHelper, false)
+    .Bind("toolset"_s, ToolsetHelper, false)
+    .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("installDir"_s, &ConfigurePreset::InstallDir,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind<std::string>("cmakeExecutable"_s, nullptr,
+                       cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
+          VariablesHelper, false)
+    .Bind("environment"_s, &ConfigurePreset::Environment,
+          cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
+    .Bind("warnings"_s, PresetWarningsHelper, false)
+    .Bind("errors"_s, PresetErrorsHelper, false)
+    .Bind("debug"_s, PresetDebugHelper, false)
+    .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
+          cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+}
+
+namespace cmCMakePresetsGraphInternal {
+ReadFileResult ConfigurePresetsHelper(std::vector<ConfigurePreset>& out,
+                                      const Json::Value* value)
+{
+  static auto const helper =
+    cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+      ConfigurePresetHelper);
+
+  return helper(out, value);
+}
+}

+ 360 - 0
Source/cmCMakePresetsGraphReadJSONTestPresets.cxx

@@ -0,0 +1,360 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmCMakePresetsGraph.h"
+#include "cmCMakePresetsGraphInternal.h"
+#include "cmJSONHelpers.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
+using TestPreset = cmCMakePresetsGraph::TestPreset;
+
+ReadFileResult TestPresetOutputVerbosityHelper(
+  TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "verbose") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "extra") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Extra;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalOutputVerbosityHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetOutputVerbosityHelper);
+
+auto const TestPresetOptionalOutputHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
+            TestPresetOptionalOutputVerbosityHelper, false)
+      .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("subprojectSummary"_s,
+            &TestPreset::OutputOptions::SubprojectSummary,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("maxPassedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxPassedTestOutputSize,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("maxFailedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxFailedTestOutputSize,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false));
+
+auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("specificTests"_s,
+            &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
+            cmCMakePresetsGraphInternal::PresetVectorIntHelper, false));
+
+ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
+  cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isString()) {
+    out.emplace();
+    out->IndexFile = value->asString();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isObject()) {
+    return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalFilterIncludeHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::IncludeOptions::Name,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("label"_s, &TestPreset::IncludeOptions::Label,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("index"_s, &TestPreset::IncludeOptions::Index,
+            TestPresetOptionalFilterIncludeIndexHelper, false)
+      .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false));
+
+auto const TestPresetOptionalFilterExcludeFixturesHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false));
+
+auto const TestPresetOptionalFilterExcludeHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::ExcludeOptions::Name,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("label"_s, &TestPreset::ExcludeOptions::Label,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
+            TestPresetOptionalFilterExcludeFixturesHelper, false));
+
+ReadFileResult TestPresetExecutionShowOnlyHelper(
+  TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
+{
+  if (!value || !value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "human") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "json-v1") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionShowOnlyHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionShowOnlyHelper);
+
+ReadFileResult TestPresetExecutionModeHelper(
+  TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "until-fail") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "until-pass") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "after-timeout") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionRepeatHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
+            TestPresetExecutionModeHelper, true)
+      .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
+            cmCMakePresetsGraphInternal::PresetIntHelper, true));
+
+ReadFileResult TestPresetExecutionNoTestsActionHelper(
+  TestPreset::ExecutionOptions::NoTestsActionEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "error") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "ignore") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionNoTestsActionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionNoTestsActionHelper);
+
+auto const TestPresetExecutionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("resourceSpecFile"_s,
+            &TestPreset::ExecutionOptions::ResourceSpecFile,
+            cmCMakePresetsGraphInternal::PresetStringHelper, false)
+      .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
+            TestPresetOptionalExecutionShowOnlyHelper, false)
+      .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
+            TestPresetOptionalExecutionRepeatHelper, false)
+      .Bind("interactiveDebugging"_s,
+            &TestPreset::ExecutionOptions::InteractiveDebugging,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
+            cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+      .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
+            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+      .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
+            TestPresetOptionalExecutionNoTestsActionHelper, false));
+
+auto const TestPresetFilterHelper =
+  cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("include"_s, &TestPreset::FilterOptions::Include,
+            TestPresetOptionalFilterIncludeHelper, false)
+      .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
+            TestPresetOptionalFilterExcludeHelper, false));
+
+auto const TestPresetHelper =
+  cmJSONObjectHelper<TestPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &TestPreset::Name,
+          cmCMakePresetsGraphInternal::PresetStringHelper)
+    .Bind("inherits"_s, &TestPreset::Inherits,
+          cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
+          false)
+    .Bind("hidden"_s, &TestPreset::Hidden,
+          cmCMakePresetsGraphInternal::PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          cmCMakePresetsGraphInternal::VendorHelper(
+                            ReadFileResult::INVALID_PRESET),
+                          false)
+    .Bind("displayName"_s, &TestPreset::DisplayName,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("description"_s, &TestPreset::Description,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("environment"_s, &TestPreset::Environment,
+          cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
+    .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &TestPreset::InheritConfigureEnvironment,
+          cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+    .Bind("configuration"_s, &TestPreset::Configuration,
+          cmCMakePresetsGraphInternal::PresetStringHelper, false)
+    .Bind("overwriteConfigurationFile"_s,
+          &TestPreset::OverwriteConfigurationFile,
+          cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
+    .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
+          false)
+    .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
+    .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
+          false)
+    .Bind("condition"_s, &TestPreset::ConditionEvaluator,
+          cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+}
+
+namespace cmCMakePresetsGraphInternal {
+cmCMakePresetsGraph::ReadFileResult TestPresetsHelper(
+  std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value)
+{
+  static auto const helper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    TestPresetHelper);
+
+  return helper(out, value);
+}
+}