From 576799954cc978e80aa1a567536ad9cd6601d56e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:44:23 +0000 Subject: [PATCH 01/14] Update BootJsonData generation to account for runtimeconfig.dev.json When RuntimeConfigJsonPath is set and IsPublish is false, also check for a runtimeconfig.dev.json file alongside the main config. If found, merge its configProperties into the result, with dev values overriding main config values. This allows the SDK to use runtimeconfig.dev.json to set Hot Reload related switches in debug builds. Fixes dotnet/runtime#130823 --- .../GenerateWasmBootJsonTests.cs | 183 ++++++++++++++++++ ...ET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 13 ++ 2 files changed, 196 insertions(+) create mode 100644 src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs create mode 100644 src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs new file mode 100644 index 00000000000000..5c52092227b342 --- /dev/null +++ b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs @@ -0,0 +1,183 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Xunit; + +namespace Microsoft.NET.Sdk.WebAssembly.Tests; + +public class GenerateWasmBootJsonTests +{ + [Fact] + public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() + { + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(null, null); + + Assert.Null(result); + } + + [Fact] + public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() + { + using var dir = new TempDirectory(); + var nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(nonExistentPath, null); + + Assert.Null(result); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + // Write dev config with native JSON boolean and number (not string) values. + var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); + File.WriteAllText(devConfigPath, """ + { + "runtimeOptions": { + "configProperties": { + "System.HotReload.Enable": true, + "System.HotReload.MaxRetries": 10 + } + } + } + """); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + var props = result!.runtimeOptions!.configProperties!; + Assert.Equal(JsonValueKind.True, ((JsonElement)props["System.HotReload.Enable"]).ValueKind); + Assert.Equal(JsonValueKind.Number, ((JsonElement)props["System.HotReload.MaxRetries"]).ValueKind); + Assert.Equal(10, ((JsonElement)props["System.HotReload.MaxRetries"]).GetInt32()); + } + + [Fact] + public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, null); + + Assert.NotNull(result); + Assert.NotNull(result.runtimeOptions?.configProperties); + Assert.Equal("value1", result.runtimeOptions!.configProperties!["key1"].ToString()); + Assert.Equal("42", result.runtimeOptions.configProperties["key2"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUnchanged() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); + + Assert.NotNull(result); + Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["key2"] = "value2" }); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); + Assert.Equal("value2", result.runtimeOptions.configProperties["key2"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["System.Runtime.Feature"] = "false" }); + var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["System.Runtime.Feature"] = "true" }); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: null); + var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["System.HotReload.Enable"] = "true" }); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() + { + using var dir = new TempDirectory(); + var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new()); + + var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Single(result!.runtimeOptions!.configProperties!); + Assert.Equal("value1", result.runtimeOptions.configProperties["key1"].ToString()); + } + + private static string WriteRuntimeConfig(string dir, string fileName, Dictionary? configProperties) + { + var path = Path.Combine(dir, fileName); + using var stream = File.OpenWrite(path); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); + writer.WriteStartObject(); + writer.WritePropertyName("runtimeOptions"); + writer.WriteStartObject(); + if (configProperties is not null) + { + writer.WritePropertyName("configProperties"); + writer.WriteStartObject(); + foreach (var (key, value) in configProperties) + writer.WriteString(key, value); + writer.WriteEndObject(); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + return path; + } + + private sealed class TempDirectory : System.IDisposable + { + public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); + + public TempDirectory() => Directory.CreateDirectory(Path); + + public void Dispose() + { + // Silently ignore cleanup failures to avoid masking actual test failures. + try { Directory.Delete(Path, recursive: true); } catch { } + } + } +} diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj new file mode 100644 index 00000000000000..407ae10bd9cbf9 --- /dev/null +++ b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj @@ -0,0 +1,13 @@ + + + $(NetCoreAppToolCurrent) + enable + true + + + + + + + + From 9e50026a50ea59c40f283e69411414b0e09a4787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Mon, 20 Jul 2026 07:55:25 -0700 Subject: [PATCH 02/14] Move tests --- eng/Subsets.props | 5 +++++ src/tasks/tasks.proj | 2 ++ .../GenerateWasmBootJsonTests.cs | 0 ...ft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 15 +++++++++++++++ ...ft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 13 ------------- 5 files changed, 22 insertions(+), 13 deletions(-) rename src/{tests/tasks => tasks/tests}/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs (100%) create mode 100644 src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj delete mode 100644 src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj diff --git a/eng/Subsets.props b/eng/Subsets.props index 14b2d3eedab02a..8c68bdc503cc38 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -666,6 +666,11 @@ + + diff --git a/src/tasks/tasks.proj b/src/tasks/tasks.proj index d84edb3f2bea63..39e370084afeb8 100644 --- a/src/tasks/tasks.proj +++ b/src/tasks/tasks.proj @@ -2,6 +2,8 @@ + + diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs b/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs similarity index 100% rename from src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs rename to src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs diff --git a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj new file mode 100644 index 00000000000000..08cbed35116eff --- /dev/null +++ b/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj @@ -0,0 +1,15 @@ + + + + $(NetCoreAppToolCurrent) + enable + + + + + + + + + + diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj deleted file mode 100644 index 407ae10bd9cbf9..00000000000000 --- a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - $(NetCoreAppToolCurrent) - enable - true - - - - - - - - From 079d9582ee14f20526b08f71d7861b44f0fd5287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Mon, 20 Jul 2026 15:13:25 -0700 Subject: [PATCH 03/14] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj index 08cbed35116eff..e08e24d15ac477 100644 --- a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj +++ b/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj @@ -1,14 +1,15 @@ + + $(NetCoreAppToolCurrent) + true + xunit enable - - - From f88d181a473ef750c820b40ba3c1221da6990604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Tue, 21 Jul 2026 09:16:06 -0700 Subject: [PATCH 04/14] Cleanup --- src/tasks/tasks.proj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tasks/tasks.proj b/src/tasks/tasks.proj index 39e370084afeb8..d84edb3f2bea63 100644 --- a/src/tasks/tasks.proj +++ b/src/tasks/tasks.proj @@ -2,8 +2,6 @@ - - From 74046a752ce5f5b9744995f35bbc560bdd14a97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Tue, 21 Jul 2026 10:43:32 -0700 Subject: [PATCH 05/14] Move test project --- .../GenerateWasmBootJsonTests.cs | 0 .../Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) rename src/{tasks/tests => tests/tasks}/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs (100%) rename src/{tasks/tests => tests/tasks}/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj (65%) diff --git a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs similarity index 100% rename from src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs rename to src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs diff --git a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj similarity index 65% rename from src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj rename to src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj index e08e24d15ac477..0d33d0eeb9c597 100644 --- a/src/tasks/tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj +++ b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj @@ -5,12 +5,11 @@ $(NetCoreAppToolCurrent) true - xunit enable - + From a504c1ed9d41ed121153e2385c5611566f65d62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Tue, 21 Jul 2026 10:45:58 -0700 Subject: [PATCH 06/14] Cleanup --- eng/Subsets.props | 5 ----- 1 file changed, 5 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 8c68bdc503cc38..14b2d3eedab02a 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -666,11 +666,6 @@ - - From 2009151fcf76cb88c0459a0afa277103dc27ee30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Tue, 21 Jul 2026 12:52:49 -0700 Subject: [PATCH 07/14] Move tests to src/tasks.tests --- eng/Subsets.props | 5 + .../GenerateWasmBootJsonTests.cs | 183 ------------------ ...ET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 15 -- 3 files changed, 5 insertions(+), 198 deletions(-) delete mode 100644 src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs delete mode 100644 src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj diff --git a/eng/Subsets.props b/eng/Subsets.props index 14b2d3eedab02a..fb23ae9fb2437a 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -666,6 +666,11 @@ + + diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs deleted file mode 100644 index 5c52092227b342..00000000000000 --- a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.IO; -using System.Text.Json; -using Xunit; - -namespace Microsoft.NET.Sdk.WebAssembly.Tests; - -public class GenerateWasmBootJsonTests -{ - [Fact] - public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() - { - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(null, null); - - Assert.Null(result); - } - - [Fact] - public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() - { - using var dir = new TempDirectory(); - var nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(nonExistentPath, null); - - Assert.Null(result); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - // Write dev config with native JSON boolean and number (not string) values. - var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - File.WriteAllText(devConfigPath, """ - { - "runtimeOptions": { - "configProperties": { - "System.HotReload.Enable": true, - "System.HotReload.MaxRetries": 10 - } - } - } - """); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - var props = result!.runtimeOptions!.configProperties!; - Assert.Equal(JsonValueKind.True, ((JsonElement)props["System.HotReload.Enable"]).ValueKind); - Assert.Equal(JsonValueKind.Number, ((JsonElement)props["System.HotReload.MaxRetries"]).ValueKind); - Assert.Equal(10, ((JsonElement)props["System.HotReload.MaxRetries"]).GetInt32()); - } - - [Fact] - public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, null); - - Assert.NotNull(result); - Assert.NotNull(result.runtimeOptions?.configProperties); - Assert.Equal("value1", result.runtimeOptions!.configProperties!["key1"].ToString()); - Assert.Equal("42", result.runtimeOptions.configProperties["key2"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUnchanged() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); - - Assert.NotNull(result); - Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["key2"] = "value2" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); - Assert.Equal("value2", result.runtimeOptions.configProperties["key2"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["System.Runtime.Feature"] = "false" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["System.Runtime.Feature"] = "true" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: null); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["System.HotReload.Enable"] = "true" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new()); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Single(result!.runtimeOptions!.configProperties!); - Assert.Equal("value1", result.runtimeOptions.configProperties["key1"].ToString()); - } - - private static string WriteRuntimeConfig(string dir, string fileName, Dictionary? configProperties) - { - var path = Path.Combine(dir, fileName); - using var stream = File.OpenWrite(path); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); - writer.WriteStartObject(); - writer.WritePropertyName("runtimeOptions"); - writer.WriteStartObject(); - if (configProperties is not null) - { - writer.WritePropertyName("configProperties"); - writer.WriteStartObject(); - foreach (var (key, value) in configProperties) - writer.WriteString(key, value); - writer.WriteEndObject(); - } - writer.WriteEndObject(); - writer.WriteEndObject(); - return path; - } - - private sealed class TempDirectory : System.IDisposable - { - public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); - - public TempDirectory() => Directory.CreateDirectory(Path); - - public void Dispose() - { - // Silently ignore cleanup failures to avoid masking actual test failures. - try { Directory.Delete(Path, recursive: true); } catch { } - } - } -} diff --git a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj deleted file mode 100644 index 0d33d0eeb9c597..00000000000000 --- a/src/tests/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - $(NetCoreAppToolCurrent) - true - enable - - - - - - - From 2e1bb409e4ad00083a82659e07f9c6e6381ea94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Wed, 22 Jul 2026 11:36:40 +0200 Subject: [PATCH 08/14] Revert Subsets.props change from #130825 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b49d3786-9f03-4fd3-8076-28a73d639686 --- eng/Subsets.props | 5 ----- 1 file changed, 5 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index fb23ae9fb2437a..14b2d3eedab02a 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -666,11 +666,6 @@ - - From 320667360de32a4d785e057213a11b12ddb61250 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 20 Jul 2026 17:36:18 -0700 Subject: [PATCH 09/14] JIT: formatting fixes in rangecheck.h (#131104) Minor formatting-only changes in `src/coreclr/jit/rangecheck.h` to wrap long lines. No behavioral changes. From 944d3f1aae9366f7e3c783e07495bd0921f1eaa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Wed, 22 Jul 2026 12:06:08 +0200 Subject: [PATCH 10/14] [browser] Move boot config tests to Wasm.Build.Tests Move GenerateWasmBootJson test coverage from the temporary tasks.tests project into Wasm.Build.Tests, remove the obsolete tasks.tests csproj, and tag the moved tests as no-workload. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2db6a9dd-0c66-4a48-b2f6-36c7329a5e0e --- .../GenerateWasmBootJsonTests.cs | 213 ++++++++++++++++++ .../GenerateWasmBootJsonTests.cs | 183 --------------- ...ET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj | 14 -- ...soft.NET.Sdk.WebAssembly.Pack.Tasks.csproj | 1 - 4 files changed, 213 insertions(+), 198 deletions(-) create mode 100644 src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs delete mode 100644 src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs delete mode 100644 src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj diff --git a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs new file mode 100644 index 00000000000000..c57e1ab0b844fd --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs @@ -0,0 +1,213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.Json; +using Microsoft.NET.Sdk.WebAssembly; +using Xunit; + +#nullable enable + +namespace Wasm.Build.Tests +{ + [TestCategory("no-workload")] + public class GenerateWasmBootJsonTests + { + [Fact] + public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() + { + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(null, null); + + Assert.Null(result); + } + + [Fact] + public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() + { + using var dir = new TempDirectory(); + string nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(nonExistentPath, null); + + Assert.Null(result); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + string devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); + File.WriteAllText(devConfigPath, """ + { + "runtimeOptions": { + "configProperties": { + "System.HotReload.Enable": true, + "System.HotReload.MaxRetries": 10 + } + } + } + """); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Dictionary props = result!.runtimeOptions!.configProperties!; + Assert.Equal(JsonValueKind.True, ((JsonElement)props["System.HotReload.Enable"]).ValueKind); + Assert.Equal(JsonValueKind.Number, ((JsonElement)props["System.HotReload.MaxRetries"]).ValueKind); + Assert.Equal(10, ((JsonElement)props["System.HotReload.MaxRetries"]).GetInt32()); + } + + [Fact] + public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, null); + + Assert.NotNull(result); + Assert.NotNull(result.runtimeOptions?.configProperties); + Assert.Equal("value1", result.runtimeOptions!.configProperties!["key1"].ToString()); + Assert.Equal("42", result.runtimeOptions.configProperties["key2"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUnchanged() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + string devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); + + Assert.NotNull(result); + Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["key2"] = "value2" }); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); + Assert.Equal("value2", result.runtimeOptions.configProperties["key2"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["System.Runtime.Feature"] = "false" }); + string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["System.Runtime.Feature"] = "true" }); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: null); + string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new() { ["System.HotReload.Enable"] = "true" }); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); + } + + [Fact] + public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() + { + using var dir = new TempDirectory(); + string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", + configProperties: new() { ["key1"] = "value1" }); + string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", + configProperties: new()); + + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + + Assert.NotNull(result?.runtimeOptions?.configProperties); + Assert.Single(result!.runtimeOptions!.configProperties!); + Assert.Equal("value1", result.runtimeOptions.configProperties["key1"].ToString()); + } + + private static string WriteRuntimeConfig(string dir, string fileName, Dictionary? configProperties) + { + string path = Path.Combine(dir, fileName); + using var stream = File.OpenWrite(path); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); + writer.WriteStartObject(); + writer.WritePropertyName("runtimeOptions"); + writer.WriteStartObject(); + if (configProperties is not null) + { + writer.WritePropertyName("configProperties"); + writer.WriteStartObject(); + foreach ((string key, string value) in configProperties) + { + writer.WriteString(key, value); + } + writer.WriteEndObject(); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + return path; + } + + private static RuntimeConfigData? InvokeReadRuntimeConfigFiles(string? mainConfigPath, string? devConfigPath) + { + MethodInfo method = typeof(GenerateWasmBootJson).GetMethod( + "ReadRuntimeConfigFiles", + BindingFlags.Static | BindingFlags.NonPublic) + ?? throw new InvalidOperationException("Could not find GenerateWasmBootJson.ReadRuntimeConfigFiles."); + + object? result = method.Invoke(null, new object?[] { mainConfigPath, devConfigPath }); + return (RuntimeConfigData?)result; + } + + private sealed class TempDirectory : IDisposable + { + public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); + + public TempDirectory() => Directory.CreateDirectory(Path); + + public void Dispose() + { + try + { + Directory.Delete(Path, recursive: true); + } + catch (DirectoryNotFoundException) + { + } + catch (IOException) + { + } + catch (UnauthorizedAccessException) + { + } + } + } + } +} diff --git a/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs b/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs deleted file mode 100644 index 5c52092227b342..00000000000000 --- a/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/GenerateWasmBootJsonTests.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.IO; -using System.Text.Json; -using Xunit; - -namespace Microsoft.NET.Sdk.WebAssembly.Tests; - -public class GenerateWasmBootJsonTests -{ - [Fact] - public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() - { - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(null, null); - - Assert.Null(result); - } - - [Fact] - public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() - { - using var dir = new TempDirectory(); - var nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(nonExistentPath, null); - - Assert.Null(result); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - // Write dev config with native JSON boolean and number (not string) values. - var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - File.WriteAllText(devConfigPath, """ - { - "runtimeOptions": { - "configProperties": { - "System.HotReload.Enable": true, - "System.HotReload.MaxRetries": 10 - } - } - } - """); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - var props = result!.runtimeOptions!.configProperties!; - Assert.Equal(JsonValueKind.True, ((JsonElement)props["System.HotReload.Enable"]).ValueKind); - Assert.Equal(JsonValueKind.Number, ((JsonElement)props["System.HotReload.MaxRetries"]).ValueKind); - Assert.Equal(10, ((JsonElement)props["System.HotReload.MaxRetries"]).GetInt32()); - } - - [Fact] - public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, null); - - Assert.NotNull(result); - Assert.NotNull(result.runtimeOptions?.configProperties); - Assert.Equal("value1", result.runtimeOptions!.configProperties!["key1"].ToString()); - Assert.Equal("42", result.runtimeOptions.configProperties["key2"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUnchanged() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); - - Assert.NotNull(result); - Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["key2"] = "value2" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); - Assert.Equal("value2", result.runtimeOptions.configProperties["key2"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["System.Runtime.Feature"] = "false" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["System.Runtime.Feature"] = "true" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: null); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new() { ["System.HotReload.Enable"] = "true" }); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); - } - - [Fact] - public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() - { - using var dir = new TempDirectory(); - var mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", - configProperties: new() { ["key1"] = "value1" }); - var devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", - configProperties: new()); - - var result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); - - Assert.NotNull(result?.runtimeOptions?.configProperties); - Assert.Single(result!.runtimeOptions!.configProperties!); - Assert.Equal("value1", result.runtimeOptions.configProperties["key1"].ToString()); - } - - private static string WriteRuntimeConfig(string dir, string fileName, Dictionary? configProperties) - { - var path = Path.Combine(dir, fileName); - using var stream = File.OpenWrite(path); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); - writer.WriteStartObject(); - writer.WritePropertyName("runtimeOptions"); - writer.WriteStartObject(); - if (configProperties is not null) - { - writer.WritePropertyName("configProperties"); - writer.WriteStartObject(); - foreach (var (key, value) in configProperties) - writer.WriteString(key, value); - writer.WriteEndObject(); - } - writer.WriteEndObject(); - writer.WriteEndObject(); - return path; - } - - private sealed class TempDirectory : System.IDisposable - { - public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); - - public TempDirectory() => Directory.CreateDirectory(Path); - - public void Dispose() - { - // Silently ignore cleanup failures to avoid masking actual test failures. - try { Directory.Delete(Path, recursive: true); } catch { } - } - } -} diff --git a/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj b/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj deleted file mode 100644 index 9adcea8712095e..00000000000000 --- a/src/tasks.tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.Tests.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - $(NetCoreAppToolCurrent) - enable - - - - - - - - - diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj index ecf3510c8914df..90267a01c8e52a 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj @@ -17,7 +17,6 @@ - From d11a71fd9ac92817da4c135be258da0262695617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Thu, 23 Jul 2026 18:13:12 +0200 Subject: [PATCH 11/14] [browser] Add friend access for Wasm.Build.Tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 543feee9-af37-42d8-8313-055510ee76d9 --- .../Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj index 90267a01c8e52a..aabab7b4282c1d 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj @@ -17,6 +17,7 @@ + From da0df732424799dc7c7e1004f5eec88d425795c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Thu, 23 Jul 2026 18:14:42 +0200 Subject: [PATCH 12/14] [browser] Call GenerateWasmBootJson directly in moved tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 543feee9-af37-42d8-8313-055510ee76d9 --- .../GenerateWasmBootJsonTests.cs | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs index c57e1ab0b844fd..8f33f2cabea654 100644 --- a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Reflection; using System.Text.Json; using Microsoft.NET.Sdk.WebAssembly; using Xunit; @@ -19,7 +18,7 @@ public class GenerateWasmBootJsonTests [Fact] public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() { - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(null, null); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(null, null); Assert.Null(result); } @@ -29,7 +28,7 @@ public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() { using var dir = new TempDirectory(); string nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(nonExistentPath, null); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(nonExistentPath, null); Assert.Null(result); } @@ -52,7 +51,7 @@ public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() } """); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); Assert.NotNull(result?.runtimeOptions?.configProperties); Dictionary props = result!.runtimeOptions!.configProperties!; @@ -68,7 +67,7 @@ public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, null); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, null); Assert.NotNull(result); Assert.NotNull(result.runtimeOptions?.configProperties); @@ -84,7 +83,7 @@ public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUncha configProperties: new() { ["key1"] = "value1" }); string devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); Assert.NotNull(result); Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); @@ -99,7 +98,7 @@ public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["key2"] = "value2" }); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); @@ -115,7 +114,7 @@ public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["System.Runtime.Feature"] = "true" }); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); @@ -130,7 +129,7 @@ public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties( string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["System.HotReload.Enable"] = "true" }); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); @@ -145,7 +144,7 @@ public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new()); - RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Single(result!.runtimeOptions!.configProperties!); @@ -175,17 +174,6 @@ private static string WriteRuntimeConfig(string dir, string fileName, Dictionary return path; } - private static RuntimeConfigData? InvokeReadRuntimeConfigFiles(string? mainConfigPath, string? devConfigPath) - { - MethodInfo method = typeof(GenerateWasmBootJson).GetMethod( - "ReadRuntimeConfigFiles", - BindingFlags.Static | BindingFlags.NonPublic) - ?? throw new InvalidOperationException("Could not find GenerateWasmBootJson.ReadRuntimeConfigFiles."); - - object? result = method.Invoke(null, new object?[] { mainConfigPath, devConfigPath }); - return (RuntimeConfigData?)result; - } - private sealed class TempDirectory : IDisposable { public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); From 35d62a5366c82f68fce9caddba49034cae4295ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 24 Jul 2026 10:13:37 +0200 Subject: [PATCH 13/14] [browser] Revert to reflection for boot json tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 543feee9-af37-42d8-8313-055510ee76d9 --- .../GenerateWasmBootJsonTests.cs | 36 ++++++++++++++----- ...soft.NET.Sdk.WebAssembly.Pack.Tasks.csproj | 1 - 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs index 8f33f2cabea654..a80cc97e139561 100644 --- a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Text.Json; using Microsoft.NET.Sdk.WebAssembly; using Xunit; @@ -18,7 +19,7 @@ public class GenerateWasmBootJsonTests [Fact] public void ReadRuntimeConfigFiles_NullMainConfigPath_ReturnsNull() { - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(null, null); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(null, null); Assert.Null(result); } @@ -28,7 +29,7 @@ public void ReadRuntimeConfigFiles_MainConfigNotExists_ReturnsNull() { using var dir = new TempDirectory(); string nonExistentPath = Path.Combine(dir.Path, "does-not-exist.runtimeconfig.json"); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(nonExistentPath, null); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(nonExistentPath, null); Assert.Null(result); } @@ -51,7 +52,7 @@ public void ReadRuntimeConfigFiles_DevConfigPreservesBooleanAndNumericTypes() } """); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); Assert.NotNull(result?.runtimeOptions?.configProperties); Dictionary props = result!.runtimeOptions!.configProperties!; @@ -67,7 +68,7 @@ public void ReadRuntimeConfigFiles_MainConfigOnly_ReturnsMainProperties() string mainConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.json", configProperties: new() { ["key1"] = "value1", ["key2"] = "42" }); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, null); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, null); Assert.NotNull(result); Assert.NotNull(result.runtimeOptions?.configProperties); @@ -83,7 +84,7 @@ public void ReadRuntimeConfigFiles_DevConfigNotExists_ReturnsMainPropertiesUncha configProperties: new() { ["key1"] = "value1" }); string devConfigPath = Path.Combine(dir.Path, "App.runtimeconfig.dev.json"); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfigPath); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfigPath); Assert.NotNull(result); Assert.Equal("value1", result.runtimeOptions?.configProperties?["key1"].ToString()); @@ -98,7 +99,7 @@ public void ReadRuntimeConfigFiles_DevConfigAddsNewProperty() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["key2"] = "value2" }); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("value1", result!.runtimeOptions!.configProperties!["key1"].ToString()); @@ -114,7 +115,7 @@ public void ReadRuntimeConfigFiles_DevConfigOverridesMainProperty() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["System.Runtime.Feature"] = "true" }); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.Runtime.Feature"].ToString()); @@ -129,7 +130,7 @@ public void ReadRuntimeConfigFiles_DevConfigMergesWhenMainHasNoConfigProperties( string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new() { ["System.HotReload.Enable"] = "true" }); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Equal("true", result!.runtimeOptions!.configProperties!["System.HotReload.Enable"].ToString()); @@ -144,7 +145,7 @@ public void ReadRuntimeConfigFiles_DevConfigEmptyProperties_DoesNotAlterResult() string devConfig = WriteRuntimeConfig(dir.Path, "App.runtimeconfig.dev.json", configProperties: new()); - RuntimeConfigData? result = GenerateWasmBootJson.ReadRuntimeConfigFiles(mainConfig, devConfig); + RuntimeConfigData? result = InvokeReadRuntimeConfigFiles(mainConfig, devConfig); Assert.NotNull(result?.runtimeOptions?.configProperties); Assert.Single(result!.runtimeOptions!.configProperties!); @@ -174,6 +175,23 @@ private static string WriteRuntimeConfig(string dir, string fileName, Dictionary return path; } + private static RuntimeConfigData? InvokeReadRuntimeConfigFiles(string? mainConfigPath, string? devConfigPath) + { + MethodInfo? method = typeof(GenerateWasmBootJson).GetMethod( + "ReadRuntimeConfigFiles", + BindingFlags.Static | BindingFlags.NonPublic); + + if (method is null) + { + throw new InvalidOperationException( + $"{nameof(GenerateWasmBootJson)}.{nameof(InvokeReadRuntimeConfigFiles)} could not find private method " + + "'ReadRuntimeConfigFiles(string?, string?)'. The production method signature may have changed."); + } + + object? result = method.Invoke(null, new object?[] { mainConfigPath, devConfigPath }); + return (RuntimeConfigData?)result; + } + private sealed class TempDirectory : IDisposable { public string Path { get; } = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj index aabab7b4282c1d..90267a01c8e52a 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj @@ -17,7 +17,6 @@ - From bfff07b52abc5d7a9be5ca7cac3a27af078521a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 24 Jul 2026 10:21:49 +0200 Subject: [PATCH 14/14] [browser] Use reflection for boot json tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 543feee9-af37-42d8-8313-055510ee76d9 --- src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs index a80cc97e139561..18d2023a75f41f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/GenerateWasmBootJsonTests.cs @@ -11,8 +11,8 @@ #nullable enable -namespace Wasm.Build.Tests -{ +namespace Wasm.Build.Tests; + [TestCategory("no-workload")] public class GenerateWasmBootJsonTests { @@ -215,5 +215,4 @@ public void Dispose() } } } - } }