presets: Improve error diagnostics

Include the preset type when emitting generic error messages,
which avoids confusion over which preset is presenting problems
(e.g., if you you have a preset called "default" in each of the
configure, build, test, package and workflow preset types).

Include additional information about the specific error encountered
when processing a preset.

Fixes: #27774
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$