Browse Source

cmJSONHelpers.h: Add generic predicate checking helper

And use it in the `cmCMakePresetsGraphReadJSON.cxx` to check
presets schema version in the declarative way.

Co-authored-by: Martin Duffy <[email protected]>
Alex Turbov 1 year ago
parent
commit
0b334e5bfb

+ 10 - 0
Source/cmCMakePresetsErrors.cxx

@@ -238,6 +238,16 @@ void TRACE_UNSUPPORTED(cmJSONState* state)
   state->AddError("File version must be 7 or higher for trace preset support");
 }
 
+JsonErrors::ErrorGenerator UNRECOGNIZED_VERSION_RANGE(int min, int max)
+{
+  return [min, max](const Json::Value* value, cmJSONState* state) -> void {
+    state->AddErrorAtValue(cmStrCat("Unrecognized \"version\" ",
+                                    value->asString(), ": must be >=", min,
+                                    " and <=", max),
+                           value);
+  };
+}
+
 JsonErrors::ErrorGenerator UNRECOGNIZED_CMAKE_VERSION(
   const std::string& version, int current, int required)
 {

+ 2 - 0
Source/cmCMakePresetsErrors.h

@@ -94,6 +94,8 @@ void CTEST_JUNIT_UNSUPPORTED(cmJSONState* state);
 
 void TRACE_UNSUPPORTED(cmJSONState* state);
 
+JsonErrors::ErrorGenerator UNRECOGNIZED_VERSION_RANGE(int min, int max);
+
 JsonErrors::ErrorGenerator UNRECOGNIZED_CMAKE_VERSION(
   const std::string& version, int current, int required);
 

+ 6 - 6
Source/cmCMakePresetsGraphReadJSON.cxx

@@ -256,9 +256,14 @@ auto const VersionIntHelper =
 auto const VersionHelper = JSONHelperBuilder::Required<int>(
   cmCMakePresetsErrors::NO_VERSION, VersionIntHelper);
 
+auto const VersionRangeHelper = JSONHelperBuilder::Checked<int>(
+  cmCMakePresetsErrors::UNRECOGNIZED_VERSION_RANGE(MIN_VERSION, MAX_VERSION),
+  VersionHelper,
+  [](const int v) -> bool { return v >= MIN_VERSION && v <= MAX_VERSION; });
+
 auto const RootVersionHelper =
   JSONHelperBuilder::Object<int>(cmCMakePresetsErrors::INVALID_ROOT_OBJECT)
-    .Bind("version"_s, VersionHelper, false);
+    .Bind("version"_s, VersionRangeHelper, false);
 
 auto const CMakeVersionUIntHelper =
   JSONHelperBuilder::UInt(cmCMakePresetsErrors::INVALID_VERSION);
@@ -481,11 +486,6 @@ bool cmCMakePresetsGraph::ReadJSONFile(const std::string& filename,
   if ((result = RootVersionHelper(v, &root, &parseState)) != true) {
     return result;
   }
-  if (v < MIN_VERSION || v > MAX_VERSION) {
-    cmCMakePresetsErrors::UNRECOGNIZED_VERSION(&root["version"],
-                                               &this->parseState);
-    return false;
-  }
 
   // Support for build and test presets added in version 2.
   if (v < 2) {

+ 15 - 0
Source/cmJSONHelpers.h

@@ -390,4 +390,19 @@ struct cmJSONHelperBuilder
       return func(out, value, state);
     };
   }
+
+  template <typename T, typename F, typename P>
+  static cmJSONHelper<T> Checked(const JsonErrors::ErrorGenerator& error,
+                                 F func, P predicate)
+  {
+    return [error, func, predicate](T& out, const Json::Value* value,
+                                    cmJSONState* state) -> bool {
+      bool result = func(out, value, state);
+      if (result && !predicate(out)) {
+        error(value, state);
+        result = false;
+      }
+      return result;
+    };
+  }
 };

+ 1 - 1
Tests/RunCMake/CMakePresets/HighVersion-stderr.txt

@@ -1,5 +1,5 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/HighVersion:
-Error: @2,14: Unrecognized "version" field
+Error: @2,14: Unrecognized "version" 1000: must be >=1 and <=10
   "version": 1000,
              \^$

+ 1 - 1
Tests/RunCMake/CMakePresets/LowVersion-stderr.txt

@@ -1,5 +1,5 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/LowVersion:
-Error: @2,14: Unrecognized "version" field
+Error: @2,14: Unrecognized "version" 0: must be >=1 and <=10
   "version": 0,
              \^