Merge topic 'presets-error-diagnostics'

654a195d8b presets: Improve error diagnostics
c6e81bf30e Help/presets: Disallow empty env keys in build presets also

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Acked-by: scivision <michael@scivision.dev>
Merge-request: !11987
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
index cd52447..128c829 100644
--- a/Help/manual/presets/schema.json
+++ b/Help/manual/presets/schema.json
@@ -1856,6 +1856,9 @@
     "buildPresets.environment@v2..": {
       "type": "object",
       "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+      "propertyNames": {
+        "pattern": "^.+$"
+      },
       "properties": {},
       "additionalProperties": {
         "anyOf": [
diff --git a/Help/manual/presets/schema.yaml b/Help/manual/presets/schema.yaml
index c66bab0..7650fa4 100644
--- a/Help/manual/presets/schema.yaml
+++ b/Help/manual/presets/schema.yaml
@@ -989,6 +989,8 @@
             ExternalProject may use a different (system default) compiler than
             the top-level CMake project.
           properties: {}
+          propertyNames:
+            pattern: '^.+$'
           additionalProperties: *environment-additional-properties
         configurePreset:
           type: string
diff --git a/Source/cmCMakePresetsErrors.cxx b/Source/cmCMakePresetsErrors.cxx
index 8f82e66..be3d193 100644
--- a/Source/cmCMakePresetsErrors.cxx
+++ b/Source/cmCMakePresetsErrors.cxx
@@ -80,9 +80,16 @@
   state->AddErrorAtValue("Invalid preset", value);
 }
 
-void INVALID_PRESET_NAMED(std::string const& presetName, cmJSONState* state)
+void INVALID_PRESET_NAMED(std::string const& presetName,
+                          std::string const& kind, cmJSONState* state,
+                          std::string const& detail)
 {
-  state->AddError(cmStrCat("Invalid preset: \"", presetName, '"'));
+  std::string err_msg =
+    cmStrCat("Invalid ", kind, " preset: \"", presetName, '"');
+  if (!detail.empty()) {
+    err_msg = cmStrCat(err_msg, ": ", detail);
+  }
+  state->AddError(err_msg);
 }
 
 void INVALID_VARIABLE(Json::Value const* value, cmJSONState* state)
@@ -97,17 +104,18 @@
 }
 
 void CYCLIC_PRESET_INHERITANCE(std::string const& presetName,
-                               cmJSONState* state)
+                               std::string const& kind, cmJSONState* state)
 
 {
-  state->AddError(
-    cmStrCat("Cyclic preset inheritance for preset \"", presetName, '"'));
+  state->AddError(cmStrCat("Cyclic preset inheritance for ", kind,
+                           " preset \"", presetName, '"'));
 }
 
 void INHERITED_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
+                                            std::string const& kind,
                                             cmJSONState* state)
 {
-  state->AddError(cmStrCat("Inherited preset \"", presetName,
+  state->AddError(cmStrCat("Inherited ", kind, " preset \"", presetName,
                            "\" is unreachable from preset's file"));
 }
 
diff --git a/Source/cmCMakePresetsErrors.h b/Source/cmCMakePresetsErrors.h
index a153d92..e8ca3e5 100644
--- a/Source/cmCMakePresetsErrors.h
+++ b/Source/cmCMakePresetsErrors.h
@@ -35,16 +35,19 @@
 
 void INVALID_PRESET(Json::Value const* value, cmJSONState* state);
 
-void INVALID_PRESET_NAMED(std::string const& presetName, cmJSONState* state);
+void INVALID_PRESET_NAMED(std::string const& presetName,
+                          std::string const& kind, cmJSONState* state,
+                          std::string const& detail);
 
 void INVALID_VARIABLE(Json::Value const* value, cmJSONState* state);
 
 void DUPLICATE_PRESETS(std::string const& presetName, cmJSONState* state);
 
 void CYCLIC_PRESET_INHERITANCE(std::string const& presetName,
-                               cmJSONState* state);
+                               std::string const& kind, cmJSONState* state);
 
 void INHERITED_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
+                                            std::string const& kind,
                                             cmJSONState* state);
 
 void CONFIGURE_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName,
diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx
index 212a97b..98dc6c6 100644
--- a/Source/cmCMakePresetsGraph.cxx
+++ b/Source/cmCMakePresetsGraph.cxx
@@ -109,8 +109,8 @@
 {
   switch (cycleStatus[preset.Name]) {
     case CycleStatus::InProgress:
-      cmCMakePresetsErrors::CYCLIC_PRESET_INHERITANCE(preset.Name,
-                                                      &graph.parseState);
+      cmCMakePresetsErrors::CYCLIC_PRESET_INHERITANCE(
+        preset.Name, preset.kind(), &graph.parseState);
       return false;
     case CycleStatus::Verified:
       return true;
@@ -121,28 +121,32 @@
   cycleStatus[preset.Name] = CycleStatus::InProgress;
 
   if (preset.Environment.count("") != 0) {
-    cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
+    cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+      preset.Name, preset.kind(), &graph.parseState,
+      "Empty environment variable names are not allowed");
     return false;
   }
 
   bool result = preset.VisitPresetBeforeInherit();
   if (!result) {
-    cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
+    cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+      preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
     return false;
   }
 
   for (auto const& i : preset.Inherits) {
     auto parent = presets.find(i);
     if (parent == presets.end()) {
-      cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
-                                                 &graph.parseState);
+      cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+        preset.Name, preset.kind(), &graph.parseState,
+        cmStrCat("Could not find inherited preset \"", i, "\""));
       return false;
     }
 
     auto& parentPreset = parent->second.Unexpanded;
     if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) {
       cmCMakePresetsErrors::INHERITED_PRESET_UNREACHABLE_FROM_FILE(
-        preset.Name, &graph.parseState);
+        preset.Name, preset.kind(), &graph.parseState);
       return false;
     }
 
@@ -152,8 +156,8 @@
 
     result = preset.VisitPresetInherit(parentPreset);
     if (!result) {
-      cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
-                                                 &graph.parseState);
+      cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+        preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
       return false;
     }
 
@@ -171,7 +175,8 @@
   result = preset.VisitPresetAfterInherit(graph.GetVersion(preset),
                                           &graph.parseState);
   if (!result) {
-    cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name, &graph.parseState);
+    cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+      preset.Name, preset.kind(), &graph.parseState, preset.ErrorDetail);
     return false;
   }
 
@@ -453,8 +458,9 @@
       switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
                        graph->GetVersion(preset))) {
         case ExpandMacroResult::Error:
-          cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
-                                                     &graph->parseState);
+          cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+            preset.Name, preset.kind(), &graph->parseState,
+            "Invalid macro expansion");
           return false;
         case ExpandMacroResult::Ignore:
           out.reset();
@@ -471,8 +477,8 @@
     cm::optional<bool> result;
     if (!preset.ConditionEvaluator->Evaluate(
           macroExpanders, graph->GetVersion(preset), result)) {
-      cmCMakePresetsErrors::INVALID_PRESET_NAMED(preset.Name,
-                                                 &graph->parseState);
+      cmCMakePresetsErrors::INVALID_PRESET_NAMED(
+        preset.Name, preset.kind(), &graph->parseState, "Invalid condition");
       return false;
     }
     if (!result) {
@@ -911,6 +917,8 @@
 {
   auto& preset = *this;
   if (preset.Environment.count("") != 0) {
+    this->ErrorDetail =
+      "Empty environment variable names are not allowed in configure presets";
     return false;
   }
 
@@ -945,6 +953,7 @@
     }
 
     if (preset.CacheVariables.count("") != 0) {
+      this->ErrorDetail = "Empty cache variable names are not allowed";
       return false;
     }
   }
