File: PackagedCommandTests.cs
Web Access
Project: ..\..\..\test\dotnet.Tests\dotnet.Tests.csproj (dotnet.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 Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.Utils;
 
namespace Microsoft.DotNet.Tests
{
    public class PackagedCommandTests : SdkTest
    {
        public PackagedCommandTests(ITestOutputHelper log) : base(log)
        {
        }
 
        //  https://github.com/dotnet/sdk/issues/49665
        //  ailed to load /private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, error: dlopen(/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, 0x0001): tried: '/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')), 
        [PlatformSpecificTheory(TestPlatforms.Any & ~TestPlatforms.OSX)]
        [InlineData("AppWithDirectAndToolDep")]
        [InlineData("AppWithToolDependency")]
        public void TestProjectToolIsAvailableThroughDriver(string appName)
        {
            var testInstance = _testAssetsManager.CopyTestAsset(appName)
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            new BuildCommand(testInstance)
                .Execute()
                .Should().Pass();
 
            new DotnetCommand(Log, "portable")
                .WithWorkingDirectory(testInstance.Path)
                .Execute()
                .Should().HaveStdOutContaining("Hello Portable World!")
                     .And.NotHaveStdErr()
                     .And.Pass();
        }
 
        [RequiresSpecificFrameworkTheory("netcoreapp1.1")]
        [InlineData(true)]
        [InlineData(false)]
        public void IfPreviousVersionOfSharedFrameworkIsInstalled_ToolsTargetingItRun(bool toolPrefersCLIRuntime)
        {
            var testInstance = _testAssetsManager.CopyTestAsset("AppWithToolDependency", identifier: toolPrefersCLIRuntime ? "preferCLIRuntime" : "")
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            testInstance = testInstance.WithProjectChanges(project =>
            {
                var ns = project.Root.Name.Namespace;
 
                var toolReference = project.Descendants(ns + "DotNetCliToolReference")
                    .Where(tr => tr.Attribute("Include").Value == "dotnet-portable")
                    .Single();
 
                toolReference.Attribute("Include").Value =
                    toolPrefersCLIRuntime ? "dotnet-portable-v1-prefercli" : "dotnet-portable-v1";
            });
 
            new BuildCommand(testInstance)
                .Execute()
                .Should().Pass();
 
            var result = new DotnetCommand(Log)
                .WithWorkingDirectory(testInstance.Path)
                .Execute(toolPrefersCLIRuntime ? "portable-v1-prefercli" : "portable-v1");
 
            result.Should().Pass()
                .And.HaveStdOutContaining("I'm running on shared framework version");
 
        }
 
        [RequiresSpecificFrameworkFact("netcoreapp1.1")]
        public void IfAToolHasNotBeenRestoredForNetCoreApp2_0ItFallsBackToNetCoreApp1_x()
        {
            string toolName = "dotnet-portable-v1";
 
            var testInstance = _testAssetsManager.CopyTestAsset("AppWithToolDependency")
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            string projectFolder = null;
 
            testInstance = testInstance.WithProjectChanges((projectPath, project) =>
            {
                projectFolder = Path.GetDirectoryName(projectPath);
                var ns = project.Root.Name.Namespace;
 
                //  Remove reference to tool that won't restore on 1.x
                project.Descendants(ns + "DotNetCliToolReference")
                    .Where(tr => tr.Attribute("Include").Value == "dotnet-PreferCliRuntime")
                    .Remove();
 
                var toolReference = project.Descendants(ns + "DotNetCliToolReference")
                    .Where(tr => tr.Attribute("Include").Value == "dotnet-portable")
                    .Single();
 
                toolReference.Attribute("Include").Value = toolName;
 
                // Restore tools for .NET Core 1.1
                project.Root.Element(ns + "PropertyGroup")
                    .Add(new XElement(ns + "DotnetCliToolTargetFramework", "netcoreapp1.1"));
 
                //  Use project-specific global packages folder
                project.Root.Element(ns + "PropertyGroup")
                    .Add(new XElement(ns + "RestorePackagesPath", @"$(MSBuildProjectDirectory)\packages"));
 
            });
 
            var toolFolder = Path.Combine(projectFolder,
                                          "packages",
                                          ".tools",
                                          toolName);
 
 
            new RestoreCommand(testInstance)
                .Execute()
                .Should()
                .Pass();
 
            var result = new DotnetCommand(Log)
                    .WithWorkingDirectory(testInstance.Path)
                    .Execute("portable-v1");
 
            result.Should().Pass()
                .And.HaveStdOutContaining("I'm running on shared framework version");
        }
 
        // Old .net tool test that doesn't work off Windows
        [WindowsOnlyFact]
        public void CanInvokeToolWhosePackageNameIsDifferentFromDllName()
        {
            var testInstance = _testAssetsManager.CopyTestAsset("AppWithDepOnToolWithOutputName")
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            new BuildCommand(testInstance)
                .Execute()
                .Should().Pass();
 
            new DotnetCommand(Log)
                .WithWorkingDirectory(testInstance.Path)
                .Execute("tool-with-output-name")
                .Should().HaveStdOutContaining("Tool with output name!")
                     .And.NotHaveStdErr()
                     .And.Pass();
        }
 
        [Fact]
        public void ItShowsErrorWhenToolIsNotRestored()
        {
            var testInstance = _testAssetsManager.CopyTestAsset("AppWithNonExistingToolDependency", testAssetSubdirectory: "NonRestoredTestProjects")
                .WithSource();
 
            new DotnetCommand(Log)
                .WithWorkingDirectory(testInstance.Path)
                .Execute("nonexistingtool")
                .Should().Fail()
                    .And.HaveStdErrContaining(LocalizableStrings.NoExecutableFoundMatchingCommandErrorMessage)
                    .And.HaveStdOutContaining(
                        string.Format(LocalizableStrings.NoExecutableFoundMatchingCommand, "dotnet-nonexistingtool"));
        }
 
        //  https://github.com/dotnet/sdk/issues/49665
        //  Failed to load /private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, error: dlopen(/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, 0x0001): tried: '/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (no such file), '/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64'))
        [PlatformSpecificFact(TestPlatforms.Any & ~TestPlatforms.OSX)]
        public void ItRunsToolRestoredToSpecificPackageDir()
        {
            var testInstance = _testAssetsManager.CopyTestAsset("ToolWithRandomPackageName", testAssetSubdirectory: "NonRestoredTestProjects")
                .WithSource();
 
            var appWithDepOnToolDir = new DirectoryInfo(testInstance.Path).Sub("AppWithDepOnTool");
            var toolWithRandPkgNameDir = new DirectoryInfo(testInstance.Path).Sub("ToolWithRandomPackageName");
            var pkgsDir = new DirectoryInfo(testInstance.Path).CreateSubdirectory("pkgs");
 
            // 3ebdd4f1-a194-470a-b01a-4515672791d1
            //                         ^-- index = 24
            string randomPackageName = Guid.NewGuid().ToString().Substring(24);
 
            // TODO: This is a workaround for https://github.com/dotnet/cli/issues/5020
            SetGeneratedPackageName(appWithDepOnToolDir.File("AppWithDepOnTool.csproj"),
                                    randomPackageName);
 
            SetGeneratedPackageName(toolWithRandPkgNameDir.File("ToolWithRandomPackageName.csproj"),
                                    randomPackageName);
 
 
            new DotnetCommand(Log)
                .WithWorkingDirectory(toolWithRandPkgNameDir.FullName)
                .Execute("pack", "-o", pkgsDir.FullName, "/p:version=1.0.0")
                .Should().Pass();
 
            new DotnetCommand(Log)
                .WithWorkingDirectory(appWithDepOnToolDir.FullName)
                .Execute("restore", "--source", pkgsDir.FullName)
                .Should().Pass();
 
            new DotnetCommand(Log)
                .WithWorkingDirectory(appWithDepOnToolDir.FullName)
                .Execute("randompackage")
                .Should().Pass()
                .And.HaveStdOutContaining("Hello World from tool!")
                .And.NotHaveStdErr();
        }
 
        //  https://github.com/dotnet/sdk/issues/49665
        //  Failed to load /private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, error: dlopen(/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib, 0x0001): tried: '/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (no such file), '/private/tmp/helix/working/B3F609DC/p/d/shared/Microsoft.NETCore.App/9.0.0/libhostpolicy.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64'))
        [PlatformSpecificFact(TestPlatforms.Any & ~TestPlatforms.OSX)]
        public void ToolsCanAccessDependencyContextProperly()
        {
            var testInstance = _testAssetsManager.CopyTestAsset("DependencyContextFromTool")
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            testInstance.Restore(Log);
 
            new DotnetCommand(Log, "dependency-context-test")
                .WithWorkingDirectory(testInstance.Path)
                .Execute()
                .Should().Pass();
        }
 
        [Fact]
        public void TestProjectDependencyIsNotAvailableThroughDriver()
        {
            var testInstance = _testAssetsManager.CopyTestAsset("AppWithDirectDep")
                .WithSource();
 
            NuGetConfigWriter.Write(testInstance.Path, TestContext.Current.TestPackages);
 
            new BuildCommand(testInstance)
                .Execute()
                .Should().Pass();
 
            var currentDirectory = Directory.GetCurrentDirectory();
 
            CommandResult result = new DotnetCommand(Log, "hello")
                .WithWorkingDirectory(testInstance.Path)
                .Execute();
 
            result.StdErr.Should().Contain(LocalizableStrings.NoExecutableFoundMatchingCommandErrorMessage);
            result.StdOut.Should().Contain(
                string.Format(LocalizableStrings.NoExecutableFoundMatchingCommand, "dotnet-hello"));
 
            result.Should().Fail();
        }
 
        private void SetGeneratedPackageName(FileInfo project, string packageName)
        {
            const string propertyName = "GeneratedPackageId";
            var p = ProjectRootElement.Open(project.FullName, new ProjectCollection(), true);
            p.AddProperty(propertyName, packageName);
            p.Save();
        }
    }
}