From 0370c04103337d28f8a71aed3092303302453470 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:54:04 +0000 Subject: [PATCH 1/3] Revert "Revert $(LatestDotNetCoreForMSBuild) related changes for separate PR" This reverts commit 1915beed9872474cc81fb08c49a0e7fbd260f87d. --- src/Build.UnitTests/NetTaskHost_E2E_Tests.cs | 66 +++++++++++++++++-- .../TaskHostFactoryLifecycle_E2E_Tests.cs | 2 +- src/Build.UnitTests/TerminalLogger_Tests.cs | 2 +- .../ExampleTask/ExampleTask.csproj | 2 +- .../TestMSBuildTaskInNet.csproj | 2 +- .../TestNetTask/TestNetTask.csproj | 2 +- .../TestNetTaskWithImplicitParams.csproj | 2 +- .../TaskHostLifecycleTestApp.csproj | 2 +- src/BuildCheck.UnitTests/EndToEndTests.cs | 4 +- .../EntryProject/EntryProject.csproj | 2 +- .../ReferencedProject.csproj | 2 +- .../EntryProject/EntryProject.csproj | 2 +- src/Tasks.UnitTests/Copy_Tests.cs | 4 +- .../BootstrapLocationAttribute.cs | 7 +- .../Microsoft.Build.UnitTests.Shared.csproj | 1 + src/UnitTests.Shared/RunnerUtilities.cs | 2 + 16 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs b/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs index 22f01c69e9b..e02030e12c0 100644 --- a/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs +++ b/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs @@ -36,7 +36,7 @@ public void NetTaskHostTest() string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -47,7 +47,7 @@ public void NetTaskHostTest() testTaskOutput.ShouldContain($"The task is executed in process: dotnet"); testTaskOutput.ShouldContain($"Process path: {dotnetPath}", customMessage: testTaskOutput); - var customTaskAssemblyLocation = Path.GetFullPath(Path.Combine(AssemblyLocation, "..", LatestDotNetCoreForMSBuild, "ExampleTask.dll")); + var customTaskAssemblyLocation = Path.GetFullPath(Path.Combine(AssemblyLocation, "..", RunnerUtilities.LatestDotNetCoreForMSBuild, "ExampleTask.dll")); var resource = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword( "TaskAssemblyLocationMismatch", @@ -57,13 +57,53 @@ public void NetTaskHostTest() testTaskOutput.ShouldNotContain(resource); } + [WindowsFullFrameworkOnlyFact] // Verifies that when MSBuild.exe app host is available in the SDK, it is used instead of dotnet.exe + MSBuild.dll. + public void NetTaskHostTest_AppHostUsedWhenAvailable() + { + using TestEnvironment env = TestEnvironment.Create(_output, setupDotnetEnvVars: true); + string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); + + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); + + successTestTask.ShouldBeTrue(); + + // When app host is used, the process name should be "MSBuild" not "dotnet" + testTaskOutput.ShouldContain("The task is executed in process: MSBuild"); + + // The process path should point to MSBuild.exe, not dotnet.exe + testTaskOutput.ShouldContain("MSBuild.exe", customMessage: "Expected MSBuild.exe app host to be used"); + testTaskOutput.ShouldNotContain("Process path: " + Path.Combine(env.GetEnvironmentVariable("DOTNET_ROOT") ?? "", "dotnet.exe")); + } + + [WindowsFullFrameworkOnlyFact] // Verifies that when using the app host, DOTNET_ROOT is properly set for child processes to find the runtime. + public void NetTaskHostTest_AppHostSetsDotnetRoot() + { + using TestEnvironment env = TestEnvironment.Create(_output); + + // Clear DOTNET_ROOT to ensure app host sets it + env.SetEnvironmentVariable("DOTNET_ROOT", null); + env.SetEnvironmentVariable("DOTNET_ROOT_X64", null); + env.SetEnvironmentVariable("DOTNET_ROOT_X86", null); + env.SetEnvironmentVariable("DOTNET_ROOT_ARM64", null); + + string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); + + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); + + _output.WriteLine(testTaskOutput); + + // The build should succeed - this proves DOTNET_ROOT was properly set for the task host + // to find the runtime, even though we cleared it from the parent environment + successTestTask.ShouldBeTrue(customMessage: "Build should succeed with app host setting DOTNET_ROOT"); + } + [WindowsFullFrameworkOnlyFact] public void NetTaskHost_CorrectPathsEscapingTest() { using TestEnvironment env = TestEnvironment.Create(_output); var dotnetPath = env.GetEnvironmentVariable("DOTNET_ROOT"); string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -124,7 +164,7 @@ public void MSBuildTaskInNetHostTest() string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestMSBuildTaskInNet", "TestMSBuildTaskInNet.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -143,7 +183,7 @@ public void NetTaskWithImplicitHostParamsTest() string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTaskWithImplicitParams", "TestNetTaskWithImplicitParams.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -163,5 +203,21 @@ public void NetTaskWithImplicitHostParamsTest() // Output from the task where neither TaskHost nor Runtime were specified testTaskOutput.ShouldContain("Found item: Banana"); } + + [WindowsFullFrameworkOnlyFact] // This test verifies app host behavior with implicit host parameters. + public void NetTaskWithImplicitHostParamsTest_AppHost() + { + using TestEnvironment env = TestEnvironment.Create(_output, setupDotnetEnvVars: true); + string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTaskWithImplicitParams", "TestNetTaskWithImplicitParams.csproj"); + + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); + + _output.WriteLine(testTaskOutput); + + successTestTask.ShouldBeTrue(); + + testTaskOutput.ShouldContain("The task is executed in process: MSBuild"); + testTaskOutput.ShouldContain("/nodereuse:True"); + } } } diff --git a/src/Build.UnitTests/TaskHostFactoryLifecycle_E2E_Tests.cs b/src/Build.UnitTests/TaskHostFactoryLifecycle_E2E_Tests.cs index b82ca9693ba..464ca7672da 100644 --- a/src/Build.UnitTests/TaskHostFactoryLifecycle_E2E_Tests.cs +++ b/src/Build.UnitTests/TaskHostFactoryLifecycle_E2E_Tests.cs @@ -95,7 +95,7 @@ private string ExecuteBuildWithTaskHost(string runtimeToUse, string taskFactoryT string testProjectPath = Path.Combine(TestAssetsRootPath, "TaskHostLifecycleTestApp.csproj"); string output = RunnerUtilities.ExecBootstrapedMSBuild( - $"{testProjectPath} -v:n -restore /p:RuntimeToUse={runtimeToUse} /p:TaskFactoryToUse={taskFactoryToUse}", + $"{testProjectPath} -v:n -restore /p:RuntimeToUse={runtimeToUse} /p:TaskFactoryToUse={taskFactoryToUse} /p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool success, outputHelper: _output); diff --git a/src/Build.UnitTests/TerminalLogger_Tests.cs b/src/Build.UnitTests/TerminalLogger_Tests.cs index 59d55089d7b..6b078789892 100644 --- a/src/Build.UnitTests/TerminalLogger_Tests.cs +++ b/src/Build.UnitTests/TerminalLogger_Tests.cs @@ -1011,7 +1011,7 @@ public async Task ProjectFinishedReportsTargetFrameworkAndRuntimeIdentifier() { // this project will report a TFM and a RID and so will show a both in the output var buildOutputEvent = MakeBuildOutputEventArgs(_projectFile); - InvokeLoggerCallbacksForSimpleProject(succeeded: true, properties: [("TargetFramework", "net10.0"), ("RuntimeIdentifier", "win-x64")], additionalCallbacks: () => + InvokeLoggerCallbacksForSimpleProject(succeeded: true, properties: [("TargetFramework", RunnerUtilities.LatestDotNetCoreForMSBuild), ("RuntimeIdentifier", "win-x64")], additionalCallbacks: () => { _centralNodeEventSource.InvokeMessageRaised(buildOutputEvent); }); diff --git a/src/Build.UnitTests/TestAssets/ExampleNetTask/ExampleTask/ExampleTask.csproj b/src/Build.UnitTests/TestAssets/ExampleNetTask/ExampleTask/ExampleTask.csproj index 36add8bbb2b..7a5976334e9 100644 --- a/src/Build.UnitTests/TestAssets/ExampleNetTask/ExampleTask/ExampleTask.csproj +++ b/src/Build.UnitTests/TestAssets/ExampleNetTask/ExampleTask/ExampleTask.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) diff --git a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestMSBuildTaskInNet/TestMSBuildTaskInNet.csproj b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestMSBuildTaskInNet/TestMSBuildTaskInNet.csproj index d40cbcf9d52..094d5e93791 100644 --- a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestMSBuildTaskInNet/TestMSBuildTaskInNet.csproj +++ b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestMSBuildTaskInNet/TestMSBuildTaskInNet.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) enable enable diff --git a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTask/TestNetTask.csproj b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTask/TestNetTask.csproj index 0ed5a43fb8d..2f63d513a2e 100644 --- a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTask/TestNetTask.csproj +++ b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTask/TestNetTask.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) diff --git a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskWithImplicitParams/TestNetTaskWithImplicitParams.csproj b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskWithImplicitParams/TestNetTaskWithImplicitParams.csproj index 7419e72c777..75ec454fc07 100644 --- a/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskWithImplicitParams/TestNetTaskWithImplicitParams.csproj +++ b/src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskWithImplicitParams/TestNetTaskWithImplicitParams.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) diff --git a/src/Build.UnitTests/TestAssets/TaskHostLifecycle/TaskHostLifecycleTestApp.csproj b/src/Build.UnitTests/TestAssets/TaskHostLifecycle/TaskHostLifecycleTestApp.csproj index adb43e0de99..76f52173659 100644 --- a/src/Build.UnitTests/TestAssets/TaskHostLifecycle/TaskHostLifecycleTestApp.csproj +++ b/src/Build.UnitTests/TestAssets/TaskHostLifecycle/TaskHostLifecycleTestApp.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) $([System.IO.Path]::GetFullPath('$([System.IO.Path]::Combine('$(AssemblyLocation)', '..'))')) $([System.IO.Path]::Combine('$(TestProjectFolder)', '$(TargetFramework)', 'ExampleTask.dll')) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index d251e8f5ecc..97c212e8585 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -171,7 +171,7 @@ private EmbedResourceTestOutput RunEmbeddedResourceTest(string resourceXmlToAdd, _env.SetCurrentDirectory(Path.Combine(workFolder.Path, entryProjectName)); - string output = RunnerUtilities.ExecBootstrapedMSBuild("-check -restore /p:WarnOnCultureOverwritten=True /p:RespectCulture=" + (respectCulture ? "True" : "\"\""), out bool success, timeoutMilliseconds: timeoutInMilliseconds); + string output = RunnerUtilities.ExecBootstrapedMSBuild($"-check -restore /p:WarnOnCultureOverwritten=True /p:RespectCulture={(respectCulture ? "True" : "\"\"")} /p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool success, timeoutMilliseconds: timeoutInMilliseconds); _env.Output.WriteLine(output); _env.Output.WriteLine("========================="); success.ShouldBeTrue(); @@ -232,7 +232,7 @@ private readonly record struct CopyTestOutput( private CopyTestOutput RunCopyToOutputTest(bool restore, bool skipUnchangedDuringCopy) { - string output = RunnerUtilities.ExecBootstrapedMSBuild($"-check {(restore ? "-restore" : null)} /p:SkipUnchanged={(skipUnchangedDuringCopy ? "True" : "\"\"")}", out bool success, timeoutMilliseconds: timeoutInMilliseconds); + string output = RunnerUtilities.ExecBootstrapedMSBuild($"-check {(restore ? "-restore" : null)} /p:SkipUnchanged={(skipUnchangedDuringCopy ? "True" : "\"\"")} /p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool success, timeoutMilliseconds: timeoutInMilliseconds); _env.Output.WriteLine(output); _env.Output.WriteLine("========================="); success.ShouldBeTrue(); diff --git a/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/EntryProject/EntryProject.csproj b/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/EntryProject/EntryProject.csproj index f5ae000b48e..169b2f4d2bb 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/EntryProject/EntryProject.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/EntryProject/EntryProject.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) enable enable diff --git a/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/ReferencedProject/ReferencedProject.csproj b/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/ReferencedProject/ReferencedProject.csproj index 9709c2acc31..aa00a8f26a6 100644 --- a/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/ReferencedProject/ReferencedProject.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/CopyAlwaysTest/ReferencedProject/ReferencedProject.csproj @@ -1,7 +1,7 @@ - net10.0 + $(LatestDotNetCoreForMSBuild) enable enable diff --git a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj index 16852d41a1b..2742526793e 100644 --- a/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj +++ b/src/BuildCheck.UnitTests/TestAssets/EmbeddedResourceTest/EntryProject/EntryProject.csproj @@ -1,7 +1,7 @@  - net10.0 + $(LatestDotNetCoreForMSBuild) enable enable true diff --git a/src/Tasks.UnitTests/Copy_Tests.cs b/src/Tasks.UnitTests/Copy_Tests.cs index 9b3bf954125..cac38f4e105 100644 --- a/src/Tasks.UnitTests/Copy_Tests.cs +++ b/src/Tasks.UnitTests/Copy_Tests.cs @@ -3174,7 +3174,7 @@ public void CopyToFileWithSameCaseInsensitiveNameAsExistingDirectoryOnUnix() Directory.CreateDirectory(tempDir); // Create a subdirectory structure to match the real scenario - string outputDir = Path.Combine(tempDir, "bin", "Debug", "net10.0"); + string outputDir = Path.Combine(tempDir, "bin", "Debug", RunnerUtilities.LatestDotNetCoreForMSBuild); Directory.CreateDirectory(outputDir); // Create a directory named "cs" (lowercase) in the output directory @@ -3182,7 +3182,7 @@ public void CopyToFileWithSameCaseInsensitiveNameAsExistingDirectoryOnUnix() Directory.CreateDirectory(lowercaseDir); // Create a few source files to copy (representing multiple files being copied to same dest dir) - string sourceDir = Path.Combine(tempDir, "CS", "obj", "Debug", "net10.0"); + string sourceDir = Path.Combine(tempDir, "CS", "obj", "Debug", RunnerUtilities.LatestDotNetCoreForMSBuild); Directory.CreateDirectory(sourceDir); string sourceFile1 = Path.Combine(sourceDir, "apphost"); diff --git a/src/UnitTests.Shared/BootstrapLocationAttribute.cs b/src/UnitTests.Shared/BootstrapLocationAttribute.cs index 3854f1ecf13..bc0d0211dfb 100644 --- a/src/UnitTests.Shared/BootstrapLocationAttribute.cs +++ b/src/UnitTests.Shared/BootstrapLocationAttribute.cs @@ -6,7 +6,7 @@ namespace Microsoft.Build.UnitTests.Shared; [System.AttributeUsage(System.AttributeTargets.Assembly)] -internal sealed class BootstrapLocationAttribute(string bootstrapRoot, string bootstrapMsBuildBinaryLocation, string bootstrapSdkVersion) : System.Attribute +internal sealed class BootstrapLocationAttribute(string bootstrapRoot, string bootstrapMsBuildBinaryLocation, string bootstrapSdkVersion, string latestDotNetCoreForMSBuild) : System.Attribute { /// /// Path to the root of the bootstrap MSBuild (in artifacts folder). @@ -22,4 +22,9 @@ internal sealed class BootstrapLocationAttribute(string bootstrapRoot, string bo /// Returns the version of the SDK used by the bootstrap MSBuild. /// public string BootstrapSdkVersion { get; } = bootstrapSdkVersion; + + /// + /// The latest .NET target framework setup in MSBuild. + /// + public string LatestDotNetCoreForMSBuild { get; } = latestDotNetCoreForMSBuild; } diff --git a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj index e3538055dba..73c968b3d22 100644 --- a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj +++ b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj @@ -44,6 +44,7 @@ <_Parameter1>$(ArtifactsBinDir)bootstrap <_Parameter2>$(TestBootstrapBinaryDestination) <_Parameter3>$(BootstrapSdkVersion) + <_Parameter4>$(LatestDotNetCoreForMSBuild) diff --git a/src/UnitTests.Shared/RunnerUtilities.cs b/src/UnitTests.Shared/RunnerUtilities.cs index 7cb15936a11..e3e43b8be32 100644 --- a/src/UnitTests.Shared/RunnerUtilities.cs +++ b/src/UnitTests.Shared/RunnerUtilities.cs @@ -27,6 +27,8 @@ public static class RunnerUtilities public static string BootstrapRootPath => BootstrapLocationAttribute.BootstrapRoot; + public static string LatestDotNetCoreForMSBuild => BootstrapLocationAttribute.LatestDotNetCoreForMSBuild; + internal static BootstrapLocationAttribute BootstrapLocationAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute() ?? throw new InvalidOperationException("This test assembly does not have the BootstrapLocationAttribute"); From 31a2104ff7f94772ff0e4e15804d5bf6783c18da Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 3 Feb 2026 17:35:11 +0100 Subject: [PATCH 2/3] remove extra changes --- src/Build.UnitTests/NetTaskHost_E2E_Tests.cs | 64 +--------- src/BuildCheck.UnitTests/EndToEndTests.cs | 127 ++++++++++--------- 2 files changed, 73 insertions(+), 118 deletions(-) diff --git a/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs b/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs index e02030e12c0..a0b35a6ed39 100644 --- a/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs +++ b/src/Build.UnitTests/NetTaskHost_E2E_Tests.cs @@ -47,7 +47,7 @@ public void NetTaskHostTest() testTaskOutput.ShouldContain($"The task is executed in process: dotnet"); testTaskOutput.ShouldContain($"Process path: {dotnetPath}", customMessage: testTaskOutput); - var customTaskAssemblyLocation = Path.GetFullPath(Path.Combine(AssemblyLocation, "..", RunnerUtilities.LatestDotNetCoreForMSBuild, "ExampleTask.dll")); + var customTaskAssemblyLocation = Path.GetFullPath(Path.Combine(AssemblyLocation, "..", LatestDotNetCoreForMSBuild, "ExampleTask.dll")); var resource = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword( "TaskAssemblyLocationMismatch", @@ -57,46 +57,6 @@ public void NetTaskHostTest() testTaskOutput.ShouldNotContain(resource); } - [WindowsFullFrameworkOnlyFact] // Verifies that when MSBuild.exe app host is available in the SDK, it is used instead of dotnet.exe + MSBuild.dll. - public void NetTaskHostTest_AppHostUsedWhenAvailable() - { - using TestEnvironment env = TestEnvironment.Create(_output, setupDotnetEnvVars: true); - string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); - - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); - - successTestTask.ShouldBeTrue(); - - // When app host is used, the process name should be "MSBuild" not "dotnet" - testTaskOutput.ShouldContain("The task is executed in process: MSBuild"); - - // The process path should point to MSBuild.exe, not dotnet.exe - testTaskOutput.ShouldContain("MSBuild.exe", customMessage: "Expected MSBuild.exe app host to be used"); - testTaskOutput.ShouldNotContain("Process path: " + Path.Combine(env.GetEnvironmentVariable("DOTNET_ROOT") ?? "", "dotnet.exe")); - } - - [WindowsFullFrameworkOnlyFact] // Verifies that when using the app host, DOTNET_ROOT is properly set for child processes to find the runtime. - public void NetTaskHostTest_AppHostSetsDotnetRoot() - { - using TestEnvironment env = TestEnvironment.Create(_output); - - // Clear DOTNET_ROOT to ensure app host sets it - env.SetEnvironmentVariable("DOTNET_ROOT", null); - env.SetEnvironmentVariable("DOTNET_ROOT_X64", null); - env.SetEnvironmentVariable("DOTNET_ROOT_X86", null); - env.SetEnvironmentVariable("DOTNET_ROOT_ARM64", null); - - string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTask", "TestNetTask.csproj"); - - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); - - _output.WriteLine(testTaskOutput); - - // The build should succeed - this proves DOTNET_ROOT was properly set for the task host - // to find the runtime, even though we cleared it from the parent environment - successTestTask.ShouldBeTrue(customMessage: "Build should succeed with app host setting DOTNET_ROOT"); - } - [WindowsFullFrameworkOnlyFact] public void NetTaskHost_CorrectPathsEscapingTest() { @@ -164,7 +124,7 @@ public void MSBuildTaskInNetHostTest() string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestMSBuildTaskInNet", "TestMSBuildTaskInNet.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -183,7 +143,7 @@ public void NetTaskWithImplicitHostParamsTest() string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTaskWithImplicitParams", "TestNetTaskWithImplicitParams.csproj"); - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); + string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); if (!successTestTask) { @@ -203,21 +163,5 @@ public void NetTaskWithImplicitHostParamsTest() // Output from the task where neither TaskHost nor Runtime were specified testTaskOutput.ShouldContain("Found item: Banana"); } - - [WindowsFullFrameworkOnlyFact] // This test verifies app host behavior with implicit host parameters. - public void NetTaskWithImplicitHostParamsTest_AppHost() - { - using TestEnvironment env = TestEnvironment.Create(_output, setupDotnetEnvVars: true); - string testProjectPath = Path.Combine(TestAssetsRootPath, "ExampleNetTask", "TestNetTaskWithImplicitParams", "TestNetTaskWithImplicitParams.csproj"); - - string testTaskOutput = RunnerUtilities.ExecBootstrapedMSBuild($"{testProjectPath} -restore -v:n -p:LatestDotNetCoreForMSBuild={RunnerUtilities.LatestDotNetCoreForMSBuild}", out bool successTestTask); - - _output.WriteLine(testTaskOutput); - - successTestTask.ShouldBeTrue(); - - testTaskOutput.ShouldContain("The task is executed in process: MSBuild"); - testTaskOutput.ShouldContain("/nodereuse:True"); - } } -} +} \ No newline at end of file diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 97c212e8585..82472057d0f 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -21,7 +21,6 @@ namespace Microsoft.Build.BuildCheck.UnitTests; public class EndToEndTests : IDisposable { private const string EditorConfigFileName = ".editorconfig"; - private const string LatestDotNetCoreForMSBuild = "net10.0"; private readonly TestEnvironment _env; @@ -361,19 +360,26 @@ public void WarningsCountExceedsLimitTest(bool buildInOutOfProcessNode, bool lim } } + private const string testAssetsFolder = "TFMConfusionCheck"; + + public static IEnumerable TFMConfusionCheckTestData() + { + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild}""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild};net472""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild};net472""", $" /p:TargetFramework={RunnerUtilities.LatestDotNetCoreForMSBuild}", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild};net472""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild};net472""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild}""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild}""", "", false]; + yield return [$"""{RunnerUtilities.LatestDotNetCoreForMSBuild}{RunnerUtilities.LatestDotNetCoreForMSBuild};net472""", "", true]; + } + [Theory] - [InlineData($"""{LatestDotNetCoreForMSBuild}""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild};net472""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild};net472""", $" /p:TargetFramework={LatestDotNetCoreForMSBuild}", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild};net472""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild};net472""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild}""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild}""", "", false)] - [InlineData($"""{LatestDotNetCoreForMSBuild}{LatestDotNetCoreForMSBuild};net472""", "", true)] + [MemberData(nameof(TFMConfusionCheckTestData))] public void TFMConfusionCheckTest(string tfmString, string cliSuffix, bool shouldTriggerCheck) { const string testAssetsFolderName = "TFMConfusionCheck"; - const string projectName = testAssetsFolderName; + const string projectName = testAssetsFolder; const string templateToReplace = "###TFM"; TransientTestFolder workFolder = _env.CreateFolder(createFolder: true); @@ -407,56 +413,61 @@ void ReplaceStringInFile(string filePath, string original, string replacement) } } + public static IEnumerable TFMinNonSdkCheckTestData() + { + yield return [ + """ + + + net48 + + + + + + """, + false]; + yield return [ + $""" + + + {RunnerUtilities.LatestDotNetCoreForMSBuild} + + + """, + false]; + yield return [ + """ + + + Library + v4.8 + bin\Debug\ + CS2008 + + + + """, + false]; + yield return [ + """ + + + Library + v4.8 + v4.8 + bin\Debug\ + CS2008 + + + + """, + true]; + } + // Windows only - due to targeting NetFx [WindowsOnlyTheory] - [InlineData( - """ - - - net48 - - - - - - """, - false)] - [InlineData( - $""" - - - {LatestDotNetCoreForMSBuild} - - - """, - false)] - [InlineData( - """ - - - Library - v4.8 - bin\Debug\ - CS2008 - - - - """, - false)] - [InlineData( - """ - - - Library - v4.8 - v4.8 - bin\Debug\ - CS2008 - - - - """, - true)] + [MemberData(nameof(TFMinNonSdkCheckTestData))] public void TFMinNonSdkCheckTest(string projectContent, bool expectCheckTrigger) { TransientTestFolder workFolder = _env.CreateFolder(createFolder: true); From 294fedec5fd0e21246e77ab9a2eeebb7433085aa Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 3 Feb 2026 17:44:16 +0100 Subject: [PATCH 3/3] fix usings --- src/Tasks.UnitTests/Copy_Tests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tasks.UnitTests/Copy_Tests.cs b/src/Tasks.UnitTests/Copy_Tests.cs index cac38f4e105..63062fcf3a5 100644 --- a/src/Tasks.UnitTests/Copy_Tests.cs +++ b/src/Tasks.UnitTests/Copy_Tests.cs @@ -21,6 +21,7 @@ using Xunit; using Xunit.Abstractions; +using Microsoft.Build.UnitTests.Shared; #nullable disable