From 7d52d48a329d6a1c456b48f63c980cce799f3a9c Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Fri, 29 Oct 2021 09:50:41 -0400
Subject: cmCTestRunTest: get the default value from the environment

This only works due to some assumptions about how the `ENVIRONMENT`
property is processed. Comments have been added to notify anyone
modifying the behavior about where to look.

Fixes: #22819
---
 Source/CTest/cmCTestRunTest.cxx   | 18 +++++++++++++++++-
 Tests/Environment/CMakeLists.txt  | 16 ++++++++++++++++
 Tests/Environment/check_mod.cmake |  9 +++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 2d1562a..9d2cef6 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -782,6 +782,9 @@ bool cmCTestRunTest::ForkProcess(
 
   std::ostringstream envMeasurement;
   if (environment && !environment->empty()) {
+    // Environment modification works on the assumption that the environment is
+    // actually modified here. If another strategy is used, there will need to
+    // be updates below in `apply_diff`.
     cmSystemTools::AppendEnv(*environment);
     for (auto const& var : *environment) {
       envMeasurement << var << std::endl;
@@ -800,7 +803,20 @@ bool cmCTestRunTest::ForkProcess(
     auto apply_diff =
       [&env_application](const std::string& name,
                          std::function<void(std::string&)> const& apply) {
-        std::string output = env_application[name].value_or(std::string{});
+        cm::optional<std::string> old_value = env_application[name];
+        std::string output;
+        if (old_value) {
+          output = *old_value;
+        } else {
+          // This only works because the environment is actually modified above
+          // (`AppendEnv`). If CTest ever just creates an environment block
+          // directly, that block will need to be queried for the subprocess'
+          // value instead.
+          const char* curval = cmSystemTools::GetEnv(name);
+          if (curval) {
+            output = curval;
+          }
+        }
         apply(output);
         env_application[name] = output;
       };
diff --git a/Tests/Environment/CMakeLists.txt b/Tests/Environment/CMakeLists.txt
index 5f1edbf..9397bfe 100644
--- a/Tests/Environment/CMakeLists.txt
+++ b/Tests/Environment/CMakeLists.txt
@@ -27,7 +27,23 @@ set_tests_properties(Environment2 EchoEnvironment2 PROPERTIES
 )
 
 set_property(TEST EchoEnvironment3
+  PROPERTY ENVIRONMENT
+    "SET_FROM_ENVIRONMENT_PROPERTY_unset=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_replace=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_string=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_path=base"
+    "SET_FROM_ENVIRONMENT_PROPERTY_list=base"
+)
+
+set_property(TEST EchoEnvironment3
   PROPERTY ENVIRONMENT_MODIFICATION
+    # Modifying variables set in the `ENVIRONMENT` property.
+    "SET_FROM_ENVIRONMENT_PROPERTY_unset=unset:"
+    "SET_FROM_ENVIRONMENT_PROPERTY_replace=set:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_string=string_append:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_path=path_list_append:new"
+    "SET_FROM_ENVIRONMENT_PROPERTY_list=cmake_list_append:new"
+
     # Variables expected to be unset.
     "UNSET_EXPLICIT=set:value"
     "UNSET_EXPLICIT=unset:"
diff --git a/Tests/Environment/check_mod.cmake b/Tests/Environment/check_mod.cmake
index 179bd7a..0691b17 100644
--- a/Tests/Environment/check_mod.cmake
+++ b/Tests/Environment/check_mod.cmake
@@ -14,6 +14,7 @@ else ()
   set(path_sep ":")
 endif ()
 
+set(unexpect_SET_FROM_ENVIRONMENT_PROPERTY_unset "")
 set(unexpect_UNSET_EXPLICIT "")
 set(unexpect_UNSET_VIA_RESET "")
 set(expect_DIRECT "new")
@@ -23,8 +24,16 @@ set(expect_CMAKE_LIST_MANIP "prefix;pre;core;post;suffix")
 set(expect_STRING_DNE "prefix-prepost-suffix")
 set(expect_PATH_DNE "prefix${path_sep}pre${path_sep}post${path_sep}suffix")
 set(expect_CMAKE_LIST_DNE "prefix;pre;post;suffix")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_replace "new")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_string "basenew")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_path "base${path_sep}new")
+set(expect_SET_FROM_ENVIRONMENT_PROPERTY_list "base;new")
 
 set(expected_vars
+  SET_FROM_ENVIRONMENT_PROPERTY_replace
+  SET_FROM_ENVIRONMENT_PROPERTY_string
+  SET_FROM_ENVIRONMENT_PROPERTY_path
+  SET_FROM_ENVIRONMENT_PROPERTY_list
   DIRECT
   STRING_MANIP
   PATH_MANIP
-- 
cgit v0.12