Use rich mock to test InstallCommand (#8402)

To ensure the mock has the same behavior the component has, run mock under the same tests the adapter has.
It is a common problem that moq has -- "everything is mocked out, you are not test anything"
This commit is contained in:
William Lee 2018-01-24 10:16:27 -08:00 committed by GitHub
parent f4a0d2db0e
commit 05052c0541
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 881 additions and 113 deletions

View file

@ -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}

View file

@ -15,6 +15,7 @@
<PreTestProjectsToExclude Condition=" 'Non-test projects in test directory' != 'consider moving elsewhere' "
Include="test/ArgumentsReflector/ArgumentsReflector.csproj;
test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj;
test/Microsoft.DotNet.Tools.Tests.ComponentMocks/Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj;
test/Msbuild.Tests.Utilities/Msbuild.Tests.Utilities.csproj;
test/Performance/Performance.csproj;
test/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.csproj" />

View file

@ -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")]

View file

@ -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")]

View file

@ -0,0 +1,8 @@
namespace Microsoft.DotNet.ShellShim
{
public interface IShellShimMaker
{
void CreateShim(string packageExecutablePath, string shellCommandName);
void EnsureCommandNameUniqueness(string shellCommandName);
}
}

View file

@ -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";

View file

@ -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);
}
}

View file

