diff --git a/test/Microsoft.NET.TestFramework/Commands/TestCommand.cs b/test/Microsoft.NET.TestFramework/Commands/TestCommand.cs index b5446a2c5b2e..ff5401650c53 100644 --- a/test/Microsoft.NET.TestFramework/Commands/TestCommand.cs +++ b/test/Microsoft.NET.TestFramework/Commands/TestCommand.cs @@ -218,10 +218,15 @@ public virtual CommandResult Execute(IEnumerable args) command.OnOutputLine(line => CommandOutputHandler.Invoke(line)); } - if (StandardOutputEncoding is not null) - { - command.StandardOutputEncoding(StandardOutputEncoding); - } + // Decode captured stdout as UTF-8 by default so non-ASCII output (e.g. localized + // strings such as the French "Bienvenue à .Net!") is not corrupted by the host + // console's active code page. Child dotnet/MSBuild processes emit UTF-8; when + // StandardOutputEncoding is left null, Process decodes the redirected stream using + // Console.OutputEncoding, which on Windows is the OEM code page (e.g. CP437/850) and + // turns UTF-8 bytes like 0xC3 0xA0 ('à') into mojibake ('├á'). Because the active code + // page varies by agent, tests asserting on non-ASCII output failed intermittently. On + // non-Windows the default capture encoding is already UTF-8, so this is a no-op there. + command.StandardOutputEncoding(StandardOutputEncoding ?? Encoding.UTF8); } string fileToShow = Path.GetFileNameWithoutExtension(spec.FileName!).Equals("dotnet", StringComparison.OrdinalIgnoreCase) ? diff --git a/test/TestAssets/TestProjects/KitchenSink/TestApp/Program.cs b/test/TestAssets/TestProjects/KitchenSink/TestApp/Program.cs index 20987f7bd003..547a8960af08 100644 --- a/test/TestAssets/TestProjects/KitchenSink/TestApp/Program.cs +++ b/test/TestAssets/TestProjects/KitchenSink/TestApp/Program.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Resources; using System.Reflection; +using System.Text; namespace TestApp { @@ -13,6 +14,14 @@ public class Program { public static void Main(string[] args) { + // Emit UTF-8 deterministically so the localized (non-ASCII) strings this app prints + // survive being captured by a test harness. When stdout is redirected, Console defaults + // its output encoding to the host's console code page (e.g. the OEM code page CP437/CP850 + // on Windows CI agents), which varies by machine. That made the encoding of characters + // such as the French 'à' non-deterministic and the satellite-assembly test flaky. Forcing + // UTF-8 here (a no-op on platforms that already default to UTF-8, and BOM-free because + // Console strips the preamble) pairs with the harness capturing stdout as UTF-8. + Console.OutputEncoding = Encoding.UTF8; Console.WriteLine(TestLibrary.Helper.GetMessage()); VerifySatelliteAssemblies(); }