// 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 FluentAssertions; using Microsoft.DotNet.Cli.Sln.Internal; using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Test.Utilities; using System; using System.IO; using System.Linq; using Xunit; using CommandLocalizableStrings = Microsoft.DotNet.Tools.Sln.LocalizableStrings; namespace Microsoft.DotNet.Cli.Sln.List.Tests { public class GivenDotnetSlnList : TestBase { private const string HelpText = @"Usage: dotnet sln list [options] Arguments: The solution file to operate on. If not specified, the command will search the current directory for one. Options: -h, --help Show command line help."; private const string SlnCommandHelpText = @"Usage: dotnet sln [options] [command] Arguments: The solution file to operate on. If not specified, the command will search the current directory for one. Options: -h, --help Show command line help. Commands: add Add one or more projects to a solution file. list List all projects in a solution file. remove Remove one or more projects from a solution file."; [Theory] [InlineData("--help")] [InlineData("-h")] public void WhenHelpOptionIsPassedItPrintsUsage(string helpArg) { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput($"sln list {helpArg}"); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Theory] [InlineData("")] [InlineData("unknownCommandName")] public void WhenNoCommandIsPassedItPrintsError(string commandName) { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput($"sln {commandName}"); cmd.Should().Fail(); cmd.StdErr.Should().Be(CommonLocalizableStrings.RequiredCommandNotPassed); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(SlnCommandHelpText); } [Fact] public void WhenTooManyArgumentsArePassedItPrintsError() { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput("sln one.sln two.sln three.sln list"); cmd.Should().Fail(); cmd.StdErr.Should().BeVisuallyEquivalentTo($@"{string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "two.sln")} {string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "three.sln")}"); } [Theory] [InlineData("idontexist.sln")] [InlineData("ihave?invalidcharacters.sln")] [InlineData("ihaveinv@lidcharacters.sln")] [InlineData("ihaveinvalid/characters")] [InlineData("ihaveinvalidchar\\acters")] public void WhenNonExistingSolutionIsPassedItPrintsErrorAndUsage(string solutionName) { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput($"sln {solutionName} list"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindSolutionOrDirectory, solutionName)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage() { var projectDirectory = TestAssets .Get("InvalidSolution") .CreateInstance() .WithSourceFiles() .Root .FullName; var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln InvalidSolution.sln list"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, "InvalidSolution.sln", LocalizableStrings.FileHeaderMissingError)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage() { var projectDirectory = TestAssets .Get("InvalidSolution") .CreateInstance() .WithSourceFiles() .Root .FullName; var solutionFullPath = Path.Combine(projectDirectory, "InvalidSolution.sln"); var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln list"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, solutionFullPath, LocalizableStrings.FileHeaderMissingError)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage() { var projectDirectory = TestAssets .Get("TestAppWithSlnAndCsprojFiles") .CreateInstance() .WithSourceFiles() .Root .FullName; var solutionDir = Path.Combine(projectDirectory, "App"); var cmd = new DotnetCommand() .WithWorkingDirectory(solutionDir) .ExecuteWithCapturedOutput("sln list"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.SolutionDoesNotExist, solutionDir + Path.DirectorySeparatorChar)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage() { var projectDirectory = TestAssets .Get("TestAppWithMultipleSlnFiles") .CreateInstance() .WithSourceFiles() .Root .FullName; var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln list"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneSolutionInDirectory, projectDirectory + Path.DirectorySeparatorChar)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenNoProjectsArePresentInTheSolutionItPrintsANoProjectMessage() { var projectDirectory = TestAssets .Get("TestAppWithEmptySln") .CreateInstance() .WithSourceFiles() .Root .FullName; var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln list"); cmd.Should().Pass(); cmd.StdOut.Should().Be(CommonLocalizableStrings.NoProjectsFound); } [Fact] public void WhenProjectsPresentInTheSolutionItListsThem() { var expectedOutput = $@"{CommandLocalizableStrings.ProjectsHeader} {new string('-', CommandLocalizableStrings.ProjectsHeader.Length)} {Path.Combine("App", "App.csproj")} {Path.Combine("Lib", "Lib.csproj")}"; var projectDirectory = TestAssets .Get("TestAppWithSlnAndExistingCsprojReferences") .CreateInstance() .WithSourceFiles() .Root .FullName; var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput("sln list"); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentTo(expectedOutput); } } }