@ -10,7 +10,7 @@ using NuGet.ProjectModel;
namespace Microsoft.DotNet.ToolPackage
{
internal class ToolPackageObtainer
internal class ToolPackageObtainer : IToolPackageObtainer
{
private readonly Lazy<string> _bundledTargetFrameworkMoniker;
private readonly Func<FilePath> _getTempProjectPath;

View file

@ -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,53 +48,11 @@ namespace Microsoft.DotNet.Tools.Install.Tool
_framework = appliedCommand.ValueOrDefault<string>("framework");
_source = appliedCommand.ValueOrDefault<string>("source");
_global = appliedCommand.ValueOrDefault<bool>("global");
}
public override int Execute()
{
if (!_global)
{
throw new GracefulException(LocalizableStrings.InstallToolCommandOnlySupportGlobal);
}
var cliFolderPathCalculator = new CliFolderPathCalculator();
var executablePackagePath = new DirectoryPath(cliFolderPathCalculator.ExecutablePackagesPath);
var offlineFeedPath = new DirectoryPath(cliFolderPathCalculator.CliFallbackFolderPath);
var toolConfigurationAndExecutablePath = ObtainPackage(executablePackagePath, offlineFeedPath);
var shellShimMaker = new ShellShimMaker(executablePackagePath.Value);
var commandName = toolConfigurationAndExecutablePath.Configuration.CommandName;
shellShimMaker.EnsureCommandNameUniqueness(commandName);
shellShimMaker.CreateShim(
toolConfigurationAndExecutablePath.Executable.Value,
commandName);
EnvironmentPathFactory
.CreateEnvironmentPathInstruction()
.PrintAddPathInstructionIfPathDoesNotExist();
Reporter.Output.WriteLine(
string.Format(LocalizableStrings.InstallationSucceeded, commandName));
return 0;
}
private static ToolConfigurationAndExecutablePath ObtainPackage(
DirectoryPath executablePackagePath,
DirectoryPath offlineFeedPath)
{
try
{
FilePath? configFile = null;
if (_configFilePath != null)
{
configFile = new FilePath(_configFilePath);
}
var toolPackageObtainer =
new ToolPackageObtainer(
_toolPackageObtainer = toolPackageObtainer ?? new ToolPackageObtainer(
executablePackagePath,
offlineFeedPath,
() => new DirectoryPath(Path.GetTempPath())
@ -95,7 +62,51 @@ namespace Microsoft.DotNet.Tools.Install.Tool
new PackageToProjectFileAdder(),
new ProjectRestorer());
return toolPackageObtainer.ObtainAndReturnExecutablePath(
_environmentPathInstruction = environmentPathInstruction
?? EnvironmentPathFactory
.CreateEnvironmentPathInstruction();
_shellShimMaker = shellShimMaker ?? new ShellShimMaker(executablePackagePath.Value);
_reporter = reporter ?? Reporter.Output;
}
public override int Execute()
{
if (!_global)
{
throw new GracefulException(LocalizableStrings.InstallToolCommandOnlySupportGlobal);
}
var toolConfigurationAndExecutablePath = ObtainPackage();
var commandName = toolConfigurationAndExecutablePath.Configuration.CommandName;
_shellShimMaker.EnsureCommandNameUniqueness(commandName);
_shellShimMaker.CreateShim(
toolConfigurationAndExecutablePath.Executable.Value,
commandName);
_environmentPathInstruction
.PrintAddPathInstructionIfPathDoesNotExist();
_reporter.WriteLine(
string.Format(LocalizableStrings.InstallationSucceeded, commandName));
return 0;
}
private ToolConfigurationAndExecutablePath ObtainPackage()
{
try
{
FilePath? configFile = null;
if (_configFilePath != null)
{
configFile = new FilePath(_configFilePath);
}
return _toolPackageObtainer.ObtainAndReturnExecutablePath(
packageId: _packageId,
packageVersion: _packageVersion,
nugetconfig: configFile,

View file

@ -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

View file

@ -9,6 +9,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.ComponentMocks\Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />

View file

@ -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<GracefulException>()
@ -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();

View file

@ -13,6 +13,7 @@
<ProjectReference Include="..\..\src\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.ComponentMocks\Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -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<string>(),
new PackageToProjectFileAdder(),
new ProjectRestorer());
Action a = () => packageObtainer.ObtainAndReturnExecutablePath(
packageId: TestPackageId,
@ -80,20 +67,53 @@ 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(
ToolConfigurationAndExecutablePath toolConfigurationAndExecutableDirectory =
packageObtainer.ObtainAndReturnExecutablePath(
packageId: TestPackageId,
packageVersion: TestPackageVersion,
nugetconfig: nugetConfigPath,
@ -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<string>(),
new PackageToProjectFileAdder(),
new ProjectRestorer());
}
ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath =
packageObtainer.ObtainAndReturnExecutablePath(
packageId: TestPackageId,
@ -156,19 +188,24 @@ 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(
ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync, nugetConfigPath.Value);
ToolConfigurationAndExecutablePath toolConfigurationAndExecutablePath =
packageObtainer.ObtainAndReturnExecutablePath(
packageId: TestPackageId,
packageVersion: TestPackageVersion,
nugetconfig: nugetConfigPath,
targetframework: _testTargetframework);
@ -177,16 +214,20 @@ namespace Microsoft.DotNet.ToolPackage.Tests
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<MockFeed>
{
new MockFeed
{
Type = MockFeedType.ExplicitNugetConfig,
Uri = nugetConfigPath.Value,
Packages = new List<MockFeedPackage>
{
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<string>(() => 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(
ConstructDefaultPackageObtainer(toolsPath, testMockBehaviorIsInSync);
var nonExistNugetConfigFile = new FilePath("NonExistent.file");
Action a = () =>
{
packageObtainer.ObtainAndReturnExecutablePath(
packageId: TestPackageId,
packageVersion: TestPackageVersion,
nugetconfig: new FilePath("NonExistent.file"),
nugetconfig: nonExistNugetConfigFile,
targetframework: _testTargetframework);
};
a.ShouldThrow<PackageObtainException>()
.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());
@ -264,6 +342,8 @@ namespace Microsoft.DotNet.ToolPackage.Tests
File.Exists(executable.Value)
.Should()
.BeTrue(executable + " should have the executable");
File.Delete(executable.Value);
}
private static readonly Func<FilePath> 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<MockFeed>
{
new MockFeed
{
Type = MockFeedType.ExplicitNugetConfig,
Uri = addNugetConfigFeedWithFilePath,
Packages = new List<MockFeedPackage>
{
new MockFeedPackage
{
PackageId = "global.tool.console.demo",
Version = "1.0.4"
}
}
}
});
}
if (addSourceFeedWithFilePath != null)
{
return new ToolPackageObtainerMock(additionalFeeds:
new List<MockFeed>
{
new MockFeed
{
Type = MockFeedType.ExplicitNugetConfig,
Uri = addSourceFeedWithFilePath,
Packages = new List<MockFeedPackage>
{
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"),

View file

@ -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;
}
}
}

View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>$(CliTargetFramework)</TargetFramework>
<RuntimeFrameworkVersion>$(MicrosoftNETCoreAppPackageVersion)</RuntimeFrameworkVersion>
<AssemblyName>Microsoft.DotNet.Tools.Tests.ComponentMocks</AssemblyName>
<AssemblyOriginatorKeyFile>../../tools/Key.snk</AssemblyOriginatorKeyFile>
<AssetTargetFallback>$(AssetTargetFallback);dotnet5.4;portable-net451+win8</AssetTargetFallback>
<SignAssembly>true</SignAssembly>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
</ItemGroup>
</Project>

View file

@ -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<MockFeedPackage> Packages;
}
}

View file

@ -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;
}
}

View file

@ -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
}
}

View file

@ -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")]

View file

@ -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; }
}
}
}

View file

@ -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<MockFeed> _mockFeeds;
public ToolPackageObtainerMock(
IFileSystem fileSystemWrapper = null,
bool useDefaultFeed = true,
IEnumerable<MockFeed> additionalFeeds = null,
Action beforeRunObtain = null)
{
_beforeRunObtain = beforeRunObtain ?? (() => { });
_fileSystem = fileSystemWrapper ?? new FileSystemWrapper();
_mockFeeds = new List<MockFeed>();
if (useDefaultFeed)
{
_mockFeeds.Add(new MockFeed
{
Type = MockFeedType.FeedFromLookUpNugetConfig,
Packages = new List<MockFeedPackage>
{
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<MockFeed>
{
feed
};
}
else
{
_mockFeeds = new List<MockFeed>();
}
}
}
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<MockFeed>
{
feed
};
}
else
{
_mockFeeds = new List<MockFeed>();
}
}
}
private static bool MatchPackageVersion(MockFeedPackage p, string packageId, string packageVersion)
{
if (packageVersion == null)
{
return p.PackageId == packageId;
}
return p.PackageId == packageId && p.Version == packageVersion;
}
}
}

View file

@ -5,3 +5,6 @@ using System.Runtime.CompilerServices;
[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")]

View file

@ -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<ShellShimMakerMock.FakeShim>(
_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<MockFeed>
{
new MockFeed
{
Type = MockFeedType.Source,
Uri = sourcePath,
Packages = new List<MockFeedPackage>
{
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<ShellShimMakerMock.FakeShim>(
_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<GracefulException>()
.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<GracefulException>()
.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<string> Message { get; set; } = new List<string>();
public void WriteLine(string message)
{
Message.Add(message);
}
public void WriteLine()
{
throw new NotImplementedException();
}
public void Write(string message)
{
throw new NotImplementedException();
}
}
}
}

View file

@ -71,6 +71,7 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.ComponentMocks\Microsoft.DotNet.Tools.Tests.ComponentMocks.csproj" />
<ProjectReference Include="..\..\src\dotnet\dotnet.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Sln.Internal\Microsoft.DotNet.Cli.Sln.Internal.csproj" />
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />