File: GivenThatWeWantToPublishAnAotApp.cs
Web Access
Project: ..\..\..\test\Microsoft.NET.Publish.Tests\Microsoft.NET.Publish.Tests.csproj (Microsoft.NET.Publish.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using System.Reflection.PortableExecutable;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.NET.Build.Tasks;
using Newtonsoft.Json.Linq;
using static Microsoft.NET.Publish.Tests.PublishTestUtils;
 
namespace Microsoft.NET.Publish.Tests
{
    public class GivenThatWeWantToPublishAnAotApp : SdkTest
    {
        private readonly string RuntimeIdentifier = $"/p:RuntimeIdentifier={RuntimeInformation.RuntimeIdentifier}";
 
        private const string NetCurrentExplicitPackageVersion = "10.0.0-preview.6.25316.103";
 
        public GivenThatWeWantToPublishAnAotApp(ITestOutputHelper log) : base(log)
        {
        }
 
        [RequiresMSBuildVersionTheory("17.12.0", Skip = "https://github.com/dotnet/sdk/issues/46006")]
        [MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))]
        public void NativeAot_hw_runs_with_no_warnings_when_PublishAot_is_enabled(string targetFramework)
        {
            if (targetFramework == "net7.0" && RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // 7.0 is not supported on Mac
                return;
            }
 
            var projectName = "HellowWorldNativeAotApp";
 
            var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            // Linux symbol files are embedded and require additional steps to be stripped to a separate file
            // assumes /bin (or /usr/bin) are in the PATH
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                testProject.AdditionalProperties["StripSymbols"] = "true";
            }
            var testAsset = _testAssetsManager.CreateTestProject(testProject);
 
            var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true", "/p:CheckEolTargetFramework=false")
                .Should().Pass()
                .And.NotHaveStdOutContaining("IL2026")
                .And.NotHaveStdErrContaining("NETSDK1179")
                .And.NotHaveStdErrContaining("warning")
                .And.NotHaveStdOutContaining("warning");
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
            var sharedLibSuffix = GetSharedLibSuffix();
            var publishedDll = Path.Combine(publishDirectory, $"{projectName}{sharedLibSuffix}");
            var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
 
            // NativeAOT published dir should not contain a non-host stand alone package
            File.Exists(publishedDll).Should().BeFalse();
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            DoSymbolsExist(publishDirectory, testProject.Name).Should().BeTrue($"{publishDirectory} should contain {testProject.Name} symbol");
            IsNativeImage(publishedExe).Should().BeTrue();
 
            bool useRuntimePackLayout = targetFramework is not ("net7.0" or "net8.0" or "net9.0");
 
            GetKnownILCompilerPackVersion(testAsset, targetFramework, out string expectedVersion);
            CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion, useRuntimePackLayout);
 
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass()
                .And.HaveStdOutContaining("Hello World");
        }
 
        [RequiresMSBuildVersionTheory("17.12.0")]
        [MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))]
        public void NativeAot_hw_runs_with_no_warnings_when_PublishAot_is_false(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var projectName = "HellowWorldNativeAotApp";
                var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "false";
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
                var publishCommand = new PublishCommand(testAsset);
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true", "/p:CheckEolTargetFramework=false")
                    .Should().Pass()
                    .And.NotHaveStdOutContaining("IL2026")
                    .And.NotHaveStdErrContaining("NETSDK1179")
                    .And.NotHaveStdErrContaining("warning")
                    .And.NotHaveStdOutContaining("warning");
 
                var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
                var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
                var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
 
                // PublishAot=false will be a normal publish
                File.Exists(publishedDll).Should().BeTrue();
 
                var command = new RunExeCommand(Log, publishedExe)
                    .Execute().Should().Pass()
                    .And.HaveStdOutContaining("Hello World");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_app_runs_in_debug_with_no_config_when_PublishAot_is_enabled(string targetFramework)
        {
            // NativeAOT application publish directory should not contain any <App>.deps.json or <App>.runtimeconfig.json
            // The test writes a key-value pair to the runtimeconfig file and checks that the app can access it
            var projectName = "NativeAotAppForConfigTestDbg";
            var projectConfiguration = "Debug";
 
            var testProject = CreateAppForConfigCheck(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["Configuration"] = projectConfiguration;
            // Linux symbol files are embedded and require additional steps to be stripped to a separate file
            // assumes /bin (or /usr/bin) are in the PATH
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                testProject.AdditionalProperties["StripSymbols"] = "true";
            }
 
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
                // populate a runtime config file with a key value pair
                // <RuntimeHostConfigurationOption Include="key1" Value="value1" />
                .WithProjectChanges(project => AddRuntimeConfigOption(project));
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                .Should().Pass();
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework, projectConfiguration);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, configuration: projectConfiguration, runtimeIdentifier: rid).FullName;
            var sharedLibSuffix = GetSharedLibSuffix();
            var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
            var publishedRuntimeConfig = Path.Combine(publishDirectory, $"{testProject.Name}.runtimeconfig.json");
            var publishedDeps = Path.Combine(publishDirectory, $"{testProject.Name}.deps.json");
 
            // NativeAOT published dir should not contain a runtime configuration file
            File.Exists(publishedRuntimeConfig).Should().BeFalse();
            // NativeAOT published dir should not contain a dependency file
            File.Exists(publishedDeps).Should().BeFalse();
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            // There should be a debug file
            DoSymbolsExist(publishDirectory, testProject.Name).Should().BeTrue($"{publishDirectory} should contain {testProject.Name} symbol");
            IsNativeImage(publishedExe).Should().BeTrue();
 
            // The app accesses the runtime config file key-value pair
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass();
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_app_runs_in_release_with_no_config_when_PublishAot_is_enabled(string targetFramework)
        {
            var projectName = "NativeAotAppForConfigTestRel";
            var projectConfiguration = "Release";
 
            var testProject = CreateAppForConfigCheck(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["Configuration"] = projectConfiguration;
            // Linux symbol files are embedded and require additional steps to be stripped to a separate file
            // assumes /bin (or /usr/bin) are in the PATH
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                testProject.AdditionalProperties["StripSymbols"] = "true";
            }
 
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
                // populate a runtime config file with a key value pair
                // <RuntimeHostConfigurationOption Include="key1" Value="value1" />
                .WithProjectChanges(project => AddRuntimeConfigOption(project));
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                .Should().Pass();
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework, projectConfiguration);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
 
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, configuration: projectConfiguration, runtimeIdentifier: rid).FullName;
            var sharedLibSuffix = GetSharedLibSuffix();
            var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
            var publishedRuntimeConfig = Path.Combine(publishDirectory, $"{testProject.Name}.runtimeconfig.json");
            var publishedDeps = Path.Combine(publishDirectory, $"{testProject.Name}.deps.json");
 
            // NativeAOT published dir should not contain a runtime configuration file
            File.Exists(publishedRuntimeConfig).Should().BeFalse();
            // NativeAOT published dir should not contain a dependency file
            File.Exists(publishedDeps).Should().BeFalse();
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            // There should be a debug file
            DoSymbolsExist(publishDirectory, testProject.Name).Should().BeTrue($"{publishDirectory} should contain {testProject.Name} symbol");
            IsNativeImage(publishedExe).Should().BeTrue();
 
            // The app accesses the runtime config file key-value pair
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass();
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_app_builds_with_config_when_PublishAot_is_enabled(string targetFramework)
        {
            // NativeAOT application publish directory should not contain any <App>.deps.json or <App>.runtimeconfig.json
            // But build step should preserve these files
            var projectName = "NativeAotAppForConfigTest";
 
            var testProject = CreateAppForConfigCheck(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
                // populate a runtime config file with a key value pair
                // <RuntimeHostConfigurationOption Include="key1" Value="value1" />
                .WithProjectChanges(project => AddRuntimeConfigOption(project));
 
            var buildCommand = new BuildCommand(testAsset);
            buildCommand.Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                .Should().Pass();
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var outputDirectory = buildCommand.GetOutputDirectory(targetFramework, runtimeIdentifier: rid).FullName;
            var assemblyPath = Path.Combine(outputDirectory, $"{projectName}{Constants.ExeSuffix}");
            var runtimeConfigPath = Path.Combine(outputDirectory, $"{projectName}.runtimeconfig.json");
            var depsPath = Path.Combine(outputDirectory, $"{projectName}.deps.json");
 
            File.Exists(assemblyPath).Should().BeTrue();
            // NativeAOT build dir should contain a runtime configuration file
            File.Exists(runtimeConfigPath).Should().BeTrue();
            // NativeAOT build dir should contain a dependency file
            File.Exists(depsPath).Should().BeTrue();
        }
 
        private const string Net7ExplicitPackageVersion = "7.0.0";
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData("net7.0")]
        public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_enabled(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // Test uses net7 package of Native AOT, which didn't exist in .NET 7
                return;
            }
 
            var projectName = "HellowWorldNativeAotApp";
 
            var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
 
            // This will add a reference to a package that will also be automatically imported by the SDK
            testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", Net7ExplicitPackageVersion));
 
            // Linux symbol files are embedded and require additional steps to be stripped to a separate file
            // assumes /bin (or /usr/bin) are in the PATH
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                testProject.AdditionalProperties["StripSymbols"] = "true";
            }
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                .Should().Pass()
            // Having an explicit package reference will generate a warning
            .And.HaveStdOutContaining("warning")
            .And.HaveStdOutContaining("Microsoft.DotNet.ILCompiler");
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
            var sharedLibSuffix = GetSharedLibSuffix();
            var publishedDll = Path.Combine(publishDirectory, $"{projectName}{sharedLibSuffix}");
            var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
 
            // NativeAOT published dir should not contain a non-host stand alone package
            File.Exists(publishedDll).Should().BeFalse();
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            DoSymbolsExist(publishDirectory, testProject.Name).Should().BeTrue($"{publishDirectory} should contain {testProject.Name} symbol");
            IsNativeImage(publishedExe).Should().BeTrue();
 
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass()
                .And.HaveStdOutContaining("Hello World");
 
            CheckIlcVersions(testAsset, targetFramework, rid, Net7ExplicitPackageVersion, useRuntimePackLayout: false);
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_empty(string targetFramework)
        {
            var projectName = "HellowWorldNativeAotApp";
            var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
 
            var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
 
            // This will add a reference to a package that will also be automatically imported by the SDK
            testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion));
 
            // Linux symbol files are embedded and require additional steps to be stripped to a separate file
            // assumes /bin (or /usr/bin) are in the PATH
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                testProject.AdditionalProperties["StripSymbols"] = "true";
            }
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true")
                .Should().Pass();
 
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
            var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
            var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
 
            // Not setting PublishAot to true will be a normal publish
            File.Exists(publishedDll).Should().BeTrue();
 
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass()
                .And.HaveStdOutContaining("Hello World");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_runs_with_cross_target_PublishAot_is_enabled(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (RuntimeInformation.OSArchitecture == Architecture.X64))
            {
                var projectName = "HellowWorldNativeAotApp";
                var rid = "win-arm64";
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
                var publishCommand = new PublishCommand(testAsset);
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true")
                    .Should().Pass();
                var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
                var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
                var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
                File.Exists(publishedDll).Should().BeFalse();
                File.Exists(publishedExe).Should().BeTrue();
 
                GetKnownILCompilerPackVersion(testAsset, targetFramework, out string expectedVersion);
                CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion, useRuntimePackLayout: true);
            }
        }
 
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_enabled(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (RuntimeInformation.OSArchitecture == Architecture.X64))
            {
                var projectName = "HellowWorldNativeAotApp";
                var rid = "win-arm64";
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
                testProject.RecordProperties("BundledNETCoreAppPackageVersion");
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                // This will add a reference to a package that will also be automatically imported by the SDK
                testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", "$(BundledNETCoreAppPackageVersion)"));
                testProject.AddItem("PackageDownload", new Dictionary<string, string>
                {
                    { "Include", "Microsoft.NETCore.App.Runtime.NativeAOT.win-arm64" },
                    { "Version", $"[$(BundledNETCoreAppPackageVersion)]" }
                });
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
                var publishCommand = new PublishCommand(testAsset);
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true")
                    .Should().Pass()
                // Having an explicit package reference will generate a warning
                .And.HaveStdOutContaining("warning")
                .And.HaveStdOutContaining("Microsoft.DotNet.ILCompiler");
 
                var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
                var targetVersion = buildProperties["BundledNETCoreAppPackageVersion"];
 
                var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
                var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
                var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}");
                File.Exists(publishedDll).Should().BeFalse();
                File.Exists(publishedExe).Should().BeTrue();
 
                CheckIlcVersions(testAsset, targetFramework, rid, targetVersion, useRuntimePackLayout: true);
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_empty(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (RuntimeInformation.OSArchitecture == Architecture.X64))
            {
                var projectName = "HellowWorldNativeAotApp";
                var rid = "win-arm64";
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
 
                // This will add a reference to a package that will also be automatically imported by the SDK
                testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion));
                testProject.PackageReferences.Add(new TestPackageReference("runtime.win-x64.Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion));
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
                var publishCommand = new PublishCommand(testAsset);
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={rid}")
                    .Should().Pass();
 
                // Not setting PublishAot to true will be a normal publish
                var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
                var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll");
                File.Exists(publishedDll).Should().BeTrue();
            }
        }
 
        [RequiresMSBuildVersionFact("17.0.0.32901")]
        public void NativeAot_hw_fails_with_sdk6_PublishAot_is_enabled()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var projectName = "HellowWorldNativeAotApp";
 
                var testProject = CreateHelloWorldTestProject("net6.0", projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject);
 
                var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
                publishCommand
                    .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                    .Should().Fail()
                    .And.HaveStdOutContaining("error NETSDK1207:");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_fails_with_sdk6_PackageReference_PublishAot_is_enabled(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var projectName = "HellowWorldNativeAotApp";
                var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
 
                var testProject = CreateHelloWorldTestProject("net6.0", projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion));
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
                var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
                publishCommand
                    .Execute($"/p:UseCurrentRuntimeIdentifier=true", "/p:SelfContained=true")
                    .Should().Fail()
                    .And.HaveStdOutContaining("error NETSDK1207:");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_fails_with_unsupported_target_rid(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.OSArchitecture == Architecture.X64)
            {
                var projectName = "HelloWorldUnsupportedTargetRid";
                var rid = "linux-x64";
                var unsupportedTargetRid = "linux-arm64";
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
                    .WithProjectChanges(project => OverrideKnownILCompilerPackRuntimeIdentifiers(project, $"{rid};"));
 
                var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={unsupportedTargetRid}", "/p:SelfContained=true")
                    .Should().Fail()
                    .And.HaveStdOutContaining("error NETSDK1203:");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAot_hw_fails_with_unsupported_host_rid(string targetFramework)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.OSArchitecture == Architecture.X64)
            {
                var projectName = "HelloWorldUnsupportedHostRid";
                var supportedTargetRid = "linux-arm64";
 
                var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
                testProject.AdditionalProperties["PublishAot"] = "true";
 
                var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework)
                    .WithProjectChanges(project => OverrideKnownILCompilerPackRuntimeIdentifiers(project, $"{supportedTargetRid};"));
 
                var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
                publishCommand
                    .Execute($"/p:RuntimeIdentifier={supportedTargetRid}", "/p:SelfContained=true")
                    .Should().Fail()
                    .And.HaveStdOutContaining("error NETSDK1204:");
            }
        }
 
        private void OverrideKnownILCompilerPackRuntimeIdentifiers(XDocument project, string runtimeIdentifiers)
        {
            var ns = project.Root.Name.Namespace;
            project.Root.Add(new XElement(ns + "ItemGroup",
                new XElement(ns + "KnownILCompilerPack",
                    new XAttribute("Update", "@(KnownILCompilerPack)"),
                    new XElement(ns + "ILCompilerRuntimeIdentifiers", runtimeIdentifiers),
                    new XElement(ns + "ILCompilerPortableRuntimeIdentifiers", runtimeIdentifiers))));
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void Only_Aot_warnings_are_produced_if_EnableAotAnalyzer_is_set(string targetFramework)
        {
            var projectName = "WarningAppWithAotAnalyzer";
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            // Inactive linker/single-file analyzers should have no effect on the aot analyzer,
            // unless PublishAot is also set.
            testProject.AdditionalProperties["EnableAotAnalyzer"] = "true";
            testProject.AdditionalProperties["SuppressTrimAnalysisWarnings"] = "false";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute(RuntimeIdentifier)
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL3056")
                .And.NotHaveStdOutContaining("warning IL2026")
                .And.NotHaveStdOutContaining("warning IL3002");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void IsAotCompatible_implies_enable_analyzers(string targetFramework)
        {
            var projectName = "WarningAppWithAotAnalyzer";
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.AdditionalProperties["IsAotCompatible"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            buildCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL3056")
                .And.HaveStdOutContaining("warning IL2026")
                .And.HaveStdOutContaining("warning IL3002");
 
            var outputDirectory = buildCommand.GetOutputDirectory(targetFramework).FullName;
            var assemblyPath = Path.Combine(outputDirectory, $"{projectName}.dll");
 
            // injects the IsTrimmable attribute
            AssemblyInfo.Get(assemblyPath).Should().Contain(("AssemblyMetadataAttribute", "IsTrimmable:True"));
 
            var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute(RuntimeIdentifier, "/p:RunAnalyzers=false")
                .Should().Pass()
                .And.NotHaveStdOutContaining("warning IL3050")
                .And.NotHaveStdOutContaining("warning IL3056")
                .And.NotHaveStdOutContaining("warning IL2026")
                .And.NotHaveStdOutContaining("warning IL3002");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData("net5.0", true)]
        [InlineData("net6.0", true)]
        [InlineData("net7.0", false)]
        public void PublishAot_fails_for_unsupported_target_framework(string targetFramework, bool shouldFail)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // OSX wasn't supported before net8
                return;
            }
 
            var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
 
            var testProject = new TestProject()
            {
                Name = "HelloWorld",
                TargetFrameworks = targetFramework
            };
            testProject.AdditionalProperties["PublishAot"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            var result = publishCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true");
            if (shouldFail) {
                result.Should().Fail()
                    .And.HaveStdOutContaining(Strings.AotUnsupportedTargetFramework);
            } else {
                result.Should().Pass()
                    .And.NotHaveStdOutContaining("warning");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.8.0")]
        [InlineData("netstandard2.0", true)]
        [InlineData("net6.0", true)]
        [InlineData("net7.0", false)]
        [InlineData("netstandard2.0;net5.0", true)] // None of these TFMs are supported for AOT
        [InlineData("netstandard2.0;net7.0", false)] // Net7.0 is the min TFM supported for AOT and targeting.
        [InlineData("netstandard2.0;net8.0", false)] // net8.0 is supported for AOT and targeting.
        [InlineData("netstandard2.0;net9.0", true)] // Net9.0 is supported for AOT, but leaves a "gap" for the supported net8.0 TFMs.
        [InlineData("alias-ns2", true)]
        [InlineData("alias-n6", true)]
        [InlineData("alias-n7", false)]
        [InlineData("alias-n7;alias-n8", false)] // If all TFMs are supported, there's no warning even though the project uses aliases.
        [InlineData("alias-ns2;alias-n7", true)] // This is correctly multi-targeted, but the logic can't detect this due to the alias so it still warns.
        public void IsAotCompatible_warns_when_expected_for_not_correctly_multitarget_libraries(string targetFrameworks, bool shouldWarn)
        {
            var rid = EnvironmentInfo.GetCompatibleRid(targetFrameworks);
 
            var testProject = new TestProject()
            {
                Name = "ClassLibTest",
                TargetFrameworks = targetFrameworks
            };
            testProject.AdditionalProperties["IsAotCompatible"] = "true";
            testProject.AdditionalProperties["CheckEolTargetFramework"] = "false"; // Silence warning about targeting EOL TFMs
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFrameworks)
                .WithProjectChanges(AddTargetFrameworkAliases);
 
            var buildCommand = new BuildCommand(testAsset);
            var resultAssertion = buildCommand.Execute("/p:CheckEolTargetFramework=false")
                .Should().Pass();
            if (shouldWarn) {
                resultAssertion
                    // Note: can't check for Strings.IsAotCompatibleUnsupported because each line of
                    // the message gets prefixed with a file path by MSBuild.
                    .And.HaveStdOutContaining($"warning NETSDK1210")
                    .And.HaveStdOutContaining($"<IsAotCompatible Condition=\"$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))\">true</IsAotCompatible>");
            } else {
                resultAssertion.And.NotHaveStdOutContaining($"warning");
            }
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void Requires_analyzers_produce_warnings_without_PublishAot_being_set(string targetFramework)
        {
            var projectName = "WarningAppWithRequiresAnalyzers";
 
            // Enable the different requires analyzers (EnableAotAnalyzer, EnableTrimAnalyzer
            // and EnableSingleFileAnalyzer) without setting PublishAot
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.AdditionalProperties["EnableAotAnalyzer"] = "true";
            testProject.AdditionalProperties["EnableTrimAnalyzer"] = "true";
            testProject.AdditionalProperties["EnableSingleFileAnalyzer"] = "true";
            testProject.AdditionalProperties["SuppressTrimAnalysisWarnings"] = "false";
            testProject.AdditionalProperties["UseCurrentRuntimeIdentifier"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL3056")
                .And.HaveStdOutContaining("warning IL2026")
                .And.HaveStdOutContaining("warning IL3002");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))]
        public void NativeAot_compiler_runs_when_PublishAot_is_enabled(string targetFramework)
        {
            if (targetFramework == "net7.0" && RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                // OSX wasn't supported before net8
                return;
            }
 
            var projectName = "WarningAppWithPublishAot";
 
            // PublishAot should enable the EnableAotAnalyzer, EnableTrimAnalyzer and EnableSingleFileAnalyzer
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["SuppressTrimAnalysisWarnings"] = "false";
            testProject.AdditionalProperties["UseCurrentRuntimeIdentifier"] = "true";
            testProject.AdditionalProperties["SelfContained"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL3056")
                .And.HaveStdOutContaining("warning IL2026")
                .And.HaveStdOutContaining("warning IL3002");
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid);
 
            var publishedExe = Path.Combine(publishDirectory.FullName, $"{testProject.Name}{Constants.ExeSuffix}");
 
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            IsNativeImage(publishedExe).Should().BeTrue();
 
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass()
                .And.HaveStdOutContaining("Hello world");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void Warnings_are_generated_in_build_with_analyzers_enabled(string targetFramework)
        {
 
            var projectName = "WarningAppWithPublishAotAnalyzersDisabled";
 
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["SelfContained"] = "true";
            // The below analyzers are enabled by default but explicitly setting them to true
            testProject.AdditionalProperties["EnableAotAnalyzer"] = "true";
            testProject.AdditionalProperties["EnableTrimAnalyzer"] = "true";
            testProject.AdditionalProperties["EnableSingleFileAnalyzer"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var buildCommand = new BuildCommand(testAsset);
            buildCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL3056")
                .And.HaveStdOutContaining("warning IL2026")
                .And.HaveStdOutContaining("warning IL3002");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void Warnings_are_not_generated_in_build_with_analyzers_disabled(string targetFramework)
        {
 
            var projectName = "WarningAppWithPublishAotAnalyzersDisabled";
 
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["SelfContained"] = "true";
            testProject.AdditionalProperties["EnableAotAnalyzer"] = "false";
            testProject.AdditionalProperties["EnableTrimAnalyzer"] = "false";
            testProject.AdditionalProperties["EnableSingleFileAnalyzer"] = "false";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var buildCommand = new BuildCommand(testAsset);
            buildCommand
                .Execute()
                .Should().Pass()
                .And.NotHaveStdOutContaining("warning IL3050")
                .And.NotHaveStdOutContaining("warning IL3056")
                .And.NotHaveStdOutContaining("warning IL2026")
                .And.NotHaveStdOutContaining("warning IL3002");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void Warnings_are_generated_even_with_analyzers_disabled(string targetFramework)
        {
 
            var projectName = "WarningAppWithPublishAotAnalyzersDisabled";
 
            // PublishAot enables the EnableAotAnalyzer, EnableTrimAnalyzer and EnableSingleFileAnalyzer
            // only if they don't have a predefined value
            var testProject = CreateTestProjectWithAnalysisWarnings(targetFramework, projectName, true);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["EnableAotAnalyzer"] = "false";
            testProject.AdditionalProperties["EnableTrimAnalyzer"] = "false";
            testProject.AdditionalProperties["EnableSingleFileAnalyzer"] = "false";
            testProject.AdditionalProperties["SuppressTrimAnalysisWarnings"] = "false";
            testProject.AdditionalProperties["UseCurrentRuntimeIdentifier"] = "true";
            testProject.AdditionalProperties["SelfContained"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("warning IL3050")
                .And.HaveStdOutContaining("warning IL2026");
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid);
 
            var publishedExe = Path.Combine(publishDirectory.FullName, $"{testProject.Name}{Constants.ExeSuffix}");
 
            // The exe exist and should be native
            File.Exists(publishedExe).Should().BeTrue();
            IsNativeImage(publishedExe).Should().BeTrue();
 
            var command = new RunExeCommand(Log, publishedExe)
                .Execute().Should().Pass()
                .And.HaveStdOutContaining("Hello world");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAotStaticLib_only_runs_when_switch_is_enabled(string targetFramework)
        {
            var projectName = "AotStaticLibraryPublish";
 
            var testProject = CreateTestProjectWithAotLibrary(targetFramework, projectName);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["UseCurrentRuntimeIdentifier"] = "true";
            testProject.AdditionalProperties["SelfContained"] = "true";
            testProject.AdditionalProperties["NativeLib"] = "Static";
            testProject.SelfContained = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute()
                .Should().Pass();
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
            var staticLibSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".lib" : ".a";
            var publishedDll = Path.Combine(publishDirectory, $"{projectName}{staticLibSuffix}");
 
            // The lib exist and should be native
            File.Exists(publishedDll).Should().BeTrue();
            IsNativeImage(publishedDll).Should().BeTrue();
        }
 
        [Theory]
        [InlineData("Static")]
        [InlineData("Shared")]
        public void NativeAotLib_warns_when_eventpipe_is_enabled(string libType)
        {
            var projectName = "AotStaticLibraryPublishWithEventPipe";
            var rid = EnvironmentInfo.GetCompatibleRid(ToolsetInfo.CurrentTargetFramework);
 
            var testProject = CreateTestProjectWithAotLibrary(ToolsetInfo.CurrentTargetFramework, projectName);
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["RuntimeIdentifier"] = rid;
            testProject.AdditionalProperties["NativeLib"] = libType;
            testProject.AdditionalProperties["SelfContained"] = "true";
            testProject.AdditionalProperties["EventSourceSupport"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject);
 
            var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute()
                .Should().Pass()
                .And.HaveStdOutContaining("EventSource is not supported or recommended when compiling to a native library");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void NativeAotSharedLib_only_runs_when_switch_is_enabled(string targetFramework)
        {
            var projectName = "AotSharedLibraryPublish";
 
            var testProject = CreateTestProjectWithAotLibrary(targetFramework, projectName);
            testProject.RecordProperties("NETCoreSdkPortableRuntimeIdentifier");
            testProject.AdditionalProperties["PublishAot"] = "true";
            testProject.AdditionalProperties["UseCurrentRuntimeIdentifier"] = "true";
            testProject.AdditionalProperties["NativeLib"] = "Shared";
            testProject.AdditionalProperties["SelfContained"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new PublishCommand(testAsset);
            publishCommand
                .Execute()
                .Should().Pass();
 
            var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework);
            var rid = buildProperties["NETCoreSdkPortableRuntimeIdentifier"];
            var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName;
            var sharedLibSuffix = GetSharedLibSuffix();
            var publishedDll = Path.Combine(publishDirectory, $"{projectName}{sharedLibSuffix}");
 
            // The lib exist and should be native
            File.Exists(publishedDll).Should().BeTrue();
            IsNativeImage(publishedDll).Should().BeTrue();
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void It_publishes_with_implicit_rid_with_NativeAotApp(string targetFramework)
        {
            var projectName = "ImplicitRidNativeAotApp";
            var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
            testProject.AdditionalProperties["PublishAot"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var publishCommand = new DotnetPublishCommand(Log, Path.Combine(testAsset.TestRoot, testProject.Name));
            publishCommand
                .Execute()
                .Should()
                .Pass();
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void It_builds_with_dynamiccodesupport_false_when_publishaot_true(string targetFramework)
        {
            var projectName = "DynamicCodeSupportFalseApp";
            var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true);
            testProject.AdditionalProperties["PublishAot"] = "true";
            var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework);
 
            var buildCommand = new BuildCommand(testAsset);
            buildCommand
                .Execute()
                .Should()
                .Pass();
 
            string outputDirectory = buildCommand.GetOutputDirectory(targetFramework: targetFramework).FullName;
            string runtimeConfigFile = Path.Combine(outputDirectory, $"{projectName}.runtimeconfig.json");
            string runtimeConfigContents = File.ReadAllText(runtimeConfigFile);
 
            JObject runtimeConfig = JObject.Parse(runtimeConfigContents);
            JToken configProperties = runtimeConfig["runtimeOptions"]["configProperties"];
            configProperties["System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported"].Value<bool>()
                .Should().BeFalse();
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void It_accepts_option_to_show_all_warnings(string targetFramework)
        {
            var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
            var testAssetName = "TrimmedAppWithReferences";
            var testAsset = _testAssetsManager
                .CopyTestAsset(testAssetName, identifier: targetFramework)
                .WithSource();
 
            var publishCommand = new PublishCommand(testAsset, "App");
            publishCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:TrimmerSingleWarn=false", "/p:PublishAot=true")
                .Should().Pass()
                .And.HaveStdOutMatching("IL2026: App.Program.Main.*Program.RUC")
                .And.HaveStdOutMatching("IL2026: ProjectReference.ProjectReferenceLib.Method.*ProjectReferenceLib.RUC")
                .And.HaveStdOutMatching("IL2026: TransitiveProjectReference.TransitiveProjectReferenceLib.Method.*TransitiveProjectReferenceLib.RUC")
                .And.HaveStdOutMatching("IL2026:.*PackageReference.PackageReferenceLib")
                .And.NotHaveStdOutContaining("IL2104");
        }
 
        [RequiresMSBuildVersionTheory("17.0.0.32901")]
        [InlineData(ToolsetInfo.CurrentTargetFramework)]
        public void It_can_show_single_warning_per_assembly(string targetFramework)
        {
            var rid = EnvironmentInfo.GetCompatibleRid(targetFramework);
            var testAssetName = "TrimmedAppWithReferences";
            var testAsset = _testAssetsManager
                .CopyTestAsset(testAssetName, identifier: targetFramework)
                .WithSource()
                .WithProjectChanges(project =>
                {
                    SetMetadata(project, "PackageReference", "TrimmerSingleWarn", "false");
                    SetMetadata(project, "ProjectReference", "TrimmerSingleWarn", "true");
                    SetMetadata(project, "App", "TrimmerSingleWarn", "true");
                });
 
            var publishCommand = new PublishCommand(testAsset, "App");
            publishCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:TrimmerSingleWarn=false", "/p:PublishAot=true")
                .Should().Pass()
                .And.NotHaveStdOutMatching("IL2026: App.Program.Main.*Program.RUC")
                .And.NotHaveStdOutMatching("IL2026: ProjectReference.ProjectReferenceLib.Method.*ProjectReferenceLib.RUC")
                .And.HaveStdOutMatching("IL2026: TransitiveProjectReference.TransitiveProjectReferenceLib.Method.*TransitiveProjectReferenceLib.RUC")
                .And.HaveStdOutMatching("IL2026:.*PackageReference.PackageReferenceLib")
                .And.NotHaveStdOutMatching("IL2104.*'PackageReference'")
                .And.HaveStdOutMatching("IL2104.*'App'")
                .And.HaveStdOutMatching("IL2104.*'ProjectReference'")
                .And.NotHaveStdOutMatching("IL2104.*'TransitiveProjectReference'");
        }
 
        private void SetMetadata(XDocument project, string assemblyName, string key, string value)
        {
            var ns = project.Root.Name.Namespace;
            var targetName = "SetTrimmerMetadata";
            var target = project.Root.Elements(ns + "Target")
                .Where(e => e.Attribute("Name")?.Value == targetName)
                .FirstOrDefault();
 
            if (target == null)
            {
                target = new XElement(ns + "Target",
                    new XAttribute("BeforeTargets", "PrepareForILLink"),
                    new XAttribute("Name", targetName));
                project.Root.Add(target);
            }
 
            target.Add(new XElement(ns + "ItemGroup",
                new XElement("ManagedAssemblyToLink",
                    new XAttribute("Condition", $"'%(FileName)' == '{assemblyName}'"),
                    new XAttribute(key, value))));
        }
 
        private void GetKnownILCompilerPackVersion(TestAsset testAsset, string targetFramework, out string version)
        {
            var getKnownPacks = new GetValuesCommand(testAsset, "KnownILCompilerPack", GetValuesCommand.ValueType.Item, targetFramework)
            {
                MetadataNames = new List<string> { "TargetFramework", "ILCompilerPackVersion" }
            };
            getKnownPacks.Execute().Should().Pass();
            var knownPacks = getKnownPacks.GetValuesWithMetadata();
            version = knownPacks
                .Where(i => i.metadata["TargetFramework"] == targetFramework)
                .Select(i => i.metadata["ILCompilerPackVersion"])
                .Single();
        }
 
        private void CheckIlcVersions(TestAsset testAsset, string targetFramework, string rid, string expectedVersion, bool useRuntimePackLayout)
        {
            // Compiler version matches expected version
            var ilcToolsPathCommand = new GetValuesCommand(testAsset, "IlcToolsPath", targetFramework: targetFramework)
            {
                DependsOnTargets = "WriteIlcRspFileForCompilation"
            };
            ilcToolsPathCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true").Should().Pass();
            var ilcToolsPath = ilcToolsPathCommand.GetValues()[0];
            var ilcVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(ilcToolsPath)));
            ilcVersion.Should().Be(expectedVersion);
 
            // Compilation references (corelib) match expected version
            var ilcReferenceCommand = new GetValuesCommand(testAsset, "IlcReference", GetValuesCommand.ValueType.Item, targetFramework)
            {
                DependsOnTargets = "WriteIlcRspFileForCompilation"
            };
            ilcReferenceCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true").Should().Pass();
            var ilcReference = ilcReferenceCommand.GetValues();
            var corelibReference = ilcReference.Where(r => Path.GetFileName(r).Equals("System.Private.CoreLib.dll")).Single();
            string ilcReferenceVersion;
            if (useRuntimePackLayout)
            {
                // In the runtime pack layout, System.Private.CoreLib.dll is in the runtimes/<rid>/native directory
                ilcReferenceVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(corelibReference)))));
            }
            else
            {
                // In the old layout, System.Private.CoreLib.dll is in the framework directory
                ilcReferenceVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(corelibReference)));
            }
            ilcReferenceVersion.Should().Be(expectedVersion);
        }
 
        private TestProject CreateHelloWorldTestProject(string targetFramework, string projectName, bool isExecutable)
        {
            var testProject = new TestProject()
            {
                Name = projectName,
                TargetFrameworks = targetFramework,
                IsExe = isExecutable
            };
 
            testProject.SourceFiles[$"{projectName}.cs"] = @"
using System;
class Test
{
    static void Main(String[] args)
    {
        Console.WriteLine(""Hello World"");
    }
}";
 
            return testProject;
        }
 
        private TestProject CreateAppForConfigCheck(string targetFramework, string projectName, bool isExecutable)
        {
            var testProject = new TestProject()
            {
                Name = projectName,
                TargetFrameworks = targetFramework,
                IsExe = isExecutable
            };
 
            testProject.SourceFiles[$"{projectName}.cs"] = @"
using System;
class Test
{
    static void Main(String[] args)
    {
        var config1 = AppContext.GetData(""key1"");
 
        string expected = ""value1"";
 
        if(!config1.Equals(expected))
            throw new ArgumentException($""Test failed, expected:<{expected}>, returned:<{config1}>"");
    }
}";
 
            return testProject;
        }
 
        private TestProject CreateTestProjectWithAnalysisWarnings(string targetFramework, string projectName, bool isExecutable)
        {
            var testProject = new TestProject()
            {
                Name = projectName,
                TargetFrameworks = targetFramework,
                IsExe = isExecutable
            };
 
            testProject.SourceFiles[$"{projectName}.cs"] = @"
using System;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
class C
{
    static void Main()
    {
        ProduceAotAnalysisWarning();
        ProduceTrimAnalysisWarning();
        ProduceSingleFileAnalysisWarning();
        Console.WriteLine(""Hello world"");
    }
 
    [RequiresDynamicCode(""Aot analysis warning"")]
    static void ProduceAotAnalysisWarning()
    {
    }
 
    [RequiresDynamicCode(""Aot analysis warning"")]
    static C()
    {
    }
 
    [RequiresUnreferencedCode(""Trim analysis warning"")]
    static void ProduceTrimAnalysisWarning()
    {
    }
 
    [RequiresAssemblyFiles(""Single File analysis warning"")]
    static void ProduceSingleFileAnalysisWarning()
    {
    }
}";
 
            return testProject;
        }
 
        private static string GetSharedLibSuffix()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return ".dll";
            }
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return ".so";
            }
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                return ".dylib";
            }
            throw new PlatformNotSupportedException();
        }
 
        private static bool DoSymbolsExist(string baseDir, string baseName)
        {
            string suffix;
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                suffix = ".pdb";
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                suffix = ".dbg";
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                suffix = ".dsym";
            }
            else
            {
                throw new PlatformNotSupportedException();
            }
 
            var path = Path.Combine(baseDir, baseName + suffix);
            // Symbol file is a directory on OSX
            return RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
                ? Directory.Exists(path)
                : File.Exists(path);
        }
 
        private TestProject CreateTestProjectWithAotLibrary(string targetFramework, string projectName)
        {
            var testProject = new TestProject()
            {
                Name = projectName,
                TargetFrameworks = targetFramework
            };
 
            testProject.SourceFiles[$"{projectName}.cs"] = @"
public class NativeLibraryClass
{
    public void LibraryMethod()
    {
    }
}";
            return testProject;
        }
 
        private static bool IsNativeImage(string path)
        {
            try
            {
                using (FileStream fs = new(path, FileMode.Open, FileAccess.Read))
                using (var peReader = new PEReader(fs))
                {
                    return !peReader.HasMetadata;
                }
            }
            catch (BadImageFormatException)
            {
                return true;
            }
        }
 
        private void AddRuntimeConfigOption(XDocument project)
        {
            var ns = project.Root.Name.Namespace;
 
            project.Root.Add(new XElement(ns + "ItemGroup",
                                new XElement("RuntimeHostConfigurationOption",
                                    new XAttribute("Include", "key1"),
                                    new XAttribute("Value", "value1"))));
        }
    }
}