diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 0748db81a..6e03ba1ff 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -232,6 +232,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ShellShim. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ToolPackage.Tests", "test\Microsoft.DotNet.ToolPackage.Tests\Microsoft.DotNet.ToolPackage.Tests.csproj", "{91BFE800-1624-4A58-A1CE-339705A8FFD0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Tools.Tests.ComponentMocks", "test\Microsoft.DotNet.Tools.Tests.ComponentMocks\Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj", "{E442F4C1-08DB-470F-B9A6-197444CD0295}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tool_launcher", "src\tool_launcher\tool_launcher.csproj", "{EDF19BE6-F20F-4AD0-8E3B-E837030726A5}" EndProject Global @@ -1666,6 +1668,30 @@ Global {EDF19BE6-F20F-4AD0-8E3B-E837030726A5}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {EDF19BE6-F20F-4AD0-8E3B-E837030726A5}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU {EDF19BE6-F20F-4AD0-8E3B-E837030726A5}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|x64.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|x64.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|x86.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Debug|x86.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.MinSizeRel|x86.Build.0 = Debug|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|Any CPU.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|x64.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|x64.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|x86.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.Release|x86.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {E442F4C1-08DB-470F-B9A6-197444CD0295}.RelWithDebInfo|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1740,6 +1766,7 @@ Global {E84C08C9-70D7-48B0-9507-ADB8B9A2694C} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {91BFE800-1624-4A58-A1CE-339705A8FFD0} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {EDF19BE6-F20F-4AD0-8E3B-E837030726A5} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} + {E442F4C1-08DB-470F-B9A6-197444CD0295} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B526D2CE-EE2D-4AD4-93EF-1867D90FF1F5} diff --git a/build/test/TestProjects.targets b/build/test/TestProjects.targets index 8a5d21a55..96b08c34d 100644 --- a/build/test/TestProjects.targets +++ b/build/test/TestProjects.targets @@ -15,6 +15,7 @@ diff --git a/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs b/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs index 4b08b51db..ecdec5b5d 100644 --- a/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs +++ b/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyModel, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("dotnet, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Tests.Utilities, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Tests.ComponentMocks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyModel.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] @@ -15,3 +16,5 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("dotnet-test.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")] [assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.ShellShim.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.ToolPackage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("dotnet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/dotnet/Properties/AssemblyInfo.cs b/src/dotnet/Properties/AssemblyInfo.cs index 249576dc2..25bd8cb8c 100644 --- a/src/dotnet/Properties/AssemblyInfo.cs +++ b/src/dotnet/Properties/AssemblyInfo.cs @@ -17,5 +17,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("dotnet-sln-remove.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("dotnet-msbuild.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("dotnet-run.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Tests.Utilities, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Tests.ComponentMocks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.ToolPackage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.DotNet.ShellShim.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/dotnet/ShellShim/IShellShimMaker.cs b/src/dotnet/ShellShim/IShellShimMaker.cs new file mode 100644 index 000000000..35ff02493 --- /dev/null +++ b/src/dotnet/ShellShim/IShellShimMaker.cs @@ -0,0 +1,8 @@ +namespace Microsoft.DotNet.ShellShim +{ + public interface IShellShimMaker + { + void CreateShim(string packageExecutablePath, string shellCommandName); + void EnsureCommandNameUniqueness(string shellCommandName); + } +} diff --git a/src/dotnet/ShellShim/ShellShimMaker.cs b/src/dotnet/ShellShim/ShellShimMaker.cs index bf204a1ef..f3247c620 100644 --- a/src/dotnet/ShellShim/ShellShimMaker.cs +++ b/src/dotnet/ShellShim/ShellShimMaker.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.EnvironmentAbstractions; namespace Microsoft.DotNet.ShellShim { - public class ShellShimMaker + public class ShellShimMaker : IShellShimMaker { private const string LauncherExeResourceName = "Microsoft.DotNet.Tools.Launcher.Executable"; private const string LauncherConfigResourceName = "Microsoft.DotNet.Tools.Launcher.Config"; diff --git a/src/dotnet/ToolPackage/IToolPackageObtainer.cs b/src/dotnet/ToolPackage/IToolPackageObtainer.cs new file mode 100644 index 000000000..e48694f9e --- /dev/null +++ b/src/dotnet/ToolPackage/IToolPackageObtainer.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.ToolPackage +{ + internal interface IToolPackageObtainer + { + ToolConfigurationAndExecutablePath ObtainAndReturnExecutablePath( + string packageId, + string packageVersion = null, + FilePath? nugetconfig = null, + string targetframework = null, + string source = null); + } +} diff --git a/src/dotnet/ToolPackage/ToolPackageObtainer.cs b/src/dotnet/ToolPackage/ToolPackageObtainer.cs index 151fe83e7..3ef3597b0 100644 --- a/src/dotnet/ToolPackage/ToolPackageObtainer.cs +++ b/src/dotnet/ToolPackage/ToolPackageObtainer.cs @@ -10,7 +10,7 @@ using NuGet.ProjectModel; namespace Microsoft.DotNet.ToolPackage { - internal class ToolPackageObtainer + internal class ToolPackageObtainer : IToolPackageObtainer { private readonly Lazy _bundledTargetFrameworkMoniker; private readonly Func _getTempProjectPath; diff --git a/src/dotnet/commands/dotnet-install/dotnet-install-tool/InstallToolCommand.cs b/src/dotnet/commands/dotnet-install/dotnet-install-tool/InstallToolCommand.cs index 276a681f5..783666939 100644 --- a/src/dotnet/commands/dotnet-install/dotnet-install-tool/InstallToolCommand.cs +++ b/src/dotnet/commands/dotnet-install/dotnet-install-tool/InstallToolCommand.cs @@ -14,18 +14,27 @@ using Microsoft.Extensions.EnvironmentAbstractions; namespace Microsoft.DotNet.Tools.Install.Tool { - public class InstallToolCommand : CommandBase + internal class InstallToolCommand : CommandBase { - private static string _packageId; - private static string _packageVersion; - private static string _configFilePath; - private static string _framework; - private static string _source; - private static bool _global; + private readonly IToolPackageObtainer _toolPackageObtainer; + private readonly IEnvironmentPathInstruction _environmentPathInstruction; + private readonly IShellShimMaker _shellShimMaker; + private readonly IReporter _reporter; + + private readonly string _packageId; + private readonly string _packageVersion; + private readonly string _configFilePath; + private readonly string _framework; + private readonly string _source; + private readonly bool _global; public InstallToolCommand( AppliedOption appliedCommand, - ParseResult parseResult) + ParseResult parseResult, + IToolPackageObtainer toolPackageObtainer = null, + IShellShimMaker shellShimMaker = null, + IEnvironmentPathInstruction environmentPathInstruction = null, + IReporter reporter = null) : base(parseResult) { if (appliedCommand == null) @@ -39,6 +48,27 @@ namespace Microsoft.DotNet.Tools.Install.Tool _framework = appliedCommand.ValueOrDefault("framework"); _source = appliedCommand.ValueOrDefault("source"); _global = appliedCommand.ValueOrDefault("global"); + + var cliFolderPathCalculator = new CliFolderPathCalculator(); + var executablePackagePath = new DirectoryPath(cliFolderPathCalculator.ExecutablePackagesPath); + var offlineFeedPath = new DirectoryPath(cliFolderPathCalculator.CliFallbackFolderPath); + _toolPackageObtainer = toolPackageObtainer ?? new ToolPackageObtainer( + executablePackagePath, + offlineFeedPath, + () => new DirectoryPath(Path.GetTempPath()) + .WithSubDirectories(Path.GetRandomFileName()) + .WithFile(Path.GetRandomFileName() + ".csproj"), + new Lazy(BundledTargetFramework.GetTargetFrameworkMoniker), + new PackageToProjectFileAdder(), + new ProjectRestorer()); + + _environmentPathInstruction = environmentPathInstruction + ?? EnvironmentPathFactory + .CreateEnvironmentPathInstruction(); + + _shellShimMaker = shellShimMaker ?? new ShellShimMaker(executablePackagePath.Value); + + _reporter = reporter ?? Reporter.Output; } public override int Execute() @@ -48,33 +78,25 @@ namespace Microsoft.DotNet.Tools.Install.Tool throw new GracefulException(LocalizableStrings.InstallToolCommandOnlySupportGlobal); } - var cliFolderPathCalculator = new CliFolderPathCalculator(); - var executablePackagePath = new DirectoryPath(cliFolderPathCalculator.ExecutablePackagesPath); - var offlineFeedPath = new DirectoryPath(cliFolderPathCalculator.CliFallbackFolderPath); + var toolConfigurationAndExecutablePath = ObtainPackage(); - var toolConfigurationAndExecutablePath = ObtainPackage(executablePackagePath, offlineFeedPath); - - var shellShimMaker = new ShellShimMaker(executablePackagePath.Value); var commandName = toolConfigurationAndExecutablePath.Configuration.CommandName; - shellShimMaker.EnsureCommandNameUniqueness(commandName); + _shellShimMaker.EnsureCommandNameUniqueness(commandName); - shellShimMaker.CreateShim( + _shellShimMaker.CreateShim( toolConfigurationAndExecutablePath.Executable.Value, commandName); - EnvironmentPathFactory - .CreateEnvironmentPathInstruction() + _environmentPathInstruction .PrintAddPathInstructionIfPathDoesNotExist(); - Reporter.Output.WriteLine( + _reporter.WriteLine( string.Format(LocalizableStrings.InstallationSucceeded, commandName)); return 0; } - private static ToolConfigurationAndExecutablePath ObtainPackage( - DirectoryPath executablePackagePath, - DirectoryPath offlineFeedPath) + private ToolConfigurationAndExecutablePath ObtainPackage() { try { @@ -84,18 +106,7 @@ namespace Microsoft.DotNet.Tools.Install.Tool configFile = new FilePath(_configFilePath); } - var toolPackageObtainer = - new ToolPackageObtainer( - executablePackagePath, - offlineFeedPath, - () => new DirectoryPath(Path.GetTempPath()) - .WithSubDirectories(Path.GetRandomFileName()) - .WithFile(Path.GetRandomFileName() + ".csproj"), - new Lazy(BundledTargetFramework.GetTargetFrameworkMoniker), - new PackageToProjectFileAdder(), - new ProjectRestorer()); - - return toolPackageObtainer.ObtainAndReturnExecutablePath( + return _toolPackageObtainer.ObtainAndReturnExecutablePath( packageId: _packageId, packageVersion: _packageVersion, nugetconfig: configFile, diff --git a/test/Microsoft.DotNet.Cli.Tests.sln b/test/Microsoft.DotNet.Cli.Tests.sln index 863d564db..05bde078d 100644 --- a/test/Microsoft.DotNet.Cli.Tests.sln +++ b/test/Microsoft.DotNet.Cli.Tests.sln @@ -86,6 +86,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ShellShim. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.ToolPackage.Tests", "Microsoft.DotNet.ToolPackage.Tests\Microsoft.DotNet.ToolPackage.Tests.csproj", "{453C809B-40FC-4A93-93B8-DE449D48B9FF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Tools.Tests.ComponentMocks", "Microsoft.DotNet.Tools.Tests.ComponentMocks\Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj", "{A3DE5654-7755-45C8-8AE5-5B5B00BEB248}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -564,6 +566,18 @@ Global {453C809B-40FC-4A93-93B8-DE449D48B9FF}.Release|x64.Build.0 = Release|Any CPU {453C809B-40FC-4A93-93B8-DE449D48B9FF}.Release|x86.ActiveCfg = Release|Any CPU {453C809B-40FC-4A93-93B8-DE449D48B9FF}.Release|x86.Build.0 = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|x64.ActiveCfg = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|x64.Build.0 = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|x86.ActiveCfg = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Debug|x86.Build.0 = Debug|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|Any CPU.Build.0 = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|x64.ActiveCfg = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|x64.Build.0 = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|x86.ActiveCfg = Release|Any CPU + {A3DE5654-7755-45C8-8AE5-5B5B00BEB248}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/Microsoft.DotNet.ShellShim.Tests/Microsoft.DotNet.ShellShim.Tests.csproj b/test/Microsoft.DotNet.ShellShim.Tests/Microsoft.DotNet.ShellShim.Tests.csproj index 64fdac72b..6cae0fd85 100644 --- a/test/Microsoft.DotNet.ShellShim.Tests/Microsoft.DotNet.ShellShim.Tests.csproj +++ b/test/Microsoft.DotNet.ShellShim.Tests/Microsoft.DotNet.ShellShim.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/test/Microsoft.DotNet.ShellShim.Tests/ShellShimMakerTests.cs b/test/Microsoft.DotNet.ShellShim.Tests/ShellShimMakerTests.cs index 75379aaae..3bf4ff3d0 100644 --- a/test/Microsoft.DotNet.ShellShim.Tests/ShellShimMakerTests.cs +++ b/test/Microsoft.DotNet.ShellShim.Tests/ShellShimMakerTests.cs @@ -11,6 +11,8 @@ using FluentAssertions; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.TestFramework; using Microsoft.DotNet.Tools.Test.Utilities; +using Microsoft.DotNet.Tools.Test.Utilities.Mock; +using Microsoft.DotNet.Tools.Tests.ComponentMocks; using Xunit; using Xunit.Abstractions; @@ -91,14 +93,23 @@ namespace Microsoft.DotNet.ShellShim.Tests } } - [Fact] - public void GivenAnExecutablePathWithExistingSameNameShimItThrows() + [InlineData(false)] + [InlineData(true)] + public void GivenAnExecutablePathWithExistingSameNameShimItThrows(bool testMockBehaviorIsInSync) { var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName(); MakeNameConflictingCommand(TempRoot.Root, shellCommandName); - var shellShimMaker = new ShellShimMaker(TempRoot.Root); + IShellShimMaker shellShimMaker; + if (testMockBehaviorIsInSync) + { + shellShimMaker = new ShellShimMakerMock(TempRoot.Root); + } + else + { + shellShimMaker = new ShellShimMaker(TempRoot.Root); + } Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName); a.ShouldThrow() @@ -107,13 +118,22 @@ namespace Microsoft.DotNet.ShellShim.Tests $"Failed to install tool {shellCommandName}. A command with the same name already exists."); } - - [Fact] - public void GivenAnExecutablePathWithoutExistingSameNameShimItShouldNotThrow() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenAnExecutablePathWithoutExistingSameNameShimItShouldNotThrow(bool testMockBehaviorIsInSync) { var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName(); - var shellShimMaker = new ShellShimMaker(TempRoot.Root); + IShellShimMaker shellShimMaker; + if (testMockBehaviorIsInSync) + { + shellShimMaker = new ShellShimMakerMock(TempRoot.Root); + } + else + { + shellShimMaker = new ShellShimMaker(TempRoot.Root); + } Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName); a.ShouldNotThrow(); diff --git a/test/Microsoft.DotNet.ToolPackage.Tests/Microsoft.DotNet.ToolPackage.Tests.csproj b/test/Microsoft.DotNet.ToolPackage.Tests/Microsoft.DotNet.ToolPackage.Tests.csproj index 736655e5b..0670e8c91 100644 --- a/test/Microsoft.DotNet.ToolPackage.Tests/Microsoft.DotNet.ToolPackage.Tests.csproj +++ b/test/Microsoft.DotNet.ToolPackage.Tests/Microsoft.DotNet.ToolPackage.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageObtainerTests.cs b/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageObtainerTests.cs index 4e948966e..8b60baef3 100644 --- a/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageObtainerTests.cs +++ b/test/Microsoft.DotNet.ToolPackage.Tests/ToolPackageObtainerTests.cs @@ -2,48 +2,35 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.IO; using System.Reflection; using FluentAssertions; using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.Extensions.EnvironmentAbstractions; using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Install.Tool; using Xunit; +using Microsoft.DotNet.Tools.Tests.ComponentMocks; namespace Microsoft.DotNet.ToolPackage.Tests { public class ToolPackageObtainerTests : TestBase { - [Fact] - public void GivenNugetConfigAndPackageNameAndVersionAndTargetFrameworkWhenCallItCanDownloadThePackage() - { - FilePath nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); - var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); - - var packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); - ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = packageObtainer.ObtainAndReturnExecutablePath( - packageId: TestPackageId, - packageVersion: TestPackageVersion, - nugetconfig: nugetConfigPath, - targetframework: _testTargetframework); - - var executable = toolConfigurationAndExecutablePath - .Executable; - - File.Exists(executable.Value) - .Should() - .BeTrue(executable + " should have the executable"); - } - [Fact] public void GivenNoFeedItThrows() { var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); ToolPackageObtainer packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); + new ToolPackageObtainer( + new DirectoryPath(toolsPath), + new DirectoryPath("no such path"), + GetUniqueTempProjectPathEachTest, + new Lazy(), + new PackageToProjectFileAdder(), + new ProjectRestorer()); Action a = () => packageObtainer.ObtainAndReturnExecutablePath( packageId: TestPackageId, @@ -80,24 +67,57 @@ namespace Microsoft.DotNet.ToolPackage.Tests .Should() .BeTrue(executable + " should have the executable"); - executable.Value.Should().NotContain(GetTestLocalFeedPath(), "Executalbe should not be still in fallbackfolder"); - executable.Value.Should().Contain(toolsPath, "Executalbe should be copied to tools Path"); + executable.Value.Should().NotContain(GetTestLocalFeedPath(), "Executable should not be still in fallbackfolder"); + executable.Value.Should().Contain(toolsPath, "Executable should be copied to tools Path"); + + File.Delete(executable.Value); } - [Fact] - public void GivenNugetConfigAndPackageNameAndVersionAndTargetFrameworkWhenCallItCreateAssetFile() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenNugetConfigAndPackageNameAndVersionAndTargetFrameworkWhenCallItCanDownloadThePackage( + bool testMockBehaviorIsInSync) + { + FilePath nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); + var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); + + var packageObtainer = + ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync, nugetConfigPath.Value); + + ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath + = packageObtainer.ObtainAndReturnExecutablePath( + packageId: TestPackageId, + packageVersion: TestPackageVersion, + nugetconfig: nugetConfigPath, + targetframework: _testTargetframework); + + FilePath executable = toolConfigurationAndExecutablePath.Executable; + File.Exists(executable.Value) + .Should() + .BeTrue(executable + " should have the executable"); + + File.Delete(executable.Value); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenNugetConfigAndPackageNameAndVersionAndTargetFrameworkWhenCallItCreateAssetFile( + bool testMockBehaviorIsInSync) { var nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); var packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); + ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync, nugetConfigPath.Value); - ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = packageObtainer.ObtainAndReturnExecutablePath( - packageId: TestPackageId, - packageVersion: TestPackageVersion, - nugetconfig: nugetConfigPath, - targetframework: _testTargetframework); + ToolConfigurationAndExecutablePath toolConfigurationAndExecutableDirectory = + packageObtainer.ObtainAndReturnExecutablePath( + packageId: TestPackageId, + packageVersion: TestPackageVersion, + nugetconfig: nugetConfigPath, + targetframework: _testTargetframework); /* From mytool.dll to project.assets.json @@ -106,7 +126,7 @@ namespace Microsoft.DotNet.ToolPackage.Tests /dependency2 package id/ /project.assets.json */ - var assetJsonPath = toolConfigurationAndExecutablePath + var assetJsonPath = toolConfigurationAndExecutableDirectory .Executable .GetDirectoryPath() .GetParentPath() @@ -119,10 +139,14 @@ namespace Microsoft.DotNet.ToolPackage.Tests File.Exists(assetJsonPath) .Should() .BeTrue(assetJsonPath + " should be created"); + + File.Delete(assetJsonPath); } - [Fact] - public void GivenAllButNoNugetConfigFilePathItCanDownloadThePackage() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenAllButNoNugetConfigFilePathItCanDownloadThePackage(bool testMockBehaviorIsInSync) { var uniqueTempProjectPath = GetUniqueTempProjectPathEachTest(); var tempProjectDirectory = uniqueTempProjectPath.GetDirectoryPath(); @@ -137,14 +161,22 @@ namespace Microsoft.DotNet.ToolPackage.Tests Directory.SetCurrentDirectory(nugetConfigPath.GetDirectoryPath().Value); - var packageObtainer = - new ToolPackageObtainer( + IToolPackageObtainer packageObtainer; + if (testMockBehaviorIsInSync) + { + packageObtainer = new ToolPackageObtainerMock(); + } + else + { + packageObtainer = new ToolPackageObtainer( new DirectoryPath(toolsPath), new DirectoryPath("no such path"), () => uniqueTempProjectPath, new Lazy(), new PackageToProjectFileAdder(), new ProjectRestorer()); + } + ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = packageObtainer.ObtainAndReturnExecutablePath( packageId: TestPackageId, @@ -156,37 +188,46 @@ namespace Microsoft.DotNet.ToolPackage.Tests File.Exists(executable.Value) .Should() .BeTrue(executable + " should have the executable"); + + File.Delete(executable.Value); } - [Fact] - public void GivenAllButNoPackageVersionItCanDownloadThePackage() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenAllButNoPackageVersionItCanDownloadThePackage(bool testMockBehaviorIsInSync) { var nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); var packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); - ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = packageObtainer.ObtainAndReturnExecutablePath( - packageId: TestPackageId, - packageVersion: TestPackageVersion, - nugetconfig: nugetConfigPath, - targetframework: _testTargetframework); + ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync, nugetConfigPath.Value); + + ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = + packageObtainer.ObtainAndReturnExecutablePath( + packageId: TestPackageId, + nugetconfig: nugetConfigPath, + targetframework: _testTargetframework); var executable = toolConfigurationAndExecutablePath.Executable; File.Exists(executable.Value) .Should() .BeTrue(executable + " should have the executable"); + + File.Delete(executable.Value); } - [Fact] - public void GivenAllButNoPackageVersionAndInvokeTwiceItShouldNotThrow() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenAllButNoPackageVersionAndInvokeTwiceItShouldNotThrow(bool testMockBehaviorIsInSync) { var nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); var packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); + ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync, nugetConfigPath.Value); packageObtainer.ObtainAndReturnExecutablePath( packageId: TestPackageId, @@ -201,21 +242,45 @@ namespace Microsoft.DotNet.ToolPackage.Tests secondCall.ShouldNotThrow(); } - - [Fact] - public void GivenAllButNoTargetFrameworkItCanDownloadThePackage() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenAllButNoTargetFrameworkItCanDownloadThePackage(bool testMockBehaviorIsInSync) { var nugetConfigPath = WriteNugetConfigFileToPointToTheFeed(); var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); - var packageObtainer = - new ToolPackageObtainer( + IToolPackageObtainer packageObtainer; + if (testMockBehaviorIsInSync) + { + packageObtainer = new ToolPackageObtainerMock(additionalFeeds: + new List + { + new MockFeed + { + Type = MockFeedType.ExplicitNugetConfig, + Uri = nugetConfigPath.Value, + Packages = new List + { + new MockFeedPackage + { + PackageId = "global.tool.console.demo", + Version = "1.0.4" + } + } + } + }); + } + else + { + packageObtainer = new ToolPackageObtainer( new DirectoryPath(toolsPath), new DirectoryPath("no such path"), GetUniqueTempProjectPathEachTest, new Lazy(() => BundledTargetFramework.GetTargetFrameworkMoniker()), new PackageToProjectFileAdder(), new ProjectRestorer()); + } ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath = packageObtainer.ObtainAndReturnExecutablePath( packageId: TestPackageId, @@ -227,28 +292,41 @@ namespace Microsoft.DotNet.ToolPackage.Tests File.Exists(executable.Value) .Should() .BeTrue(executable + " should have the executable"); + + File.Delete(executable.Value); } - [Fact] - public void GivenNonExistentNugetConfigFileItThrows() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenNonExistentNugetConfigFileItThrows(bool testMockBehaviorIsInSync) { var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); var packageObtainer = - ConstructDefaultPackageObtainer(toolsPath); - Action a = () => packageObtainer.ObtainAndReturnExecutablePath( - packageId: TestPackageId, - packageVersion: TestPackageVersion, - nugetconfig: new FilePath("NonExistent.file"), - targetframework: _testTargetframework); + ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync); + + var nonExistNugetConfigFile = new FilePath("NonExistent.file"); + Action a = () => + { + packageObtainer.ObtainAndReturnExecutablePath( + packageId: TestPackageId, + packageVersion: TestPackageVersion, + nugetconfig: nonExistNugetConfigFile, + targetframework: _testTargetframework); + }; a.ShouldThrow() .And - .Message.Should().Contain("does not exist"); + .Message.Should().Contain(string.Format( + CommonLocalizableStrings.NuGetConfigurationFileDoesNotExist, + Path.GetFullPath(nonExistNugetConfigFile.Value))); } - [Fact] - public void GivenASourceItCanObtainThePackageFromThatSource() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GivenASourceItCanObtainThePackageFromThatSource(bool testMockBehaviorIsInSync) { var toolsPath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName()); @@ -257,13 +335,15 @@ namespace Microsoft.DotNet.ToolPackage.Tests packageId: TestPackageId, packageVersion: TestPackageVersion, targetframework: _testTargetframework, - source: GetTestLocalFeedPath()); + source:GetTestLocalFeedPath()); var executable = toolConfigurationAndExecutableDirectory.Executable; File.Exists(executable.Value) .Should() .BeTrue(executable + " should have the executable"); + + File.Delete(executable.Value); } private static readonly Func GetUniqueTempProjectPathEachTest = () => @@ -275,8 +355,59 @@ namespace Microsoft.DotNet.ToolPackage.Tests return tempProjectPath; }; - private static ToolPackageObtainer ConstructDefaultPackageObtainer(string toolsPath) + private static IToolPackageObtainer ConstructDefaultPackageObtainer( + string toolsPath, + bool testMockBehaviorIsInSync = false, + string addNugetConfigFeedWithFilePath = null, + string addSourceFeedWithFilePath = null) { + if (testMockBehaviorIsInSync) + { + if (addNugetConfigFeedWithFilePath != null) + { + return new ToolPackageObtainerMock(additionalFeeds: + new List + { + new MockFeed + { + Type = MockFeedType.ExplicitNugetConfig, + Uri = addNugetConfigFeedWithFilePath, + Packages = new List + { + new MockFeedPackage + { + PackageId = "global.tool.console.demo", + Version = "1.0.4" + } + } + } + }); + } + + if (addSourceFeedWithFilePath != null) + { + return new ToolPackageObtainerMock(additionalFeeds: + new List + { + new MockFeed + { + Type = MockFeedType.ExplicitNugetConfig, + Uri = addSourceFeedWithFilePath, + Packages = new List + { + new MockFeedPackage + { + PackageId = "global.tool.console.demo", + Version = "1.0.4" + } + } + } + }); + } + + return new ToolPackageObtainerMock(); + } + return new ToolPackageObtainer( new DirectoryPath(toolsPath), new DirectoryPath("no such path"), @@ -292,7 +423,7 @@ namespace Microsoft.DotNet.ToolPackage.Tests var tempPathForNugetConfigWithWhiteSpace = Path.Combine(Path.GetTempPath(), - Path.GetRandomFileName() + " " + Path.GetRandomFileName()); + Path.GetRandomFileName() + " " + Path.GetRandomFileName()); Directory.CreateDirectory(tempPathForNugetConfigWithWhiteSpace); NuGetConfig.Write( diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/EnvironmentPathInstructionMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/EnvironmentPathInstructionMock.cs new file mode 100644 index 000000000..c07f5ad1b --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/EnvironmentPathInstructionMock.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + internal class EnvironmentPathInstructionMock : IEnvironmentPathInstruction + { + private readonly string _packageExecutablePath; + private readonly bool _packageExecutablePathExists; + private readonly IReporter _reporter; + + public EnvironmentPathInstructionMock( + IReporter reporter, + string packageExecutablePath, + bool packageExecutablePathExists = false) + { + _packageExecutablePath = + packageExecutablePath ?? throw new ArgumentNullException(nameof(packageExecutablePath)); + _reporter = reporter ?? throw new ArgumentNullException(nameof(reporter)); + _packageExecutablePathExists = packageExecutablePathExists; + } + + public void PrintAddPathInstructionIfPathDoesNotExist() + { + if (!PackageExecutablePathExists()) + { + _reporter.WriteLine("INSTRUCTION"); + } + } + + private bool PackageExecutablePathExists() + { + return _packageExecutablePathExists; + } + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj new file mode 100644 index 000000000..bd29dccd9 --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj @@ -0,0 +1,16 @@ + + + $(CliTargetFramework) + $(MicrosoftNETCoreAppPackageVersion) + Microsoft.DotNet.Tools.Tests.ComponentMocks + ../../tools/Key.snk + $(AssetTargetFallback);dotnet5.4;portable-net451+win8 + true + true + + + + + + + diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeed.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeed.cs new file mode 100644 index 000000000..a2199c75e --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeed.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + public class MockFeed + { + public MockFeedType Type; + public string Uri; + public List Packages; + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedPackage.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedPackage.cs new file mode 100644 index 000000000..6bf9fc44a --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedPackage.cs @@ -0,0 +1,11 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + public class MockFeedPackage + { + public string PackageId; + public string Version; + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedType.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedType.cs new file mode 100644 index 000000000..c79dc327e --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/MockFeedType.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + public enum MockFeedType + { + FeedFromLookUpNugetConfig, + ExplicitNugetConfig, + Source + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Properties/Properties.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Properties/Properties.cs new file mode 100644 index 000000000..b358c68f3 --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Properties/Properties.cs @@ -0,0 +1,8 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("dotnet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.ToolPackage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.ShellShim.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ShellShimMakerMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ShellShimMakerMock.cs new file mode 100644 index 000000000..3e19da8db --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ShellShimMakerMock.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ShellShim; +using Microsoft.Extensions.EnvironmentAbstractions; +using Newtonsoft.Json; + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + internal class ShellShimMakerMock : IShellShimMaker + { + private static IFileSystem _fileSystem; + private readonly string _pathToPlaceShim; + + public ShellShimMakerMock(string pathToPlaceShim, IFileSystem fileSystem = null) + { + _pathToPlaceShim = + pathToPlaceShim ?? throw new ArgumentNullException(nameof(pathToPlaceShim)); + + _fileSystem = fileSystem ?? new FileSystemWrapper(); + } + + public void CreateShim(string packageExecutablePath, string shellCommandName) + { + var packageExecutable = new FilePath(packageExecutablePath); + + + var fakeshim = new FakeShim + { + Runner = "dotnet", + ExecutablePath = packageExecutable.Value + }; + var script = JsonConvert.SerializeObject(fakeshim); + + FilePath scriptPath = new FilePath(Path.Combine(_pathToPlaceShim, shellCommandName)); + _fileSystem.File.WriteAllText(scriptPath.Value, script); + } + + public void EnsureCommandNameUniqueness(string shellCommandName) + { + if (_fileSystem.File.Exists(Path.Combine(_pathToPlaceShim, shellCommandName))) + { + throw new GracefulException( + string.Format(CommonLocalizableStrings.FailInstallToolSameName, + shellCommandName)); + } + } + + public class FakeShim + { + public string Runner { get; set; } + public string ExecutablePath { get; set; } + } + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageObtainerMock.cs b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageObtainerMock.cs new file mode 100644 index 000000000..efc42f4e8 --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.ComponentMocks/ToolPackageObtainerMock.cs @@ -0,0 +1,159 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.DotNet.ToolPackage; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.Tools.Tests.ComponentMocks +{ + internal class ToolPackageObtainerMock : IToolPackageObtainer + { + private readonly Action _beforeRunObtain; + public const string FakeEntrypointName = "SimulatorEntryPoint.dll"; + public const string FakeCommandName = "SimulatorCommand"; + private static IFileSystem _fileSystem; + private string _fakeExecutableDirectory; + private List _mockFeeds; + + public ToolPackageObtainerMock( + IFileSystem fileSystemWrapper = null, + bool useDefaultFeed = true, + IEnumerable additionalFeeds = null, + Action beforeRunObtain = null) + { + _beforeRunObtain = beforeRunObtain ?? (() => { }); + _fileSystem = fileSystemWrapper ?? new FileSystemWrapper(); + _mockFeeds = new List(); + + if (useDefaultFeed) + { + _mockFeeds.Add(new MockFeed + { + Type = MockFeedType.FeedFromLookUpNugetConfig, + Packages = new List + { + new MockFeedPackage + { + PackageId = "global.tool.console.demo", + Version = "1.0.4" + } + } + }); + } + + if (additionalFeeds != null) + { + _mockFeeds.AddRange(additionalFeeds); + } + } + + public ToolConfigurationAndExecutablePath ObtainAndReturnExecutablePath( + string packageId, + string packageVersion = null, + FilePath? nugetconfig = null, + string targetframework = null, + string source = null) + { + _beforeRunObtain(); + + PickFeedByNugetConfig(nugetconfig); + PickFeedBySource(source); + + MockFeedPackage package = _mockFeeds + .SelectMany(f => f.Packages) + .Where(p => MatchPackageVersion(p, packageId, packageVersion)).OrderByDescending(p => p.Version) + .FirstOrDefault(); + + if (package == null) + { + throw new PackageObtainException("simulated cannot find package"); + } + + packageVersion = package.Version; + targetframework = targetframework ?? "targetframework"; + + var packageIdVersionDirectory = Path.Combine("toolPath", packageId, packageVersion); + + _fakeExecutableDirectory = Path.Combine(packageIdVersionDirectory, + packageId, packageVersion, "morefolders", "tools", + targetframework); + var fakeExecutable = Path.Combine(_fakeExecutableDirectory, FakeEntrypointName); + + if (!_fileSystem.Directory.Exists(_fakeExecutableDirectory)) + { + _fileSystem.Directory.CreateDirectory(_fakeExecutableDirectory); + } + + _fileSystem.File.CreateEmptyFile(Path.Combine(packageIdVersionDirectory, "project.assets.json")); + _fileSystem.File.CreateEmptyFile(fakeExecutable); + + return new ToolConfigurationAndExecutablePath( + toolConfiguration: new ToolConfiguration(FakeCommandName, FakeEntrypointName), + executable: new FilePath(fakeExecutable)); + } + + private void PickFeedBySource(string source) + { + if (source != null) + { + var feed = _mockFeeds.SingleOrDefault( + f => f.Type == MockFeedType.Source + && f.Uri == source); + + if (feed != null) + { + _mockFeeds = new List + { + feed + }; + } + else + { + _mockFeeds = new List(); + } + } + } + + private void PickFeedByNugetConfig(FilePath? nugetconfig) + { + if (nugetconfig != null) + { + if (!_fileSystem.File.Exists(nugetconfig.Value.Value)) + { + throw new PackageObtainException( + string.Format(CommonLocalizableStrings.NuGetConfigurationFileDoesNotExist, + Path.GetFullPath(nugetconfig.Value.Value))); + } + + var feed = _mockFeeds.SingleOrDefault( + f => f.Type == MockFeedType.ExplicitNugetConfig + && f.Uri == nugetconfig.Value.Value); + + if (feed != null) + { + _mockFeeds = new List + { + feed + }; + } + else + { + _mockFeeds = new List(); + } + } + } + + private static bool MatchPackageVersion(MockFeedPackage p, string packageId, string packageVersion) + { + if (packageVersion == null) + { + return p.PackageId == packageId; + } + return p.PackageId == packageId && p.Version == packageVersion; + } + } +} diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Properties/Properties.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Properties/Properties.cs index 98bfc776e..be0d4944b 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Properties/Properties.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Properties/Properties.cs @@ -3,5 +3,8 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyModel.Tests , PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer.UnitTests , PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyModel.Tests , PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer.UnitTests , PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("dotnet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.ToolPackage.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.DotNet.ShellShim.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/test/dotnet.Tests/InstallToolCommandTests/InstallToolCommandTests.cs b/test/dotnet.Tests/InstallToolCommandTests/InstallToolCommandTests.cs new file mode 100644 index 000000000..118db746b --- /dev/null +++ b/test/dotnet.Tests/InstallToolCommandTests/InstallToolCommandTests.cs @@ -0,0 +1,211 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using FluentAssertions; +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ToolPackage; +using Microsoft.DotNet.Tools.Install.Tool; +using Microsoft.DotNet.Tools.Tests.ComponentMocks; +using Microsoft.Extensions.DependencyModel.Tests; +using Microsoft.Extensions.EnvironmentAbstractions; +using Newtonsoft.Json; +using Xunit; +using Parser = Microsoft.DotNet.Cli.Parser; +using LocalizableStrings = Microsoft.DotNet.Tools.Install.Tool.LocalizableStrings; + +namespace Microsoft.DotNet.Tests.InstallToolCommandTests +{ + public class InstallToolCommandTests + { + private readonly IFileSystem _fileSystemWrapper; + private readonly ToolPackageObtainerMock _toolPackageObtainerMock; + private readonly ShellShimMakerMock _shellShimMakerMock; + private readonly EnvironmentPathInstructionMock _environmentPathInstructionMock; + private readonly AppliedOption _appliedCommand; + private readonly ParseResult _parseResult; + private readonly FakeReporter _fakeReporter; + private const string PathToPlaceShim = "pathToPlace"; + + public InstallToolCommandTests() + { + _fileSystemWrapper = new FileSystemMockBuilder().Build(); + _toolPackageObtainerMock = new ToolPackageObtainerMock(_fileSystemWrapper); + _shellShimMakerMock = new ShellShimMakerMock(PathToPlaceShim, _fileSystemWrapper); + _fakeReporter = new FakeReporter(); + _environmentPathInstructionMock = + new EnvironmentPathInstructionMock(_fakeReporter, PathToPlaceShim); + + ParseResult result = Parser.Instance.Parse("dotnet install tool -g global.tool.console.demo"); + _appliedCommand = result["dotnet"]["install"]["tool"]; + var parser = Parser.Instance; + _parseResult = parser.ParseFrom("dotnet install", new[] {"tool", "global.tool.console.demo"}); + } + + [Fact] + public void WhenRunWithPackageIdItShouldCreateValidShim() + { + var installToolCommand = new InstallToolCommand(_appliedCommand, + _parseResult, + _toolPackageObtainerMock, + _shellShimMakerMock, + _environmentPathInstructionMock); + + installToolCommand.Execute(); + + // It is hard to simulate shell behavior. Only Assert shim can point to executable dll + _fileSystemWrapper.File.Exists(Path.Combine("pathToPlace", ToolPackageObtainerMock.FakeCommandName)) + .Should().BeTrue(); + var deserializedFakeShim = JsonConvert.DeserializeObject( + _fileSystemWrapper.File.ReadAllText( + Path.Combine("pathToPlace", + ToolPackageObtainerMock.FakeCommandName))); + _fileSystemWrapper.File.Exists(deserializedFakeShim.ExecutablePath).Should().BeTrue(); + } + + [Fact] + public void WhenRunWithPackageIdWithSourceItShouldCreateValidShim() + { + const string sourcePath = "http://mysouce.com"; + ParseResult result = Parser.Instance.Parse($"dotnet install tool -g global.tool.console.demo --source {sourcePath}"); + AppliedOption appliedCommand = result["dotnet"]["install"]["tool"]; + const string packageId = "global.tool.console.demo"; + ParseResult parseResult = + Parser.Instance.ParseFrom("dotnet install", new[] {"tool", packageId, "--source", sourcePath}); + + var installToolCommand = new InstallToolCommand(appliedCommand, + parseResult, + new ToolPackageObtainerMock(_fileSystemWrapper, additionalFeeds: new List + { + new MockFeed + { + Type = MockFeedType.Source, + Uri = sourcePath, + Packages = new List + { + new MockFeedPackage + { + PackageId = packageId, + Version = "1.0.4" + } + } + } + }), + _shellShimMakerMock, + _environmentPathInstructionMock); + + installToolCommand.Execute(); + + // It is hard to simulate shell behavior. Only Assert shim can point to executable dll + _fileSystemWrapper.File.Exists(Path.Combine("pathToPlace", ToolPackageObtainerMock.FakeCommandName)) + .Should().BeTrue(); + ShellShimMakerMock.FakeShim deserializedFakeShim = + JsonConvert.DeserializeObject( + _fileSystemWrapper.File.ReadAllText( + Path.Combine("pathToPlace", + ToolPackageObtainerMock.FakeCommandName))); + _fileSystemWrapper.File.Exists(deserializedFakeShim.ExecutablePath).Should().BeTrue(); + } + + [Fact] + public void WhenRunWithPackageIdItShouldShowPathInstruction() + { + var installToolCommand = new InstallToolCommand(_appliedCommand, + _parseResult, + _toolPackageObtainerMock, + _shellShimMakerMock, + _environmentPathInstructionMock); + + installToolCommand.Execute(); + + _fakeReporter.Message.Single().Should().NotBeEmpty(); + } + + [Fact] + public void GivenFailedPackageObtainWhenRunWithPackageIdItShouldThrow() + { + var toolPackageObtainerSimulatorThatThrows + = new ToolPackageObtainerMock( + _fileSystemWrapper, true, null, + () => throw new PackageObtainException("Simulated error")); + var installToolCommand = new InstallToolCommand( + _appliedCommand, + _parseResult, + toolPackageObtainerSimulatorThatThrows, + _shellShimMakerMock, + _environmentPathInstructionMock, + _fakeReporter); + + Action a = () => installToolCommand.Execute(); + + a.ShouldThrow() + .And.Message.Should() + .Contain(string.Format(LocalizableStrings.InstallFailedNuget, "Simulated error")); + } + + [Fact] + public void GivenInCorrectToolConfigurationWhenRunWithPackageIdItShouldThrow() + { + var toolPackageObtainerSimulatorThatThrows + = new ToolPackageObtainerMock( + _fileSystemWrapper, true, null, + () => throw new ToolConfigurationException("Simulated error")); + var installToolCommand = new InstallToolCommand( + _appliedCommand, + _parseResult, + toolPackageObtainerSimulatorThatThrows, + _shellShimMakerMock, + _environmentPathInstructionMock, + _fakeReporter); + + Action a = () => installToolCommand.Execute(); + a.ShouldThrow() + .And.Message.Should() + .Contain(string.Format(LocalizableStrings.InstallFailedPackage, "Simulated error")); + } + + [Fact] + public void WhenRunWithPackageIdItShouldShowSuccessMessage() + { + var installToolCommand = new InstallToolCommand( + _appliedCommand, + _parseResult, + _toolPackageObtainerMock, + _shellShimMakerMock, + new EnvironmentPathInstructionMock(_fakeReporter, PathToPlaceShim, true), + _fakeReporter); + + installToolCommand.Execute(); + + _fakeReporter + .Message + .Single().Should() + .Contain(string.Format(LocalizableStrings.InstallationSucceeded, "SimulatorCommand")); + } + + internal class FakeReporter : IReporter + { + public List Message { get; set; } = new List(); + + public void WriteLine(string message) + { + Message.Add(message); + } + + public void WriteLine() + { + throw new NotImplementedException(); + } + + public void Write(string message) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/dotnet.Tests/dotnet.Tests.csproj b/test/dotnet.Tests/dotnet.Tests.csproj index 6095d1a0e..561d03b72 100644 --- a/test/dotnet.Tests/dotnet.Tests.csproj +++ b/test/dotnet.Tests/dotnet.Tests.csproj @@ -71,6 +71,7 @@ +