@@ -249,52 +249,8 @@ TEST(SubosInfo, UnknownOpIsDroppedLikeXlingsDrops) {
249249 EXPECT_EQ (env[0 ].second , " /yes" );
250250}
251251
252- // A `set` is a default; an exported value wins.
253- //
254- // The resolved pairs REPLACE the variable in the child (they go in as
255- // extraEnv), so a `set` that ignores the caller's environment overwrites it
256- // silently. Recipes are written on the opposite assumption: xlings'
257- // wsl-gl-host-link documents that a user who exports GALLIUM_DRIVER=llvmpipe
258- // keeps it, and that escape hatch did not exist -- `export
259- // GALLIUM_DRIVER=llvmpipe; mcpp run` still ran with the subos value and still
260- // failed (mcpp#382).
261- TEST (SubosResolveEnv, SetDoesNotOverrideAnExportedValue) {
262- Tmp t;
263- t.write (R"( {"workspace":{},"subos_info":{"schema_version":1,"runtime":"glibc@2.39",
264- "envs":{"glibc@2.39":[{"var":"GALLIUM_DRIVER","op":"set","value":"d3d12"}]}}})" );
265- auto info = su::read (t.dir );
266- auto out = su::resolve_env (
267- info, t.dir , [](std::string_view v) -> std::optional<std::string> {
268- if (v == " GALLIUM_DRIVER" ) return std::string (" llvmpipe" );
269- return std::nullopt ;
270- });
271- ASSERT_EQ (out.size (), 1u );
272- EXPECT_EQ (out[0 ].first , " GALLIUM_DRIVER" );
273- EXPECT_EQ (out[0 ].second , " llvmpipe" ) << " the user's export must survive" ;
274- }
275252
276- TEST (SubosResolveEnv, SetAppliesWhenNothingIsExported) {
277- Tmp t;
278- t.write (R"( {"workspace":{},"subos_info":{"schema_version":1,"runtime":"glibc@2.39",
279- "envs":{"glibc@2.39":[{"var":"GALLIUM_DRIVER","op":"set","value":"d3d12"}]}}})" );
280- auto info = su::read (t.dir );
281- auto out = su::resolve_env (
282- info, t.dir , [](std::string_view) { return std::optional<std::string>{}; });
283- ASSERT_EQ (out.size (), 1u );
284- EXPECT_EQ (out[0 ].second , " d3d12" );
285- }
286253
287- // An empty export is not an export.
288- TEST (SubosResolveEnv, EmptyAmbientDoesNotBlockASet) {
289- Tmp t;
290- t.write (R"( {"workspace":{},"subos_info":{"schema_version":1,"runtime":"glibc@2.39",
291- "envs":{"glibc@2.39":[{"var":"X","op":"set","value":"v"}]}}})" );
292- auto info = su::read (t.dir );
293- auto out = su::resolve_env (
294- info, t.dir , [](std::string_view) { return std::optional<std::string>(" " ); });
295- ASSERT_EQ (out.size (), 1u );
296- EXPECT_EQ (out[0 ].second , " v" );
297- }
298254
299255// `prepend` prepends TO the caller's value rather than replacing it. Same
300256// reason: the pair replaces the variable, so emitting the declared value alone
@@ -331,4 +287,27 @@ TEST(SubosResolveEnv, PrependIsIdempotentAgainstTheExportedValue) {
331287 EXPECT_EQ (out[0 ].second , existing);
332288}
333289
290+ // `set` wins over an exported value, and that is deliberate.
291+ //
292+ // This assertion exists to stop the opposite reading from being reintroduced
293+ // -- it was, once, as a fix for mcpp#382, and withdrawn: `set` and "a default
294+ // the user may override" are two intentions, and a subos needs the first for
295+ // variables naming its own configuration. The escape hatch that issue wants is
296+ // a NEW op from xlings, whose wire format this is, not a second meaning for
297+ // this one applied by one consumer.
298+ TEST (SubosResolveEnv, SetWinsOverAnExportedValue) {
299+ Tmp t;
300+ t.write (R"( {"workspace":{},"subos_info":{"schema_version":1,
301+ "runtime":"glibc@2.39",
302+ "envs":{"glibc@2.39":[{"var":"GALLIUM_DRIVER","op":"set","value":"d3d12"}]}}})" );
303+ auto info = su::read (t.dir );
304+ auto out = su::resolve_env (
305+ info, t.dir , [](std::string_view v) -> std::optional<std::string> {
306+ if (v == " GALLIUM_DRIVER" ) return std::string (" llvmpipe" );
307+ return std::nullopt ;
308+ });
309+ ASSERT_EQ (out.size (), 1u );
310+ EXPECT_EQ (out[0 ].second , " d3d12" );
311+ }
312+
334313} // namespace
0 commit comments