2018-03-02 14:35:23 -08:00
// 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 ;
2018-03-21 19:12:32 -07:00
using Microsoft.DotNet.Tools.Tool.List ;
2018-03-02 14:35:23 -08:00
using Microsoft.DotNet.Tools.Test.Utilities ;
using Microsoft.Extensions.DependencyModel.Tests ;
using Microsoft.Extensions.EnvironmentAbstractions ;
using Moq ;
using NuGet.Versioning ;
using Xunit ;
using Parser = Microsoft . DotNet . Cli . Parser ;
2018-03-21 19:12:32 -07:00
using LocalizableStrings = Microsoft . DotNet . Tools . Tool . List . LocalizableStrings ;
2018-03-02 14:35:23 -08:00
namespace Microsoft.DotNet.Tests.Commands
{
2018-03-21 19:12:32 -07:00
public class ToolListCommandTests
2018-03-02 14:35:23 -08:00
{
private readonly BufferedReporter _reporter ;
2018-03-21 19:12:32 -07:00
public ToolListCommandTests ( )
2018-03-02 14:35:23 -08:00
{
_reporter = new BufferedReporter ( ) ;
}
[Fact]
2018-03-16 14:56:24 -07:00
public void GivenAMissingGlobalOrToolPathOptionItErrors ( )
2018-03-02 14:35:23 -08:00
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
var command = CreateCommand ( store . Object ) ;
Action a = ( ) = > {
command . Execute ( ) ;
} ;
a . ShouldThrow < GracefulException > ( )
. And
. Message
. Should ( )
2018-03-16 14:56:24 -07:00
. Be ( LocalizableStrings . NeedGlobalOrToolPath ) ;
}
[Fact]
public void GivenBothGlobalAndToolPathOptionsItErrors ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
var command = CreateCommand ( store . Object , "-g --tool-path /tools" , "/tools" ) ;
Action a = ( ) = > {
command . Execute ( ) ;
} ;
a . ShouldThrow < GracefulException > ( )
. And
. Message
. Should ( )
. Be ( LocalizableStrings . GlobalAndToolPathConflict ) ;
2018-03-02 14:35:23 -08:00
}
[Fact]
public void GivenNoInstalledPackagesItPrintsEmptyTable ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new IToolPackage [ 0 ] ) ;
var command = CreateCommand ( store . Object , "-g" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
2018-03-15 14:40:10 -07:00
_reporter . Lines . Should ( ) . Equal ( EnumerateExpectedTableLines ( store . Object ) ) ;
2018-03-02 14:35:23 -08:00
}
2018-03-16 14:56:24 -07:00
[Fact]
public void GivenAToolPathItPassesToolPathToStoreFactory ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new IToolPackage [ 0 ] ) ;
var command = CreateCommand ( store . Object , "--tool-path /tools" , "/tools" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
_reporter . Lines . Should ( ) . Equal ( EnumerateExpectedTableLines ( store . Object ) ) ;
}
2018-03-02 14:35:23 -08:00
[Fact]
public void GivenASingleInstalledPackageItPrintsThePackage ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new [ ] {
CreateMockToolPackage (
"test.tool" ,
"1.3.5-preview" ,
new [ ] {
new CommandSettings ( "foo" , "dotnet" , new FilePath ( "tool" ) )
}
)
} ) ;
var command = CreateCommand ( store . Object , "-g" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
2018-03-15 14:40:10 -07:00
_reporter . Lines . Should ( ) . Equal ( EnumerateExpectedTableLines ( store . Object ) ) ;
2018-03-02 14:35:23 -08:00
}
[Fact]
public void GivenMultipleInstalledPackagesItPrintsThePackages ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new [ ] {
CreateMockToolPackage (
"test.tool" ,
"1.3.5-preview" ,
new [ ] {
new CommandSettings ( "foo" , "dotnet" , new FilePath ( "tool" ) )
}
) ,
CreateMockToolPackage (
"another.tool" ,
"2.7.3" ,
new [ ] {
new CommandSettings ( "bar" , "dotnet" , new FilePath ( "tool" ) )
}
) ,
CreateMockToolPackage (
"some.tool" ,
"1.0.0" ,
new [ ] {
new CommandSettings ( "fancy-foo" , "dotnet" , new FilePath ( "tool" ) )
}
)
} ) ;
var command = CreateCommand ( store . Object , "-g" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
2018-03-15 14:40:10 -07:00
_reporter . Lines . Should ( ) . Equal ( EnumerateExpectedTableLines ( store . Object ) ) ;
2018-03-02 14:35:23 -08:00
}
[Fact]
public void GivenAPackageWithMultipleCommandsItListsThem ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new [ ] {
CreateMockToolPackage (
"test.tool" ,
"1.3.5-preview" ,
new [ ] {
new CommandSettings ( "foo" , "dotnet" , new FilePath ( "tool" ) ) ,
new CommandSettings ( "bar" , "dotnet" , new FilePath ( "tool" ) ) ,
new CommandSettings ( "baz" , "dotnet" , new FilePath ( "tool" ) )
}
)
} ) ;
var command = CreateCommand ( store . Object , "-g" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
2018-03-15 14:40:10 -07:00
_reporter . Lines . Should ( ) . Equal ( EnumerateExpectedTableLines ( store . Object ) ) ;
2018-03-02 14:35:23 -08:00
}
[Fact]
public void GivenABrokenPackageItPrintsWarning ( )
{
var store = new Mock < IToolPackageStore > ( MockBehavior . Strict ) ;
store
. Setup ( s = > s . EnumeratePackages ( ) )
. Returns ( new [ ] {
CreateMockToolPackage (
"test.tool" ,
"1.3.5-preview" ,
new [ ] {
new CommandSettings ( "foo" , "dotnet" , new FilePath ( "tool" ) )
}
) ,
CreateMockBrokenPackage ( "another.tool" , "2.7.3" ) ,
CreateMockToolPackage (
"some.tool" ,
"1.0.0" ,
new [ ] {
new CommandSettings ( "fancy-foo" , "dotnet" , new FilePath ( "tool" ) )
}
)
} ) ;
var command = CreateCommand ( store . Object , "-g" ) ;
command . Execute ( ) . Should ( ) . Be ( 0 ) ;
_reporter . Lines . Should ( ) . Equal (
2018-03-15 14:40:10 -07:00
EnumerateExpectedTableLines ( store . Object ) . Prepend (
string . Format (
LocalizableStrings . InvalidPackageWarning ,
"another.tool" ,
"broken" ) . Yellow ( ) ) ) ;
2018-03-02 14:35:23 -08:00
}
private IToolPackage CreateMockToolPackage ( string id , string version , IReadOnlyList < CommandSettings > commands )
{
var package = new Mock < IToolPackage > ( MockBehavior . Strict ) ;
package . SetupGet ( p = > p . Id ) . Returns ( new PackageId ( id ) ) ;
package . SetupGet ( p = > p . Version ) . Returns ( NuGetVersion . Parse ( version ) ) ;
package . SetupGet ( p = > p . Commands ) . Returns ( commands ) ;
return package . Object ;
}
private IToolPackage CreateMockBrokenPackage ( string id , string version )
{
var package = new Mock < IToolPackage > ( MockBehavior . Strict ) ;
package . SetupGet ( p = > p . Id ) . Returns ( new PackageId ( id ) ) ;
package . SetupGet ( p = > p . Version ) . Returns ( NuGetVersion . Parse ( version ) ) ;
package . SetupGet ( p = > p . Commands ) . Throws ( new ToolConfigurationException ( "broken" ) ) ;
return package . Object ;
}
2018-03-16 14:56:24 -07:00
private ListToolCommand CreateCommand ( IToolPackageStore store , string options = "" , string expectedToolPath = null )
2018-03-02 14:35:23 -08:00
{
2018-03-21 19:12:32 -07:00
ParseResult result = Parser . Instance . Parse ( "dotnet tool list " + options ) ;
2018-03-02 14:35:23 -08:00
return new ListToolCommand (
2018-03-21 19:12:32 -07:00
result [ "dotnet" ] [ "tool" ] [ "list" ] ,
2018-03-02 14:35:23 -08:00
result ,
2018-03-16 14:56:24 -07:00
toolPath = > { AssertExpectedToolPath ( toolPath , expectedToolPath ) ; return store ; } ,
2018-03-02 14:35:23 -08:00
_reporter ) ;
}
2018-03-15 14:40:10 -07:00
2018-03-16 14:56:24 -07:00
private void AssertExpectedToolPath ( DirectoryPath ? toolPath , string expectedToolPath )
{
if ( expectedToolPath ! = null )
{
toolPath . Should ( ) . NotBeNull ( ) ;
toolPath . Value . Value . Should ( ) . Be ( expectedToolPath ) ;
}
else
{
toolPath . Should ( ) . BeNull ( ) ;
}
}
2018-03-15 14:40:10 -07:00
private IEnumerable < string > EnumerateExpectedTableLines ( IToolPackageStore store )
{
string GetCommandsString ( IToolPackage package )
{
return string . Join ( ListToolCommand . CommandDelimiter , package . Commands . Select ( c = > c . Name ) ) ;
}
var packages = store . EnumeratePackages ( ) . Where ( PackageHasCommands ) . OrderBy ( package = > package . Id ) ;
var columnDelimiter = PrintableTable < IToolPackageStore > . ColumnDelimiter ;
int packageIdColumnWidth = LocalizableStrings . PackageIdColumn . Length ;
int versionColumnWidth = LocalizableStrings . VersionColumn . Length ;
int commandsColumnWidth = LocalizableStrings . CommandsColumn . Length ;
foreach ( var package in packages )
{
packageIdColumnWidth = Math . Max ( packageIdColumnWidth , package . Id . ToString ( ) . Length ) ;
versionColumnWidth = Math . Max ( versionColumnWidth , package . Version . ToNormalizedString ( ) . Length ) ;
commandsColumnWidth = Math . Max ( commandsColumnWidth , GetCommandsString ( package ) . Length ) ;
}
yield return string . Format (
"{0}{1}{2}{3}{4}" ,
LocalizableStrings . PackageIdColumn . PadRight ( packageIdColumnWidth ) ,
columnDelimiter ,
LocalizableStrings . VersionColumn . PadRight ( versionColumnWidth ) ,
columnDelimiter ,
LocalizableStrings . CommandsColumn . PadRight ( commandsColumnWidth ) ) ;
yield return new string (
'-' ,
packageIdColumnWidth + versionColumnWidth + commandsColumnWidth + ( columnDelimiter . Length * 2 ) ) ;
foreach ( var package in packages )
{
yield return string . Format (
"{0}{1}{2}{3}{4}" ,
package . Id . ToString ( ) . PadRight ( packageIdColumnWidth ) ,
columnDelimiter ,
package . Version . ToNormalizedString ( ) . PadRight ( versionColumnWidth ) ,
columnDelimiter ,
GetCommandsString ( package ) . PadRight ( commandsColumnWidth ) ) ;
}
}
private static bool PackageHasCommands ( IToolPackage package )
{
try
{
return package . Commands . Count > = 0 ;
}
catch ( Exception ex ) when ( ex is ToolConfigurationException )
{
return false ;
}
}
2018-03-02 14:35:23 -08:00
}
}