From 9838f79640cb642ee745c90e3c216b416b1629f3 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Tue, 20 Jan 2026 17:03:20 +0000 Subject: [PATCH 1/5] [ci] Remove trimming workaround --- .../netstandard2.0/Microsoft.Maui.Controls.Common.targets | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets index 55462cab2279..36d798563dbe 100644 --- a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets +++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets @@ -11,12 +11,6 @@ '$([MSBuild]::GetTargetPlatformIdentifier($(TargetFramework)))' == 'tizen')">True - - - false - true - - From a55908b6186bc5e589a30ee5ad93db29dca58648 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 20 Jan 2026 15:56:21 -0600 Subject: [PATCH 2/5] [ci] Output build errors from binlog to Azure DevOps logs When integration tests fail to build, extract and display errors from the binlog file directly to the console. This makes errors visible in Azure DevOps task logs without requiring artifact downloads. - Add OutputBuildErrorsFromBinLog() method to BuildWarningsUtilities - Call it automatically when Build() or Publish() fails in DotnetInternal - Limits output to 50 errors by default for readability --- .../Utilities/BuildWarningsUtilities.cs | 46 ++++++++++++++++++- .../Utilities/DotnetInternal.cs | 28 ++++++++--- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs index 9361fd3bfa9e..083b99dc79ef 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.IO; +using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Logging.StructuredLogger; @@ -25,6 +26,49 @@ public static class BuildWarningsUtilities private static string NormalizeFilePath(string file) => file.Replace("\\\\", "/", StringComparison.Ordinal).Replace('\\', '/'); + /// + /// Reads build errors from a binlog file and outputs them to the console. + /// This makes errors visible in Azure DevOps logs instead of requiring artifact downloads. + /// + /// Path to the .binlog file + /// Maximum number of errors to output (default 50) + public static void OutputBuildErrorsFromBinLog(string binLogFilePath, int maxErrors = 50) + { + if (!File.Exists(binLogFilePath)) + { + Console.WriteLine($"[BuildWarningsUtilities] Binlog file not found: {binLogFilePath}"); + return; + } + + var errors = new List(); + foreach (var record in new BinLogReader().ReadRecords(binLogFilePath)) + { + if (record.Args is BuildErrorEventArgs error) + { + var file = NormalizeFilePath(error.File ?? ""); + var location = error.LineNumber > 0 ? $"({error.LineNumber},{error.ColumnNumber})" : ""; + errors.Add($"{file}{location}: error {error.Code}: {error.Message}"); + } + } + + if (errors.Count > 0) + { + Console.WriteLine(); + Console.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); + Console.WriteLine($"║ BUILD ERRORS FROM BINLOG ({errors.Count} total)"); + Console.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); + foreach (var error in errors.Take(maxErrors)) + { + Console.WriteLine(error); + } + if (errors.Count > maxErrors) + { + Console.WriteLine($"... and {errors.Count - maxErrors} more errors (see binlog for full list)"); + } + Console.WriteLine(); + } + } + public static List ReadNativeAOTWarningsFromBinLog(string binLogFilePath) { var actualWarnings = new List(); diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs index db9d30f2d6ff..d022af594a7e 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs @@ -9,7 +9,7 @@ public static class DotnetInternal static readonly string DotnetTool = Path.Combine(DotnetRoot, "dotnet"); const int DEFAULT_TIMEOUT = 1800; - private static string ConstructBuildArgs(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", string runtimeIdentifier = "", bool isPublishing = false) + private static (string buildArgs, string binlogPath) ConstructBuildArgs(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", string runtimeIdentifier = "", bool isPublishing = false) { var buildArgs = $"\"{projectFile}\" -c {config}"; @@ -43,13 +43,13 @@ private static string ConstructBuildArgs(string projectFile, string config, stri } buildArgs += $" -bl:\"{binlogPath}\""; - return buildArgs; + return (buildArgs, binlogPath); } public static bool Build(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", bool msbuildWarningsAsErrors = false, string runtimeIdentifier = "", string[]? warningsToIgnore = null) { - var buildArgs = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, false); + var (buildArgs, actualBinlogPath) = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, false); if (msbuildWarningsAsErrors) { @@ -78,13 +78,29 @@ public static bool Build(string projectFile, string config, string target = "", buildArgs += $" -p:nowarn=\"{csWarnings}\""; } - return Run("build", $"{buildArgs}"); + var result = Run("build", $"{buildArgs}"); + + // On failure, extract and output errors from the binlog for visibility in CI logs + if (!result) + { + BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath); + } + + return result; } public static bool Publish(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", string runtimeIdentifier = "") { - var buildArgs = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, true); - return Run("publish", $"{buildArgs}"); + var (buildArgs, actualBinlogPath) = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, true); + var result = Run("publish", $"{buildArgs}"); + + // On failure, extract and output errors from the binlog for visibility in CI logs + if (!result) + { + BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath); + } + + return result; } public static bool New(string shortName, string outputDirectory, string framework = "", string? additionalDotNetNewParams = null) From 07a9761f0d76e794fd5dc497c78975275fc0199c Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 20 Jan 2026 17:20:24 -0600 Subject: [PATCH 3/5] [ci] Enable ShowLiveOutput for integration tests This makes Console.WriteLine output from tests visible in Azure DevOps task logs, including the build errors extracted from binlogs when a build fails. --- eng/pipelines/arcade/stage-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/arcade/stage-integration-tests.yml b/eng/pipelines/arcade/stage-integration-tests.yml index d7b0a4d75ab7..cfc034ea23bd 100644 --- a/eng/pipelines/arcade/stage-integration-tests.yml +++ b/eng/pipelines/arcade/stage-integration-tests.yml @@ -40,7 +40,7 @@ stages: mauiSourcePath: ${{ parameters.mauiSourcePath }} command: test project: ${{ parameters.mauiSourcePath }}/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj - arguments: '-c ${{ parameters.buildConfig }} --filter "$(testFilter)" --logger trx --results-directory $(Agent.TempDirectory)/Microsoft.Maui.IntegrationTests' + arguments: '-c ${{ parameters.buildConfig }} --filter "$(testFilter)" --logger trx --results-directory $(Agent.TempDirectory)/Microsoft.Maui.IntegrationTests -- RunConfiguration.ShowLiveOutput=true' useExitCodeForErrors: true retryCountOnTaskFailure: 1 # Set IOS_TEST_DEVICE for all iOS-related tests (RunOniOS and RunOniOS_*) From f524f88b2ad54cc64d4c2bf2468e123de2a6ce88 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 20 Jan 2026 17:44:14 -0600 Subject: [PATCH 4/5] Use ITestOutputHelper for integration test output - Add ITestOutputHelper parameter to all utility methods (DotnetInternal, ToolRunner, XHarness, Adb, Emulator, Simulator) - Replace Console.WriteLine with output?.WriteLine for proper xUnit test output - Add ShowLiveOutput=true to csproj for CI visibility - All parameters are optional to maintain backward compatibility --- .../arcade/stage-integration-tests.yml | 2 +- .../Android/Adb.cs | 27 +++---- .../Android/Emulator.cs | 37 ++++----- .../Apple/Simulator.cs | 23 ++++-- .../Microsoft.Maui.IntegrationTests.csproj | 2 + .../Utilities/BuildWarningsUtilities.cs | 24 +++--- .../Utilities/DotnetInternal.cs | 77 ++++++++++--------- .../Utilities/ToolRunner.cs | 12 +-- .../Utilities/XHarness.cs | 35 +++++---- 9 files changed, 129 insertions(+), 110 deletions(-) diff --git a/eng/pipelines/arcade/stage-integration-tests.yml b/eng/pipelines/arcade/stage-integration-tests.yml index cfc034ea23bd..d7b0a4d75ab7 100644 --- a/eng/pipelines/arcade/stage-integration-tests.yml +++ b/eng/pipelines/arcade/stage-integration-tests.yml @@ -40,7 +40,7 @@ stages: mauiSourcePath: ${{ parameters.mauiSourcePath }} command: test project: ${{ parameters.mauiSourcePath }}/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj - arguments: '-c ${{ parameters.buildConfig }} --filter "$(testFilter)" --logger trx --results-directory $(Agent.TempDirectory)/Microsoft.Maui.IntegrationTests -- RunConfiguration.ShowLiveOutput=true' + arguments: '-c ${{ parameters.buildConfig }} --filter "$(testFilter)" --logger trx --results-directory $(Agent.TempDirectory)/Microsoft.Maui.IntegrationTests' useExitCodeForErrors: true retryCountOnTaskFailure: 1 # Set IOS_TEST_DEVICE for all iOS-related tests (RunOniOS and RunOniOS_*) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Adb.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Adb.cs index 37f359aa5726..cee13f56c3ec 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Adb.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Adb.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests.Android { @@ -7,16 +8,16 @@ public static class Adb static readonly string AdbTool = Path.Combine(TestEnvironment.GetAndroidSdkPath(), "platform-tools", "adb"); const int DEFAULT_TIMEOUT = 20; - public static bool WaitForEmulator(int timeout, string deviceId = "") + public static bool WaitForEmulator(int timeout, string deviceId = "", ITestOutputHelper? output = null) { var maxWaitTime = DateTime.UtcNow.AddSeconds(timeout); int currentWaitTime = 0; bool bootCompleted = false; while (DateTime.UtcNow < maxWaitTime && !bootCompleted) { - Console.WriteLine($"Waiting {currentWaitTime}/{timeout} seconds for the emulator to boot up..."); - var adbOutput = RunForOutput(GetArgs("shell getprop sys.boot_completed", deviceId), out _); - Console.WriteLine($"sys.boot_completed: {adbOutput}"); + output?.WriteLine($"Waiting {currentWaitTime}/{timeout} seconds for the emulator to boot up..."); + var adbOutput = RunForOutput(GetArgs("shell getprop sys.boot_completed", deviceId), out _, output: output); + output?.WriteLine($"sys.boot_completed: {adbOutput}"); int.TryParse(adbOutput, out int bootCompletedPropValue); bootCompleted = bootCompletedPropValue == 1; Thread.Sleep(10000); @@ -25,14 +26,14 @@ public static bool WaitForEmulator(int timeout, string deviceId = "") return bootCompleted; } - public static bool KillEmulator(string deviceId = "") + public static bool KillEmulator(string deviceId = "", ITestOutputHelper? output = null) { - return Run(GetArgs("emu kill", deviceId)); + return Run(GetArgs("emu kill", deviceId), output: output); } - public static bool UninstallPackage(string package, string deviceId = "") + public static bool UninstallPackage(string package, string deviceId = "", ITestOutputHelper? output = null) { - return Run(GetArgs($"uninstall {package}", deviceId)); + return Run(GetArgs($"uninstall {package}", deviceId), output: output); } static string GetArgs(string args, string deviceId) @@ -40,18 +41,18 @@ static string GetArgs(string args, string deviceId) return string.IsNullOrEmpty(deviceId) ? args : $"-s {deviceId} " + args; } - public static bool Run(string args, int timeout = DEFAULT_TIMEOUT, string deviceId = "") + public static bool Run(string args, int timeout = DEFAULT_TIMEOUT, string deviceId = "", ITestOutputHelper? output = null) { - RunForOutput(args, out int exitCode, timeout, deviceId); + RunForOutput(args, out int exitCode, timeout, deviceId, output: output); if (exitCode != 0) - Console.WriteLine(exitCode); + output?.WriteLine(exitCode.ToString()); return exitCode == 0; } - public static string RunForOutput(string args, out int exitCode, int timeout = DEFAULT_TIMEOUT, string deviceId = "") + public static string RunForOutput(string args, out int exitCode, int timeout = DEFAULT_TIMEOUT, string deviceId = "", ITestOutputHelper? output = null) { - return ToolRunner.Run(AdbTool, GetArgs(args, deviceId), out exitCode, timeoutInSeconds: timeout); + return ToolRunner.Run(AdbTool, GetArgs(args, deviceId), out exitCode, timeoutInSeconds: timeout, output: output); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Emulator.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Emulator.cs index c066e3150087..ab34a5f17f90 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Emulator.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Android/Emulator.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests.Android { @@ -18,7 +19,7 @@ public class Emulator public string Id => $"emulator-{Port}"; public string SystemImageId => $"system-images;android-{ApiLevel};{ImageType};{Abi}"; - public bool AcceptLicenses(out string acceptLicenseOutput) + public bool AcceptLicenses(out string acceptLicenseOutput, ITestOutputHelper? output = null) { acceptLicenseOutput = ToolRunner.Run(new ProcessStartInfo(SdkManagerTool, "--licenses"), out int exitCode, timeoutInSeconds: 30, inputAction: (p) => { @@ -26,61 +27,61 @@ public bool AcceptLicenses(out string acceptLicenseOutput) { p.StandardInput.WriteLine('y'); } - }); + }, output: output); if (exitCode != 0) - Console.WriteLine(acceptLicenseOutput); + output?.WriteLine(acceptLicenseOutput); return exitCode == 0; } - public bool InstallAvd(out string installOutput) + public bool InstallAvd(out string installOutput, ITestOutputHelper? output = null) { - installOutput = ToolRunner.Run(SdkManagerTool, $"\"{SystemImageId}\"", out int exitCode, timeoutInSeconds: 180); + installOutput = ToolRunner.Run(SdkManagerTool, $"\"{SystemImageId}\"", out int exitCode, timeoutInSeconds: 180, output: output); if (exitCode != 0) - Console.WriteLine(installOutput); + output?.WriteLine(installOutput); return exitCode == 0; } - public bool DeleteAvd() + public bool DeleteAvd(ITestOutputHelper? output = null) { - var deleteOutput = ToolRunner.Run(AvdManagerTool, $"delete avd -n {Name}", out int exitCode, timeoutInSeconds: 15); + var deleteOutput = ToolRunner.Run(AvdManagerTool, $"delete avd -n {Name}", out int exitCode, timeoutInSeconds: 15, output: output); return exitCode == 0 || deleteOutput.Contains($"There is no Android Virtual Device named '{Name}'", StringComparison.OrdinalIgnoreCase); } - public bool CreateAvd(bool force = true) + public bool CreateAvd(bool force = true, ITestOutputHelper? output = null) { var createArgs = $"create avd -n {Name} -k \"{SystemImageId}\" -d {DeviceType}"; if (force) createArgs += " -f"; - var createOutput = ToolRunner.Run(AvdManagerTool, createArgs, out int exitCode, timeoutInSeconds: 15); + var createOutput = ToolRunner.Run(AvdManagerTool, createArgs, out int exitCode, timeoutInSeconds: 15, output: output); if (exitCode != 0) - Console.WriteLine(createOutput); + output?.WriteLine(createOutput); return exitCode == 0; } - public bool LaunchAndWaitForAvd(int timeToWaitInSeconds, string logFile) + public bool LaunchAndWaitForAvd(int timeToWaitInSeconds, string logFile, ITestOutputHelper? output = null) { - if (Adb.WaitForEmulator(10, Id)) + if (Adb.WaitForEmulator(10, Id, output: output)) return true; - if (!DeleteAvd()) + if (!DeleteAvd(output: output)) return false; - if (!CreateAvd()) + if (!CreateAvd(output: output)) return false; var launchArgs = $"-verbose -detect-image-hang -port {Port} -avd {Name}"; launchArgs += TestEnvironment.IsRunningOnCI ? " -no-window -no-boot-anim -no-audio -no-snapshot -cache-size 512" : string.Empty; // Emulator process does not stop once the emulator is running, end it after 15 seconds and then begin polling for boot success - Console.WriteLine($"Launching AVD: {Name}..."); - var emulatorOutput = ToolRunner.Run(EmulatorTool, launchArgs, out _, timeoutInSeconds: 15); + output?.WriteLine($"Launching AVD: {Name}..."); + var emulatorOutput = ToolRunner.Run(EmulatorTool, launchArgs, out _, timeoutInSeconds: 15, output: output); File.WriteAllText(logFile, emulatorOutput); - return Adb.WaitForEmulator(timeToWaitInSeconds, Id); + return Adb.WaitForEmulator(timeToWaitInSeconds, Id, output: output); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Apple/Simulator.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Apple/Simulator.cs index 26dcd788abfe..3458da5e98fb 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Apple/Simulator.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Apple/Simulator.cs @@ -1,10 +1,17 @@ using System.Text.Json; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests.Apple { public class Simulator { readonly string XCRunTool = "xcrun"; + readonly ITestOutputHelper? _output; + + public Simulator(ITestOutputHelper? output = null) + { + _output = output; + } string? _xharnessID; @@ -45,12 +52,12 @@ string ResolveXHarnessID() { var versionSuffix = $"{latestVersion.Major}.{latestVersion.Minor}"; var resolvedTarget = $"{baseTarget}_{versionSuffix}"; - Console.WriteLine($"Auto-detected iOS target: {resolvedTarget}"); + _output?.WriteLine($"Auto-detected iOS target: {resolvedTarget}"); return resolvedTarget; } // Fallback to base target (may fail if XHarness can't find a match) - Console.WriteLine($"Warning: Could not auto-detect iOS version, using '{baseTarget}' which may fail."); + _output?.WriteLine($"Warning: Could not auto-detect iOS version, using '{baseTarget}' which may fail."); return baseTarget; } @@ -62,7 +69,7 @@ string ResolveXHarnessID() { try { - var output = ToolRunner.Run(XCRunTool, "simctl list runtimes --json", out int exitCode, timeoutInSeconds: 30); + var output = ToolRunner.Run(XCRunTool, "simctl list runtimes --json", out int exitCode, timeoutInSeconds: 30, output: _output); if (exitCode != 0 || string.IsNullOrEmpty(output)) return null; @@ -99,7 +106,7 @@ string ResolveXHarnessID() } catch (Exception ex) { - Console.WriteLine($"Failed to detect iOS version: {ex.Message}"); + _output?.WriteLine($"Failed to detect iOS version: {ex.Message}"); return null; } } @@ -110,7 +117,7 @@ public string GetUDID() if (!string.IsNullOrEmpty(_udid)) return _udid; - var xharnessOutput = XHarness.GetSimulatorUDID(XHarnessID).Trim(); + var xharnessOutput = XHarness.GetSimulatorUDID(XHarnessID, output: _output).Trim(); // XHarness returns a UDID on success, or an error message on failure. // A valid UDID is a UUID format (e.g., "DE87D078-70D4-47F6-9F21-82612D9D4F7E") @@ -132,7 +139,7 @@ static bool IsValidUDID(string value) public bool Launch() { - var output = ToolRunner.Run(XCRunTool, $"simctl boot {GetUDID()}", out int exitCode, timeoutInSeconds: 30); + var output = ToolRunner.Run(XCRunTool, $"simctl boot {GetUDID()}", out int exitCode, timeoutInSeconds: 30, output: _output); // Exit code 0 = successfully booted // Exit code 149 with "current state: Booted" = already running (also success) return exitCode == 0 || (exitCode == 149 && output.Contains("current state: Booted", StringComparison.Ordinal)); @@ -140,13 +147,13 @@ public bool Launch() public bool Shutdown() { - ToolRunner.Run(XCRunTool, $"simctl shutdown {GetUDID()}", out int exitCode, timeoutInSeconds: 60); + ToolRunner.Run(XCRunTool, $"simctl shutdown {GetUDID()}", out int exitCode, timeoutInSeconds: 60, output: _output); return exitCode == 0; } public bool ShowWindow() { - ToolRunner.Run("open", $"-a Simulator", out int exitCode, timeoutInSeconds: 30); + ToolRunner.Run("open", $"-a Simulator", out int exitCode, timeoutInSeconds: 30, output: _output); return exitCode == 0; } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj index 54f8184a964d..5a27d251ccaa 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Microsoft.Maui.IntegrationTests.csproj @@ -6,6 +6,8 @@ enable false Major + + true diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs index 083b99dc79ef..04f270a99b1f 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs @@ -2,6 +2,7 @@ using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Logging.StructuredLogger; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests { @@ -27,16 +28,17 @@ public static class BuildWarningsUtilities private static string NormalizeFilePath(string file) => file.Replace("\\\\", "/", StringComparison.Ordinal).Replace('\\', '/'); /// - /// Reads build errors from a binlog file and outputs them to the console. + /// Reads build errors from a binlog file and outputs them to the test output. /// This makes errors visible in Azure DevOps logs instead of requiring artifact downloads. /// /// Path to the .binlog file /// Maximum number of errors to output (default 50) - public static void OutputBuildErrorsFromBinLog(string binLogFilePath, int maxErrors = 50) + /// Optional test output helper for logging + public static void OutputBuildErrorsFromBinLog(string binLogFilePath, int maxErrors = 50, ITestOutputHelper? output = null) { if (!File.Exists(binLogFilePath)) { - Console.WriteLine($"[BuildWarningsUtilities] Binlog file not found: {binLogFilePath}"); + output?.WriteLine($"[BuildWarningsUtilities] Binlog file not found: {binLogFilePath}"); return; } @@ -53,19 +55,19 @@ public static void OutputBuildErrorsFromBinLog(string binLogFilePath, int maxErr if (errors.Count > 0) { - Console.WriteLine(); - Console.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); - Console.WriteLine($"║ BUILD ERRORS FROM BINLOG ({errors.Count} total)"); - Console.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); - foreach (var error in errors.Take(maxErrors)) + output?.WriteLine(""); + output?.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); + output?.WriteLine($"║ BUILD ERRORS FROM BINLOG ({errors.Count} total)"); + output?.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); + foreach (var err in errors.Take(maxErrors)) { - Console.WriteLine(error); + output?.WriteLine(err); } if (errors.Count > maxErrors) { - Console.WriteLine($"... and {errors.Count - maxErrors} more errors (see binlog for full list)"); + output?.WriteLine($"... and {errors.Count - maxErrors} more errors (see binlog for full list)"); } - Console.WriteLine(); + output?.WriteLine(""); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs index d022af594a7e..4d41b1deebcf 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/DotnetInternal.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.IO; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests { @@ -47,7 +48,7 @@ private static (string buildArgs, string binlogPath) ConstructBuildArgs(string p } public static bool Build(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", bool msbuildWarningsAsErrors = false, string runtimeIdentifier = "", - string[]? warningsToIgnore = null) + string[]? warningsToIgnore = null, ITestOutputHelper? output = null) { var (buildArgs, actualBinlogPath) = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, false); @@ -78,32 +79,32 @@ public static bool Build(string projectFile, string config, string target = "", buildArgs += $" -p:nowarn=\"{csWarnings}\""; } - var result = Run("build", $"{buildArgs}"); + var result = Run("build", $"{buildArgs}", output: output); // On failure, extract and output errors from the binlog for visibility in CI logs if (!result) { - BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath); + BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath, output: output); } return result; } - public static bool Publish(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", string runtimeIdentifier = "") + public static bool Publish(string projectFile, string config, string target = "", string framework = "", IEnumerable? properties = null, string binlogPath = "", string runtimeIdentifier = "", ITestOutputHelper? output = null) { var (buildArgs, actualBinlogPath) = ConstructBuildArgs(projectFile, config, target, framework, properties, binlogPath, runtimeIdentifier, true); - var result = Run("publish", $"{buildArgs}"); + var result = Run("publish", $"{buildArgs}", output: output); // On failure, extract and output errors from the binlog for visibility in CI logs if (!result) { - BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath); + BuildWarningsUtilities.OutputBuildErrorsFromBinLog(actualBinlogPath, output: output); } return result; } - public static bool New(string shortName, string outputDirectory, string framework = "", string? additionalDotNetNewParams = null) + public static bool New(string shortName, string outputDirectory, string framework = "", string? additionalDotNetNewParams = null, ITestOutputHelper? output = null) { var args = $"{shortName} -o \"{outputDirectory}\""; @@ -114,23 +115,23 @@ public static bool New(string shortName, string outputDirectory, string framewor args += $" {additionalDotNetNewParams}"; - var output = RunForOutput("new", args, out int exitCode, timeoutInSeconds: 300); - Console.WriteLine(output); + var cmdOutput = RunForOutput("new", args, out int exitCode, timeoutInSeconds: 300, output: output); + output?.WriteLine(cmdOutput); return exitCode == 0; } - public static bool Run(string command, string args, int timeoutinSeconds = DEFAULT_TIMEOUT) + public static bool Run(string command, string args, int timeoutinSeconds = DEFAULT_TIMEOUT, ITestOutputHelper? output = null) { - var runOutput = RunForOutput(command, args, out int exitCode, timeoutinSeconds); - Console.WriteLine($"Process exit code: {exitCode}"); - Console.WriteLine($"-------- Process output start --------"); - Console.WriteLine(runOutput); - Console.WriteLine($"-------- Process output end --------"); + var runOutput = RunForOutput(command, args, out int exitCode, timeoutinSeconds, output: output); + output?.WriteLine($"Process exit code: {exitCode}"); + output?.WriteLine($"-------- Process output start --------"); + output?.WriteLine(runOutput); + output?.WriteLine($"-------- Process output end --------"); // Provide helpful messages for common errors if (exitCode != 0) { - CheckForCommonErrors(runOutput); + CheckForCommonErrors(runOutput, output); } return exitCode == 0; @@ -139,43 +140,43 @@ public static bool Run(string command, string args, int timeoutinSeconds = DEFAU /// /// Checks build output for common errors and provides helpful guidance. /// - static void CheckForCommonErrors(string output) + static void CheckForCommonErrors(string cmdOutput, ITestOutputHelper? output) { // Check for Xcode version mismatch - if (output.Contains("requires Xcode", StringComparison.OrdinalIgnoreCase) && output.Contains("The current version of Xcode is", StringComparison.OrdinalIgnoreCase)) + if (cmdOutput.Contains("requires Xcode", StringComparison.OrdinalIgnoreCase) && cmdOutput.Contains("The current version of Xcode is", StringComparison.OrdinalIgnoreCase)) { // Extract the error message line for display - var errorLine = output.Split('\n') + var errorLine = cmdOutput.Split('\n') .FirstOrDefault(line => line.Contains("requires Xcode", StringComparison.OrdinalIgnoreCase)) ?.Trim() ?? "Xcode version mismatch"; - Console.WriteLine(""); - Console.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); - Console.WriteLine("║ XCODE VERSION MISMATCH DETECTED ║"); - Console.WriteLine("╠══════════════════════════════════════════════════════════════════════════════╣"); - Console.WriteLine($" {errorLine}"); - Console.WriteLine("╠══════════════════════════════════════════════════════════════════════════════╣"); - Console.WriteLine("║ To skip Xcode version validation, you can: ║"); - Console.WriteLine("║ ║"); - Console.WriteLine("║ 1. Set environment variable: ║"); - Console.WriteLine("║ export SKIP_XCODE_VERSION_CHECK=true ║"); - Console.WriteLine("║ ║"); - Console.WriteLine("║ 2. Or set SkipXcodeVersionCheck in TestEnvironment.cs ║"); - Console.WriteLine("║ src/TestUtils/src/.../Utilities/TestEnvironment.cs ║"); - Console.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); - Console.WriteLine(""); + output?.WriteLine(""); + output?.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); + output?.WriteLine("║ XCODE VERSION MISMATCH DETECTED ║"); + output?.WriteLine("╠══════════════════════════════════════════════════════════════════════════════╣"); + output?.WriteLine($" {errorLine}"); + output?.WriteLine("╠══════════════════════════════════════════════════════════════════════════════╣"); + output?.WriteLine("║ To skip Xcode version validation, you can: ║"); + output?.WriteLine("║ ║"); + output?.WriteLine("║ 1. Set environment variable: ║"); + output?.WriteLine("║ export SKIP_XCODE_VERSION_CHECK=true ║"); + output?.WriteLine("║ ║"); + output?.WriteLine("║ 2. Or set SkipXcodeVersionCheck in TestEnvironment.cs ║"); + output?.WriteLine("║ src/TestUtils/src/.../Utilities/TestEnvironment.cs ║"); + output?.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); + output?.WriteLine(""); } } - public static string RunForOutput(string command, string args, out int exitCode, int timeoutInSeconds = DEFAULT_TIMEOUT) + public static string RunForOutput(string command, string args, out int exitCode, int timeoutInSeconds = DEFAULT_TIMEOUT, ITestOutputHelper? output = null) { - Console.WriteLine($"Running: '{DotnetTool}' with '{command}'"); - Console.WriteLine($"Args list: {args}"); + output?.WriteLine($"Running: '{DotnetTool}' with '{command}'"); + output?.WriteLine($"Args list: {args}"); var pinfo = new ProcessStartInfo(DotnetTool, $"{command} {args}"); pinfo.EnvironmentVariables["DOTNET_MULTILEVEL_LOOKUP"] = "0"; pinfo.EnvironmentVariables["DOTNET_ROOT"] = DotnetRoot; - return ToolRunner.Run(pinfo, out exitCode, timeoutInSeconds: timeoutInSeconds); + return ToolRunner.Run(pinfo, out exitCode, timeoutInSeconds: timeoutInSeconds, output: output); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/ToolRunner.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/ToolRunner.cs index 48358f066c2e..32509f4a7a10 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/ToolRunner.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/ToolRunner.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Text; +using Xunit.Abstractions; namespace Microsoft.Maui.IntegrationTests { @@ -7,24 +8,25 @@ public static class ToolRunner { public static string Run(string tool, string args, out int exitCode, string workingDirectory = "", - int timeoutInSeconds = 600) + int timeoutInSeconds = 600, + ITestOutputHelper? output = null) { var info = new ProcessStartInfo(tool, args); if (Directory.Exists(workingDirectory)) info.WorkingDirectory = workingDirectory; - return Run(info, out exitCode, timeoutInSeconds); + return Run(info, out exitCode, timeoutInSeconds, output: output); } public static string Run(ProcessStartInfo info, out int exitCode, - int timeoutInSeconds = 600, Action? inputAction = null) + int timeoutInSeconds = 600, Action? inputAction = null, ITestOutputHelper? output = null) { var procOutput = new StringBuilder(); using (var p = new Process()) { p.StartInfo = info; - Console.WriteLine($"[ToolRunner] Running: {p.StartInfo.FileName} {p.StartInfo.Arguments}"); + output?.WriteLine($"[ToolRunner] Running: {p.StartInfo.FileName} {p.StartInfo.Arguments}"); p.StartInfo.CreateNoWindow = true; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; @@ -62,7 +64,7 @@ public static string Run(ProcessStartInfo info, out int exitCode, if (p.WaitForExit(timeoutInSeconds * 1000)) { exitCode = p.ExitCode; - Console.WriteLine($"[ToolRunner] Process '{Path.GetFileName(p.StartInfo.FileName)}' exited with code: {exitCode}"); + output?.WriteLine($"[ToolRunner] Process '{Path.GetFileName(p.StartInfo.FileName)}' exited with code: {exitCode}"); } else { diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/XHarness.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/XHarness.cs index 47e69166fb06..288393d0aabf 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/XHarness.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/XHarness.cs @@ -1,15 +1,17 @@ -namespace Microsoft.Maui.IntegrationTests +using Xunit.Abstractions; + +namespace Microsoft.Maui.IntegrationTests { public static class XHarness { static readonly string XHarnessTool = "xharness"; const int DEFAULT_TIMEOUT = 300; - public static bool RunAndroid(string packageName, string resultDir, int expectedExitCode, int launchTimeoutSeconds = 120) + public static bool RunAndroid(string packageName, string resultDir, int expectedExitCode, int launchTimeoutSeconds = 120, ITestOutputHelper? output = null) { var timeoutString = TimeSpan.FromSeconds(launchTimeoutSeconds).ToString(); var args = $"android run --package-name={packageName} --output-directory=\"{resultDir}\" --expected-exit-code={expectedExitCode} --timeout=\"{timeoutString}\" --verbosity=Debug"; - return Run(args, launchTimeoutSeconds + 30); + return Run(args, launchTimeoutSeconds + 30, output: output); } /// @@ -25,8 +27,9 @@ public static bool RunAndroid(string packageName, string resultDir, int expected /// XHarness target device string (e.g., "ios-simulator-64_18.5") /// Optional specific device UDID to use /// How long to let the app run before killing it (default: 15s) + /// Optional test output helper for logging /// True if the app ran successfully (didn't crash), false otherwise - public static bool RunAppleForTimeout(string appPath, string resultDir, string targetDevice, string? deviceUdid = null, int launchTimeoutSeconds = 15) + public static bool RunAppleForTimeout(string appPath, string resultDir, string targetDevice, string? deviceUdid = null, int launchTimeoutSeconds = 15, ITestOutputHelper? output = null) { var timeoutString = TimeSpan.FromSeconds(launchTimeoutSeconds).ToString(); @@ -37,7 +40,7 @@ public static bool RunAppleForTimeout(string appPath, string resultDir, string t } var args = $"apple run --app=\"{appPath}\" --output-directory=\"{resultDir}\" {deviceArg} --timeout=\"{timeoutString}\" --verbosity=Debug"; - var xhOutput = RunForOutput(args, out int exitCode, launchTimeoutSeconds + 30); + var xhOutput = RunForOutput(args, out int exitCode, launchTimeoutSeconds + 30, output: output); // XHarness exit codes - see https://github.com/dotnet/xharness/blob/main/src/Microsoft.DotNet.XHarness.Common/CLI/ExitCode.cs // Success cases: @@ -55,38 +58,38 @@ public static bool RunAppleForTimeout(string appPath, string resultDir, string t if (!isSuccess) { - Console.WriteLine($"XHarness failed with exit code {exitCode}"); - Console.WriteLine(xhOutput); + output?.WriteLine($"XHarness failed with exit code {exitCode}"); + output?.WriteLine(xhOutput); } return isSuccess; } - public static bool InstallSimulator(string targetDevice) + public static bool InstallSimulator(string targetDevice, ITestOutputHelper? output = null) { - return Run($"apple simulators install \"{targetDevice}\" "); + return Run($"apple simulators install \"{targetDevice}\" ", output: output); } - public static string GetSimulatorUDID(string targetDevice) + public static string GetSimulatorUDID(string targetDevice, ITestOutputHelper? output = null) { var logDir = TestEnvironment.GetLogDirectory(); Directory.CreateDirectory(logDir); var diagnosticsPath = Path.Combine(logDir, $"xharness-device-{targetDevice.Replace("/", "-", StringComparison.Ordinal)}.log"); - return RunForOutput($"apple device \"{targetDevice}\" --diagnostics=\"{diagnosticsPath}\"", out _, timeoutInSeconds: 30); + return RunForOutput($"apple device \"{targetDevice}\" --diagnostics=\"{diagnosticsPath}\"", out _, timeoutInSeconds: 30, output: output); } - public static bool Run(string args, int timeoutInSeconds = DEFAULT_TIMEOUT) + public static bool Run(string args, int timeoutInSeconds = DEFAULT_TIMEOUT, ITestOutputHelper? output = null) { - var xhOutput = RunForOutput(args, out int exitCode, timeoutInSeconds); + var xhOutput = RunForOutput(args, out int exitCode, timeoutInSeconds, output: output); if (exitCode != 0) - Console.WriteLine(xhOutput); + output?.WriteLine(xhOutput); return exitCode == 0; } - public static string RunForOutput(string args, out int exitCode, int timeoutInSeconds = DEFAULT_TIMEOUT) + public static string RunForOutput(string args, out int exitCode, int timeoutInSeconds = DEFAULT_TIMEOUT, ITestOutputHelper? output = null) { - return DotnetInternal.RunForOutput(XHarnessTool, args, out exitCode, timeoutInSeconds); + return DotnetInternal.RunForOutput(XHarnessTool, args, out exitCode, timeoutInSeconds, output: output); } } } \ No newline at end of file From 370550f4756679d277c497e366dab506c1ea4092 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 20 Jan 2026 20:39:41 -0600 Subject: [PATCH 5/5] Pass ITestOutputHelper to all utility method call sites Updated all call sites in integration tests to pass _output to: - DotnetInternal.Build() - DotnetInternal.New() - DotnetInternal.Publish() - DotnetInternal.Run() - DotnetInternal.RunForOutput() - XHarness.RunAppleForTimeout() This enables ITestOutputHelper output to flow through to Azure DevOps pipeline logs via ShowLiveOutput=true, making build errors visible directly in CI logs instead of only in binlog artifacts. --- .../AOTTemplateTest.cs | 8 ++-- .../AndroidTemplateTests.cs | 6 +-- .../AppleTemplateTests.cs | 6 +-- .../BlazorTemplateTest.cs | 6 +-- .../MacTemplateTest.cs | 12 +++--- .../MultiProjectTemplateTest.cs | 16 ++++---- .../ResizetizerTests.cs | 6 +-- .../SampleTests.cs | 2 +- .../SimpleTemplateTest.cs | 38 +++++++++---------- .../WindowsTemplateTest.cs | 24 ++++++------ 10 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs index a088b35a3766..d571dd125081 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs @@ -28,13 +28,13 @@ public void PublishNativeAOT(string id, string framework, string runtimeIdentifi var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); var extendedBuildProps = isWindowsFramework ? PrepareNativeAotBuildPropsWindows(runtimeIdentifier) : PrepareNativeAotBuildProps(); string binLogFilePath = $"publish-{DateTime.UtcNow.ToFileTimeUtc()}.binlog"; - Assert.True(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath), + Assert.True(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); var actualWarnings = BuildWarningsUtilities.ReadNativeAOTWarningsFromBinLog(binLogFilePath); @@ -64,7 +64,7 @@ public void PublishNativeAOTRootAllMauiAssemblies(string id, string framework, s var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); var extendedBuildProps = isWindowsFramework ? PrepareNativeAotBuildPropsWindows(runtimeIdentifier) : PrepareNativeAotBuildProps(); @@ -91,7 +91,7 @@ public void PublishNativeAOTRootAllMauiAssemblies(string id, string framework, s """); string binLogFilePath = $"publish-{DateTime.UtcNow.ToFileTimeUtc()}.binlog"; - Assert.True(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath), + Assert.True(DotnetInternal.Build(projectFile, "Release", framework: framework, properties: extendedBuildProps, runtimeIdentifier: runtimeIdentifier, binlogPath: binLogFilePath, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); var actualWarnings = BuildWarningsUtilities.ReadNativeAOTWarningsFromBinLog(binLogFilePath); diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs index 1faf0936e322..0a632cfb85bf 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs @@ -89,7 +89,7 @@ public void RunOnAndroid(string id, string framework, string config, string? tri var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); var buildProps = BuildProps; @@ -101,7 +101,7 @@ public void RunOnAndroid(string id, string framework, string config, string? tri AddInstrumentation(projectDir); - Assert.True(DotnetInternal.Build(projectFile, config, target: "Install", framework: $"{framework}-android", properties: BuildProps), + Assert.True(DotnetInternal.Build(projectFile, config, target: "Install", framework: $"{framework}-android", properties: BuildProps, output: _output), $"Project {Path.GetFileName(projectFile)} failed to install. Check test output/attachments for errors."); // Write xh-results to the log directory for artifact collection @@ -109,7 +109,7 @@ public void RunOnAndroid(string id, string framework, string config, string? tri Directory.CreateDirectory(xhResultsDir); testPackage = $"com.companyname.{Path.GetFileName(projectDir).ToLowerInvariant()}"; - Assert.True(XHarness.RunAndroid(testPackage, xhResultsDir, -1), + Assert.True(XHarness.RunAndroid(testPackage, xhResultsDir, -1, output: _output), $"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors."); } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AppleTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AppleTemplateTests.cs index ff0eb74ab63b..707c4f08cc8a 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AppleTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AppleTemplateTests.cs @@ -100,7 +100,7 @@ void RunOniOS(string id, string config, string framework, RuntimeVariant runtime var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); var buildProps = BuildProps; @@ -126,7 +126,7 @@ void RunOniOS(string id, string config, string framework, RuntimeVariant runtime buildProps.Add("TrimmerSingleWarn=false"); // Disable trimmer warnings for iOS full trimming builds due to ObjCRuntime issues } - Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: buildProps, runtimeIdentifier: runtimeIdentifier), + Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: buildProps, runtimeIdentifier: runtimeIdentifier, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); // Find the .app bundle - it may be in the bin folder with or without a RID subfolder depending on build settings @@ -142,7 +142,7 @@ void RunOniOS(string id, string config, string framework, RuntimeVariant runtime // Let XHarness find the simulator based on target (e.g., ios-simulator-64_18.5). // Don't pass a specific UDID - this gives XHarness full control over the simulator // lifecycle and avoids race conditions with watchdog disabling. - Assert.True(XHarness.RunAppleForTimeout(appFile, xhResultsDir, _simulatorFixture.TestSimulator.XHarnessID), + Assert.True(XHarness.RunAppleForTimeout(appFile, xhResultsDir, _simulatorFixture.TestSimulator.XHarnessID, output: _output), $"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors."); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/BlazorTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/BlazorTemplateTest.cs index 0907ac830573..4e5f5e60fa6e 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/BlazorTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/BlazorTemplateTest.cs @@ -68,7 +68,7 @@ public void BuildMauiBlazorWebSolution(string framework, string config, string a _output.WriteLine($"Creating project in {solutionProjectDir}"); - Assert.True(DotnetInternal.New(templateShortName, outputDirectory: solutionProjectDir, framework: framework, additionalDotNetNewParams: additionalDotNetNewParams), + Assert.True(DotnetInternal.New(templateShortName, outputDirectory: solutionProjectDir, framework: framework, additionalDotNetNewParams: additionalDotNetNewParams, output: _output), $"Unable to create template {templateShortName}. Check test output for errors."); _output.WriteLine($"Solution directory: {solutionProjectDir} (exists? {Directory.Exists(solutionProjectDir)})"); @@ -78,11 +78,11 @@ public void BuildMauiBlazorWebSolution(string framework, string config, string a _output.WriteLine($"MAUI app project file: {mauiAppProjectFile} (exists? {File.Exists(mauiAppProjectFile)})"); _output.WriteLine($"Building Blazor Web app: {webAppProjectFile}"); - Assert.True(DotnetInternal.Build(webAppProjectFile, config, target: "", properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(webAppProjectFile, config, target: "", properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(webAppProjectFile)} failed to build. Check test output/attachments for errors."); _output.WriteLine($"Building .NET MAUI app: {mauiAppProjectFile} props: {buildProps}"); - Assert.True(DotnetInternal.Build(mauiAppProjectFile, config, target: "", properties: buildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(mauiAppProjectFile, config, target: "", properties: buildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(mauiAppProjectFile)} failed to build. Check test output/attachments for errors."); } } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MacTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MacTemplateTest.cs index 33a0958c3980..dd5100b9d589 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MacTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MacTemplateTest.cs @@ -18,7 +18,7 @@ public void BuildWithCustomBundleResource(string id, string framework) var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); File.WriteAllText(Path.Combine(projectDir, "Resources", "testfile.txt"), "Something here :)"); @@ -35,7 +35,7 @@ public void BuildWithCustomBundleResource(string id, string framework) var extendedBuildProps = BuildProps; extendedBuildProps.Add($"TargetFramework={DotNetCurrent}-{framework}"); - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -65,8 +65,8 @@ private void CheckEntitlementsForMauiBlazorOnMacCatalyst(string id, string confi $"EnableCodeSigning={sign}" }; - Assert.True(DotnetInternal.New(id, projectDir, framework), $"Unable to create template {id}. Check test output for errors."); - Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-maccatalyst", properties: buildWithCodeSignProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); + Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-maccatalyst", properties: buildWithCodeSignProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); List expectedEntitlements = @@ -124,8 +124,8 @@ public void CheckPrivacyManifestForiOS(string id, string config, string framewor buildWithCodeSignProps.Add("EnableCodeSigning=true"); } - Assert.True(DotnetInternal.New(id, projectDir, framework), $"Unable to create template {id}. Check test output for errors."); - Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: buildWithCodeSignProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); + Assert.True(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: buildWithCodeSignProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); string manifestLocation = Path.Combine(appLocation, "PrivacyInfo.xcprivacy"); diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MultiProjectTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MultiProjectTemplateTest.cs index e41656f54ee6..42aeda29beec 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MultiProjectTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/MultiProjectTemplateTest.cs @@ -17,7 +17,7 @@ public void BuildMultiProject(string config, string projectName) var name = Path.GetFileName(projectDir); var solutionFile = Path.Combine(projectDir, $"{name}.sln"); - Assert.True(DotnetInternal.New("maui-multiproject", projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New("maui-multiproject", projectDir, DotNetCurrent, output: _output), $"Unable to create template maui-multiproject. Check test output for errors."); // Always remove WinUI project if the project name contains special characters that cause WinRT source generator issues @@ -26,7 +26,7 @@ public void BuildMultiProject(string config, string projectName) if (!TestEnvironment.IsWindows || containsSpecialChars) { - Assert.True(DotnetInternal.Run("sln", $"\"{solutionFile}\" remove \"{projectDir}/{name}.WinUI/{name}.WinUI.csproj\""), + Assert.True(DotnetInternal.Run("sln", $"\"{solutionFile}\" remove \"{projectDir}/{name}.WinUI/{name}.WinUI.csproj\"", output: _output), $"Unable to remove WinUI project from solution. Check test output for errors."); } @@ -34,7 +34,7 @@ public void BuildMultiProject(string config, string projectName) var buildProps = BuildProps; buildProps.Add("ResizetizerErrorOnDuplicateOutputFilename=false"); - Assert.True(DotnetInternal.Build(solutionFile, config, properties: buildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(solutionFile, config, properties: buildProps, msbuildWarningsAsErrors: true, output: _output), $"Solution {name} failed to build. Check test output/attachments for errors."); } @@ -50,16 +50,16 @@ public void BuildMultiProjectSinglePlatform(string config, string platformArg) var name = Path.GetFileName(projectDir); var solutionFile = Path.Combine(projectDir, $"{name}.sln"); - Assert.True(DotnetInternal.New($"maui-multiproject {platformArg}", projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New($"maui-multiproject {platformArg}", projectDir, DotNetCurrent, output: _output), $"Unable to create template maui-multiproject. Check test output for errors."); if (!TestEnvironment.IsWindows) { - Assert.True(DotnetInternal.Run("sln", $"{solutionFile} remove {projectDir}/{name}.WinUI/{name}.WinUI.csproj"), + Assert.True(DotnetInternal.Run("sln", $"{solutionFile} remove {projectDir}/{name}.WinUI/{name}.WinUI.csproj", output: _output), $"Unable to remove WinUI project from solution. Check test output for errors."); } - Assert.True(DotnetInternal.Build(solutionFile, config, properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(solutionFile, config, properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Solution {name} failed to build. Check test output/attachments for errors."); } @@ -77,10 +77,10 @@ public void VerifyIncludedPlatformsInSln(string platformArg) var name = Path.GetFileName(projectDir); var solutionFile = Path.Combine(projectDir, $"{name}.sln"); - Assert.True(DotnetInternal.New($"maui-multiproject {platformArg}", projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New($"maui-multiproject {platformArg}", projectDir, DotNetCurrent, output: _output), $"Unable to create template maui-multiproject. Check test output for errors."); - var slnListOutput = DotnetInternal.RunForOutput("sln", $"{solutionFile} list", out int exitCode); + var slnListOutput = DotnetInternal.RunForOutput("sln", $"{solutionFile} list", out int exitCode, output: _output); // Asserts the process completed successfully if (exitCode != 0) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs index 2323d8286074..fefbe048b1ed 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs @@ -34,13 +34,13 @@ public void CollectsAssets(string id, string libid, bool unpackaged) // new app var appDir = Path.Combine(TestDirectory, "theapp"); var appFile = Path.Combine(appDir, $"{Path.GetFileName(appDir)}.csproj"); - Assert.True(DotnetInternal.New(id, appDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, appDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); // new lib var libDir = Path.Combine(TestDirectory, "thelib"); var libFile = Path.Combine(libDir, $"{Path.GetFileName(libDir)}.csproj"); - Assert.True(DotnetInternal.New(libid, libDir, DotNetCurrent), + Assert.True(DotnetInternal.New(libid, libDir, DotNetCurrent, output: _output), $"Unable to create template {libid}. Check test output for errors."); // add a project reference @@ -85,7 +85,7 @@ public void CollectsAssets(string id, string libid, bool unpackaged) """); // build - Assert.True(DotnetInternal.Build(appFile, "Debug", properties: BuildProps), + Assert.True(DotnetInternal.Build(appFile, "Debug", properties: BuildProps, output: _output), $"Project {Path.GetFileName(appFile)} failed to build. Check test output/attachments for errors."); // assert diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SampleTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SampleTests.cs index 79c051a65af8..a1448d25800a 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SampleTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SampleTests.cs @@ -42,7 +42,7 @@ public void Build(string relativeProj, string config) "TrimmerSingleWarn=false", }; - Assert.True(DotnetInternal.Build(projectFile, config, properties: sampleProps, binlogPath: binlog), + Assert.True(DotnetInternal.Build(projectFile, config, properties: sampleProps, binlogPath: binlog, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SimpleTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SimpleTemplateTest.cs index b726b0a887dd..a79ca922cb88 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SimpleTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/SimpleTemplateTest.cs @@ -34,7 +34,7 @@ public void Build(string id, string framework, string config, bool shouldPack, s var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework, additionalDotNetNewParams), + Assert.True(DotnetInternal.New(id, projectDir, framework, additionalDotNetNewParams, output: _output), $"Unable to create template {id}. Check test output for errors."); @@ -57,7 +57,7 @@ public void Build(string id, string framework, string config, bool shouldPack, s } string target = shouldPack ? "Pack" : ""; - Assert.True(DotnetInternal.Build(projectFile, config, target: target, properties: buildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, config, target: target, properties: buildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -68,14 +68,14 @@ public void InstallPackagesIntoUnsupportedTfmFails(string id, string framework, var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); FileUtilities.ReplaceInFile(projectFile, "$(MauiVersion)", MauiPackageVersion); - Assert.False(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.False(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} built, but should not have. Check test output/attachments for why."); } @@ -92,7 +92,7 @@ public void BuildsWithSpecialCharacters(string id, string projectName, string ex var projectDir = Path.Combine(TestDirectory, projectName); var projectFile = Path.Combine(projectDir, $"{projectName}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); // libraries do not have application IDs @@ -117,7 +117,7 @@ public void BuildsWithSpecialCharacters(string id, string projectName, string ex Assert.Equal(projectName, appTitle); } - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -140,7 +140,7 @@ public void BuildWithMauiVersion(string id, string framework, string config, boo var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); if (shouldPack) @@ -167,7 +167,7 @@ public void BuildWithMauiVersion(string id, string framework, string config, boo } string target = shouldPack ? "Pack" : ""; - Assert.True(DotnetInternal.Build(projectFile, config, target: target, binlogPath: binlogDir, properties: buildProps), + Assert.True(DotnetInternal.Build(projectFile, config, target: target, binlogPath: binlogDir, properties: buildProps, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -184,7 +184,7 @@ public void PreviousDotNetCanUseLatestMaui(string id, string config, bool should var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetPrevious), + Assert.True(DotnetInternal.New(id, projectDir, DotNetPrevious, output: _output), $"Unable to create template {id}. Check test output for errors."); if (shouldPack) @@ -204,7 +204,7 @@ public void PreviousDotNetCanUseLatestMaui(string id, string config, bool should """); string target = shouldPack ? "Pack" : ""; - Assert.True(DotnetInternal.Build(projectFile, config, target: target, properties: BuildProps), + Assert.True(DotnetInternal.Build(projectFile, config, target: target, properties: BuildProps, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } #endif @@ -215,12 +215,12 @@ public void BuildHandlesBadFilesInImages() var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New("maui", projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New("maui", projectDir, DotNetCurrent, output: _output), $"Unable to create template maui. Check test output for errors."); File.WriteAllText(Path.Combine(projectDir, "Resources", "Images", ".DS_Store"), "Boom!"); - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -237,7 +237,7 @@ public void PackCoreLib(string id, string framework, string config) var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); var projectSectionsToReplace = new Dictionary() @@ -255,7 +255,7 @@ public void PackCoreLib(string id, string framework, string config) FileUtilities.ReplaceInFile(projectFile, projectSectionsToReplace); Directory.Delete(Path.Combine(projectDir, "Platforms"), recursive: true); - Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -268,7 +268,7 @@ public void BuildWithoutPackageReference(string id, string framework, string con var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); FileUtilities.ReplaceInFile(projectFile, @@ -278,7 +278,7 @@ public void BuildWithoutPackageReference(string id, string framework, string con "", ""); - Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -294,7 +294,7 @@ public void BuildWithDifferentVersionNumber(string id, string config, string dis var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir), + Assert.True(DotnetInternal.New(id, projectDir, output: _output), $"Unable to create template {id}. Check test output for errors."); FileUtilities.ReplaceInFile(projectFile, @@ -311,7 +311,7 @@ public void BuildWithDifferentVersionNumber(string id, string config, string dis additionalDotNetBuildParams.Split(" ").ToList().ForEach(p => buildProps.Add(p)); } - Assert.True(DotnetInternal.Build(projectFile, config, properties: buildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, config, properties: buildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -324,7 +324,7 @@ public void AspireServiceDefaultsTemplateUsesCorrectProjectName(string projectNa var projectDir = Path.Combine(TestDirectory, projectName); var expectedProjectFile = Path.Combine(projectDir, $"{projectName}.csproj"); - Assert.True(DotnetInternal.New("maui-aspire-servicedefaults", projectDir, additionalDotNetNewParams: $"-n \"{projectName}\""), + Assert.True(DotnetInternal.New("maui-aspire-servicedefaults", projectDir, additionalDotNetNewParams: $"-n \"{projectName}\"", output: _output), $"Unable to create template maui-aspire-servicedefaults. Check test output for errors."); // Verify the project file was created with the correct name (this was the bug) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/WindowsTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/WindowsTemplateTest.cs index d20e753830c6..ea4c55cce73e 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/WindowsTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/WindowsTemplateTest.cs @@ -20,7 +20,7 @@ public void BuildPackaged(string id, string framework, string config) var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); // .NET 9 and later was Unpackaged, so we need to remove the line @@ -28,7 +28,7 @@ public void BuildPackaged(string id, string framework, string config) "None", ""); - Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, config, properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -52,7 +52,7 @@ public void BuildWindowsAppSDKSelfContained(string id, bool wasdkself, bool nets var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); FileUtilities.ReplaceInFile(projectFile, @@ -66,7 +66,7 @@ public void BuildWindowsAppSDKSelfContained(string id, bool wasdkself, bool nets var extendedBuildProps = BuildProps; extendedBuildProps.Add($"TargetFramework={DotNetCurrent}-windows10.0.19041.0"); - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -86,7 +86,7 @@ public void BuildWindowsRidGraph(string id, bool useRidGraph, string packageType var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New(id, projectDir, DotNetCurrent, output: _output), $"Unable to create template {id}. Check test output for errors."); FileUtilities.ReplaceInFile(projectFile, @@ -99,7 +99,7 @@ public void BuildWindowsRidGraph(string id, bool useRidGraph, string packageType var extendedBuildProps = BuildProps; extendedBuildProps.Add($"TargetFramework={DotNetCurrent}-windows10.0.19041.0"); - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: extendedBuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } @@ -119,14 +119,14 @@ public void PublishUnpackaged(string id, string framework, string config, bool u var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); // .NET 9 is Unpackaged by default, so we don't have to do anything FileUtilities.ShouldContainInFile(projectFile, "None"); - Assert.True(DotnetInternal.Publish(projectFile, config, framework: $"{framework}-windows10.0.19041.0", properties: BuildProps), + Assert.True(DotnetInternal.Publish(projectFile, config, framework: $"{framework}-windows10.0.19041.0", properties: BuildProps, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); var rid = usesRidGraph ? "win10-x64" : "win-x64"; @@ -163,7 +163,7 @@ public void PublishPackaged(string id, string framework, string config, bool use var name = Path.GetFileName(projectDir); var projectFile = Path.Combine(projectDir, $"{name}.csproj"); - Assert.True(DotnetInternal.New(id, projectDir, framework), + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); // .NET 9 and later was Unpackaged, so we need to remove the line @@ -171,7 +171,7 @@ public void PublishPackaged(string id, string framework, string config, bool use "None", ""); - Assert.True(DotnetInternal.Publish(projectFile, config, framework: $"{framework}-windows10.0.19041.0", properties: BuildProps), + Assert.True(DotnetInternal.Publish(projectFile, config, framework: $"{framework}-windows10.0.19041.0", properties: BuildProps, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); var rid = usesRidGraph ? "win10-x64/" : ""; @@ -196,7 +196,7 @@ public void BuildWithIdentityClient() var projectDir = TestDirectory; var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); - Assert.True(DotnetInternal.New("maui", projectDir, DotNetCurrent), + Assert.True(DotnetInternal.New("maui", projectDir, DotNetCurrent, output: _output), $"Unable to create template maui. Check test output for errors."); // .NET 9 and later was Unpackaged, so we need to remove the line @@ -210,7 +210,7 @@ public void BuildWithIdentityClient() """); - Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true), + Assert.True(DotnetInternal.Build(projectFile, "Debug", properties: BuildProps, msbuildWarningsAsErrors: true, output: _output), $"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors."); } }