@@ -977,7 +986,12 @@
 bool cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(
   int /* version */, cmJSONState* /*stat*/)
 {
-  return this->Hidden || !this->ConfigurePreset.empty();
+  if (!this->Hidden && this->ConfigurePreset.empty()) {
+    this->ErrorDetail = "Build presets must either be hidden or have an "
+                        "associated configure preset";
+    return false;
+  }
+  return true;
 }
 
 bool cmCMakePresetsGraph::TestPreset::VisitPresetInherit(
@@ -1087,7 +1101,12 @@
 bool cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(
   int /* version */, cmJSONState* /*state*/)
 {
-  return this->Hidden || !this->ConfigurePreset.empty();
+  if (!this->Hidden && this->ConfigurePreset.empty()) {
+    this->ErrorDetail = "Test presets must either be hidden or have an "
+                        "associated configure preset";
+    return false;
+  }
+  return true;
 }
 
 bool cmCMakePresetsGraph::PackagePreset::VisitPresetInherit(
@@ -1116,7 +1135,12 @@
 bool cmCMakePresetsGraph::PackagePreset::VisitPresetAfterInherit(
   int /* version */, cmJSONState* /*state*/)
 {
-  return this->Hidden || !this->ConfigurePreset.empty();
+  if (!this->Hidden && this->ConfigurePreset.empty()) {
+    this->ErrorDetail = "Package presets must either be hidden or have an "
+                        "associated configure preset";
+    return false;
+  }
+  return true;
 }
 
 bool cmCMakePresetsGraph::WorkflowPreset::VisitPresetInherit(
diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h
index 74063e4..f04dfdd 100644
--- a/Source/cmCMakePresetsGraph.h
+++ b/Source/cmCMakePresetsGraph.h
@@ -84,6 +84,8 @@
 
     std::map<std::string, cm::optional<std::string>> Environment;
 
+    std::string ErrorDetail;
+
     virtual bool VisitPresetInherit(Preset const& parent) = 0;
     virtual bool VisitPresetBeforeInherit() { return true; }
 
diff --git a/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-result.txt b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-stderr.txt b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-stderr.txt
new file mode 100644
index 0000000..e8d349d
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey:
+Invalid build preset: "EmptyEnvKey": Empty environment variable names are not allowed$
diff --git a/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey.json.in b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey.json.in
new file mode 100644
index 0000000..7e9932b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildEmptyEnvKey.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 2,
+  "buildPresets": [
+    {
+      "name": "EmptyEnvKey",
+      "environment": {
+        "": "value"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-result.txt b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-stderr.txt
new file mode 100644
index 0000000..e9ba8c2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/BuildInvalidInheritance:
+Invalid build preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
diff --git a/Tests/RunCMake/CMakePresets/BuildInvalidInheritance.json.in b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance.json.in
new file mode 100644
index 0000000..2dd5d81
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/BuildInvalidInheritance.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 2,
+  "buildPresets": [
+    {
+      "name": "InvalidInheritance",
+      "inherits": [
+        "NoExist"
+      ]
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt
index 2d5b477..d7366f7 100644
--- a/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance0-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/CyclicInheritance0:
-Cyclic preset inheritance for preset "CyclicInheritance0"$
+Cyclic preset inheritance for configure preset "CyclicInheritance0"$
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt
index 596fcf8..e2d9d11 100644
--- a/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance1-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/CyclicInheritance1:
-Cyclic preset inheritance for preset "CyclicInheritance0"$
+Cyclic preset inheritance for configure preset "CyclicInheritance0"$
diff --git a/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt b/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt
index a6b83c8..99fe0bd 100644
--- a/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/CyclicInheritance2-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/CyclicInheritance2:
-Cyclic preset inheritance for preset "CyclicInheritance0"$
+Cyclic preset inheritance for configure preset "CyclicInheritance0"$
diff --git a/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt
index cb9e545..d6f402f 100644
--- a/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/EmptyCacheKey:
-Invalid preset: "EmptyCacheKey"$
+Invalid configure preset: "EmptyCacheKey": Empty cache variable names are not allowed$
diff --git a/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt b/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt
index bc0f866..a357267 100644
--- a/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/EmptyEnvKey:
-Invalid preset: "EmptyEnvKey"$
+Invalid configure preset: "EmptyEnvKey": Empty environment variable names are not allowed$
diff --git a/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt b/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt
index 8e19c69..eb658ce 100644
--- a/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/EnvCycle-stderr.txt
@@ -1,4 +1,4 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/EnvCycle:
-Invalid preset: "EnvCycle"
+Invalid configure preset: "EnvCycle": Invalid macro expansion
 Invalid macro expansion in "EnvCycle"$
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt
index 5c02d5b..dd47dc7 100644
--- a/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDeprecated:
-Invalid preset: "ErrorNoWarningDeprecated"$
+Invalid configure preset: "ErrorNoWarningDeprecated"$
diff --git a/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt
index 4640b1e..ca087b1 100644
--- a/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/ErrorNoWarningDev-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/ErrorNoWarningDev:
-Invalid preset: "ErrorNoWarningDev"$
+Invalid configure preset: "ErrorNoWarningDev"$
diff --git a/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt
index 216f308..a8eb597 100644
--- a/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/InvalidInheritance-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/InvalidInheritance:
-Invalid preset: "InvalidInheritance"$
+Invalid configure preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
index 86cd861..b948676 100644
--- a/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
@@ -1,4 +1,4 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/InvalidRegex:
-Invalid preset: "InvalidRegex"
+Invalid configure preset: "InvalidRegex": Invalid condition
 Invalid macro expansion in "InvalidRegex"$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt
index bae9794..ccd3d4c 100644
--- a/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/NoPresetBinaryDir-stderr.txt
@@ -1,4 +1,4 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/NoPresetBinaryDir:
 Preset "NoPresetBinaryDir" missing field "binaryDir"
-Invalid preset: "NoPresetBinaryDir"$
+Invalid configure preset: "NoPresetBinaryDir"$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt
index c7e5b5e..51558cd 100644
--- a/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/NoPresetGenerator-stderr.txt
@@ -1,4 +1,4 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/NoPresetGenerator:
 Preset "NoPresetGenerator" missing field "generator"
-Invalid preset: "NoPresetGenerator"$
+Invalid configure preset: "NoPresetGenerator"$
diff --git a/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-result.txt b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-stderr.txt b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-stderr.txt
new file mode 100644
index 0000000..6d18c7a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey:
+Invalid package preset: "EmptyEnvKey": Empty environment variable names are not allowed$
diff --git a/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey.json.in b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey.json.in
new file mode 100644
index 0000000..f181e45
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageEmptyEnvKey.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 6,
+  "packagePresets": [
+    {
+      "name": "EmptyEnvKey",
+      "environment": {
+        "": "value"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-result.txt b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-stderr.txt
new file mode 100644
index 0000000..ad32da4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/PackageInvalidInheritance:
+Invalid package preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
diff --git a/Tests/RunCMake/CMakePresets/PackageInvalidInheritance.json.in b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance.json.in
new file mode 100644
index 0000000..7076ecc
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageInvalidInheritance.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 6,
+  "packagePresets": [
+    {
+      "name": "InvalidInheritance",
+      "inherits": [
+        "NoExist"
+      ]
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-result.txt b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-stderr.txt
new file mode 100644
index 0000000..b29e953
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset:
+Invalid package preset: "noConfigurePreset": Package presets must either be hidden or have an associated configure preset$
diff --git a/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset.json.in b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset.json.in
new file mode 100644
index 0000000..03b09ed
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/PackageNoConfigurePreset.json.in
@@ -0,0 +1,8 @@
+{
+  "version": 6,
+  "packagePresets": [
+    {
+      "name": "noConfigurePreset"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index 8ca58a2..95acf52 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -181,6 +181,10 @@
 run_cmake_presets(CyclicInheritance1)
 run_cmake_presets(CyclicInheritance2)
 run_cmake_presets(InvalidInheritance)
+run_cmake_presets(BuildInvalidInheritance)
+run_cmake_presets(PackageInvalidInheritance)
+run_cmake_presets(TestInvalidInheritance)
+run_cmake_presets(PackageNoConfigurePreset)
 run_cmake_presets(ErrorNoWarningDev)
 run_cmake_presets(ErrorNoWarningDeprecated)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
@@ -190,6 +194,9 @@
 run_cmake_presets(UnknownToolsetStrategy)
 run_cmake_presets(EmptyCacheKey)
 run_cmake_presets(EmptyEnvKey)
+run_cmake_presets(BuildEmptyEnvKey)
+run_cmake_presets(PackageEmptyEnvKey)
+run_cmake_presets(TestEmptyEnvKey)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 run_cmake_presets(UnclosedMacro)
 run_cmake_presets(NoSuchMacro)
diff --git a/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-result.txt b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-stderr.txt b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-stderr.txt
new file mode 100644
index 0000000..df00af9
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/TestEmptyEnvKey:
+Invalid test preset: "EmptyEnvKey": Empty environment variable names are not allowed$
diff --git a/Tests/RunCMake/CMakePresets/TestEmptyEnvKey.json.in b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey.json.in
new file mode 100644
index 0000000..50741d1
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestEmptyEnvKey.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 2,
+  "testPresets": [
+    {
+      "name": "EmptyEnvKey",
+      "environment": {
+        "": "value"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/TestInvalidInheritance-result.txt b/Tests/RunCMake/CMakePresets/TestInvalidInheritance-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestInvalidInheritance-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/TestInvalidInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/TestInvalidInheritance-stderr.txt
new file mode 100644
index 0000000..a72e498
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestInvalidInheritance-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/TestInvalidInheritance:
+Invalid test preset: "InvalidInheritance": Could not find inherited preset "NoExist"$
diff --git a/Tests/RunCMake/CMakePresets/TestInvalidInheritance.json.in b/Tests/RunCMake/CMakePresets/TestInvalidInheritance.json.in
new file mode 100644
index 0000000..e137f52
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/TestInvalidInheritance.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 2,
+  "testPresets": [
+    {
+      "name": "InvalidInheritance",
+      "inherits": [
+        "NoExist"
+      ]
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt
index 2ce1316..65d1a5f 100644
--- a/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt
@@ -1,3 +1,3 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/UserInheritance:
-Inherited preset "UserInheritance" is unreachable from preset's file$
+Inherited configure preset "UserInheritance" is unreachable from preset's file$
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
index 9ce6ea5..4749340 100644
--- a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
+++ b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
@@ -1,3 +1,3 @@
 CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset:
-Invalid preset: "noConfigurePreset"$
+Invalid build preset: "noConfigurePreset": Build presets must either be hidden or have an associated configure preset$
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
index a70497f..d414ed8 100644
--- a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
+++ b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
@@ -1,3 +1,3 @@
 CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset:
-Invalid preset: "noConfigurePreset"$
+Invalid test preset: "noConfigurePreset": Test presets must either be hidden or have an associated configure preset$