WIP Refactor and improve tests

This commit is contained in:
Justin Goshi 2016-12-16 01:04:09 -08:00
parent 20f2242947
commit 023a899db0
17 changed files with 425 additions and 470 deletions

View file

@ -64,7 +64,21 @@ namespace Microsoft.DotNet.Cli.CommandLine
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
{
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name };
return Command(command, configuration, throwOnUnexpectedArg);
}
public CommandLineApplication Command(CommandLineApplication command, bool throwOnUnexpectedArg = true)
{
return Command(command, _ => { }, throwOnUnexpectedArg);
}
public CommandLineApplication Command(
CommandLineApplication command,
Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
{
command.Parent = this;
Commands.Add(command);
configuration(command);
return command;

View file

@ -0,0 +1,16 @@
// 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.DotNet.Cli.CommandLine;
namespace Microsoft.DotNet.Cli
{
internal abstract class DotNetSubCommandBase : CommandLineApplication
{
internal DotNetSubCommandBase() : base(throwOnUnexpectedArg: false)
{
}
public abstract int Run(string fileOrDirectory);
}
}

View file

@ -3,10 +3,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Cli
{
@ -14,37 +16,62 @@ namespace Microsoft.DotNet.Cli
{
protected abstract string CommandName { get; }
protected abstract string FullCommandNameLocalized { get; }
internal abstract List<Func<CommandLineApplication, CommandLineApplication>> SubCommands { get; }
internal abstract List<Func<DotNetSubCommandBase>> SubCommands { get; }
public int RunCommand(string[] args)
{
DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: true)
CommandLineApplication command = new CommandLineApplication(throwOnUnexpectedArg: true)
{
Name = $"dotnet {CommandName}",
FullName = FullCommandNameLocalized,
};
app.HelpOption("-h|--help");
command.HelpOption("-h|--help");
app.Argument(
command.Argument(
Constants.ProjectOrSolutionArgumentName,
CommonLocalizableStrings.ArgumentsProjectOrSolutionDescription);
foreach (var subCommandCreator in SubCommands)
{
subCommandCreator(app);
var subCommand = subCommandCreator();
command.Command(subCommand);
subCommand.OnExecute(() => {
try
{
if (!command.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projectOrDirectory = command.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
return subCommand.Run(projectOrDirectory);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
subCommand.ShowHelp();
return 1;
}
});
}
try
{
return app.Execute(args);
return command.Execute(args);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
command.ShowHelp();
return 1;
}
catch (CommandParsingException e)

View file

@ -1,62 +0,0 @@
// 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.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools.Add
{
public abstract class AddSubCommandBase
{
protected abstract string CommandName { get; }
protected abstract string LocalizedDisplayName { get; }
protected abstract string LocalizedDescription { get; }
protected abstract string LocalizedHelpText { get; }
internal abstract void AddCustomOptions(CommandLineApplication app);
protected abstract IAddSubCommand CreateIAddSubCommand(string fileOrDirectory);
internal CommandLineApplication Create(CommandLineApplication parentApp)
{
CommandLineApplication app = parentApp.Command(CommandName, throwOnUnexpectedArg: false);
app.FullName = LocalizedDisplayName;
app.Description = LocalizedDescription;
app.HandleRemainingArguments = true;
app.ArgumentSeparatorHelpText = LocalizedHelpText;
app.HelpOption("-h|--help");
AddCustomOptions(app);
app.OnExecute(() => {
try
{
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
var addSubCommand = CreateIAddSubCommand(projectOrDirectory);
return addSubCommand.Add(app.RemainingArguments);
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
});
return app;
}
}
}

View file

@ -1,12 +0,0 @@
// 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.Add
{
public interface IAddSubCommand
{
int Add(List<string> items);
}
}

View file

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
using Microsoft.DotNet.Tools.Add.ProjectToSolution;
@ -14,11 +13,11 @@ namespace Microsoft.DotNet.Tools.Add
{
protected override string CommandName => "add";
protected override string FullCommandNameLocalized => LocalizableStrings.NetAddCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
internal override List<Func<DotNetSubCommandBase>> SubCommands =>
new List<Func<DotNetSubCommandBase>>
{
AddProjectToSolutionCommand.CreateApplication,
AddProjectToProjectReferenceCommand.CreateApplication,
AddProjectToSolutionCommand.Create,
AddProjectToProjectReferenceCommand.Create,
};
public static int Run(string[] args)

View file

@ -2,9 +2,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Add;
using Microsoft.DotNet.Tools.Common;
using NuGet.Frameworks;
using System.Collections.Generic;
@ -14,33 +14,48 @@ using System.Text;
namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
public class AddProjectToProjectReference : IAddSubCommand
internal class AddProjectToProjectReferenceCommand : DotNetSubCommandBase
{
private CommandOption _frameworkOption;
private MsbuildProject _msbuildProj;
private ProjectCollection _projects;
internal AddProjectToProjectReference(string fileOrDirectory, CommandOption frameworkOption)
public static DotNetSubCommandBase Create()
{
_projects = new ProjectCollection();
_msbuildProj = MsbuildProject.FromFileOrDirectory(_projects, fileOrDirectory);
_frameworkOption = frameworkOption;
var command = new AddProjectToProjectReferenceCommand()
{
Name = "p2p",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
HandleRemainingArguments = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText,
};
command.HelpOption("-h|--help");
command._frameworkOption = command.Option(
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
return command;
}
public int Add(List<string> references)
public override int Run(string fileOrDirectory)
{
if (references.Count == 0)
ProjectCollection projects = new ProjectCollection();
MsbuildProject msbuildProj = MsbuildProject.FromFileOrDirectory(projects, fileOrDirectory);
if (RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToAdd);
}
string frameworkString = _frameworkOption.Value();
PathUtility.EnsureAllPathsExist(references, CommonLocalizableStrings.ReferenceDoesNotExist);
IEnumerable<MsbuildProject> refs = references.Select((r) => MsbuildProject.FromFile(_projects, r));
PathUtility.EnsureAllPathsExist(RemainingArguments, CommonLocalizableStrings.ReferenceDoesNotExist);
IEnumerable<MsbuildProject> refs = RemainingArguments.Select((r) => MsbuildProject.FromFile(projects, r));
if (frameworkString == null)
{
foreach (var tfm in _msbuildProj.GetTargetFrameworks())
foreach (var tfm in msbuildProj.GetTargetFrameworks())
{
foreach (var @ref in refs)
{
@ -48,7 +63,7 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{
Reporter.Error.Write(GetProjectNotCompatibleWithFrameworksDisplayString(
@ref,
_msbuildProj.GetTargetFrameworks().Select((fx) => fx.GetShortFolderName())));
msbuildProj.GetTargetFrameworks().Select((fx) => fx.GetShortFolderName())));
return 1;
}
}
@ -57,11 +72,11 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
else
{
var framework = NuGetFramework.Parse(frameworkString);
if (!_msbuildProj.IsTargettingFramework(framework))
if (!msbuildProj.IsTargettingFramework(framework))
{
Reporter.Error.WriteLine(string.Format(
CommonLocalizableStrings.ProjectDoesNotTargetFramework,
_msbuildProj.ProjectRootElement.FullPath,
msbuildProj.ProjectRootElement.FullPath,
frameworkString));
return 1;
}
@ -78,16 +93,16 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
}
}
var relativePathReferences = references.Select((r) =>
PathUtility.GetRelativePath(_msbuildProj.ProjectDirectory, Path.GetFullPath(r))).ToList();
var relativePathReferences = RemainingArguments.Select((r) =>
PathUtility.GetRelativePath(msbuildProj.ProjectDirectory, Path.GetFullPath(r))).ToList();
int numberOfAddedReferences = _msbuildProj.AddProjectToProjectReferences(
int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
_frameworkOption.Value(),
relativePathReferences);
if (numberOfAddedReferences != 0)
{
_msbuildProj.ProjectRootElement.Save();
msbuildProj.ProjectRootElement.Save();
}
return 0;
@ -105,33 +120,4 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
return sb.ToString();
}
}
public class AddProjectToProjectReferenceCommand : AddSubCommandBase
{
private CommandOption _frameworkOption;
protected override string CommandName => "p2p";
protected override string LocalizedDisplayName => LocalizableStrings.AppFullName;
protected override string LocalizedDescription => LocalizableStrings.AppDescription;
protected override string LocalizedHelpText => LocalizableStrings.AppHelpText;
internal override void AddCustomOptions(CommandLineApplication app)
{
_frameworkOption = app.Option(
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
}
protected override IAddSubCommand CreateIAddSubCommand(string fileOrDirectory)
{
return new AddProjectToProjectReference(fileOrDirectory, _frameworkOption);
}
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
var addSubCommand = new AddProjectToProjectReferenceCommand();
return addSubCommand.Create(parentApp);
}
}
}

View file

@ -3,64 +3,73 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Tools.Add;
namespace Microsoft.DotNet.Tools.Add.ProjectToSolution
{
public class AddProjectToSolution : IAddSubCommand
internal class AddProjectToSolutionCommand : DotNetSubCommandBase
{
private SlnFile _slnFile;
public AddProjectToSolution(string fileOrDirectory)
public static DotNetSubCommandBase Create()
{
_slnFile = SlnFileFactory.CreateFromFileOrDirectory(fileOrDirectory);
var command = new AddProjectToSolutionCommand()
{
Name = "project",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
HandleRemainingArguments = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText,
};
command.HelpOption("-h|--help");
return command;
}
public int Add(List<string> projectPaths)
public override int Run(string fileOrDirectory)
{
if (projectPaths.Count == 0)
SlnFile slnFile = SlnFileFactory.CreateFromFileOrDirectory(fileOrDirectory);
if (RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd);
}
PathUtility.EnsureAllPathsExist(projectPaths, CommonLocalizableStrings.ProjectDoesNotExist);
var relativeProjectPaths = projectPaths.Select((p) =>
PathUtility.EnsureAllPathsExist(RemainingArguments, CommonLocalizableStrings.ProjectDoesNotExist);
var relativeProjectPaths = RemainingArguments.Select((p) =>
PathUtility.GetRelativePath(
PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory),
PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory),
Path.GetFullPath(p))).ToList();
int preAddProjectCount = _slnFile.Projects.Count;
int preAddProjectCount = slnFile.Projects.Count;
foreach (var project in relativeProjectPaths)
{
AddProject(project);
AddProject(slnFile, project);
}
if (_slnFile.Projects.Count > preAddProjectCount)
if (slnFile.Projects.Count > preAddProjectCount)
{
_slnFile.Write();
slnFile.Write();
}
return 0;
}
private void AddProject(string projectPath)
private void AddProject(SlnFile slnFile, string projectPath)
{
var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath);
if (_slnFile.Projects.Any((p) =>
if (slnFile.Projects.Any((p) =>
string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)))
{
Reporter.Output.WriteLine(string.Format(
CommonLocalizableStrings.SolutionAlreadyContainsProject,
_slnFile.FullPath,
slnFile.FullPath,
projectPath));
}
else
@ -94,33 +103,10 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToSolution
FilePath = projectPathNormalized
};
_slnFile.Projects.Add(slnProject);
slnFile.Projects.Add(slnProject);
Reporter.Output.WriteLine(
string.Format(CommonLocalizableStrings.ProjectAddedToTheSolution, projectPath));
}
}
}
public class AddProjectToSolutionCommand : AddSubCommandBase
{
protected override string CommandName => "project";
protected override string LocalizedDisplayName => LocalizableStrings.AppFullName;
protected override string LocalizedDescription => LocalizableStrings.AppDescription;
protected override string LocalizedHelpText => LocalizableStrings.AppHelpText;
internal override void AddCustomOptions(CommandLineApplication app)
{
}
protected override IAddSubCommand CreateIAddSubCommand(string fileOrDirectory)
{
return new AddProjectToSolution(fileOrDirectory);
}
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
var addSubCommand = new AddProjectToSolutionCommand();
return addSubCommand.Create(parentApp);
}
}
}

View file

@ -1,12 +0,0 @@
// 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.Remove
{
public interface IRemoveSubCommand
{
void Remove(IList<string> items);
}
}

View file

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Remove.ProjectFromSolution;
using Microsoft.DotNet.Tools.Remove.ProjectToProjectReference;
@ -14,11 +13,11 @@ namespace Microsoft.DotNet.Tools.Remove
{
protected override string CommandName => "remove";
protected override string FullCommandNameLocalized => LocalizableStrings.NetRemoveCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>>
internal override List<Func<DotNetSubCommandBase>> SubCommands =>
new List<Func<DotNetSubCommandBase>>
{
RemoveProjectFromSolutionCommand.CreateApplication,
RemoveProjectToProjectReferenceCommand.CreateApplication,
RemoveProjectFromSolutionCommand.Create,
RemoveProjectToProjectReferenceCommand.Create,
};
public static int Run(string[] args)

View file

@ -1,64 +0,0 @@
// 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.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools.Remove
{
public abstract class RemoveSubCommandBase
{
protected abstract string CommandName { get; }
protected abstract string LocalizedDisplayName { get; }
protected abstract string LocalizedDescription { get; }
protected abstract string LocalizedHelpText { get; }
internal abstract void AddCustomOptions(CommandLineApplication app);
protected abstract IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory);
internal CommandLineApplication Create(CommandLineApplication parentApp)
{
CommandLineApplication app = parentApp.Command(CommandName, throwOnUnexpectedArg: false);
app.FullName = LocalizedDisplayName;
app.Description = LocalizedDescription;
app.HandleRemainingArguments = true;
app.ArgumentSeparatorHelpText = LocalizedHelpText;
app.HelpOption("-h|--help");
AddCustomOptions(app);
app.OnExecute(() => {
try
{
if (!parentApp.Arguments.Any())
{
throw new GracefulException(CommonLocalizableStrings.RequiredArgumentNotPassed, Constants.ProjectOrSolutionArgumentName);
}
var projectOrDirectory = parentApp.Arguments.First().Value;
if (string.IsNullOrEmpty(projectOrDirectory))
{
projectOrDirectory = PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory());
}
var removeSubCommand = CreateIRemoveSubCommand(projectOrDirectory);
removeSubCommand.Remove(app.RemainingArguments);
return 0;
}
catch (GracefulException e)
{
Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp();
return 1;
}
});
return app;
}
}
}

View file

@ -2,68 +2,55 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using System.Collections.Generic;
using Microsoft.DotNet.Tools.Remove;
namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference
{
public class RemoveProjectToProjectReference : IRemoveSubCommand
internal class RemoveProjectToProjectReferenceCommand : DotNetSubCommandBase
{
private CommandOption _frameworkOption;
private MsbuildProject _msbuildProj;
internal RemoveProjectToProjectReference(string fileOrDirectory, CommandOption frameworkOption)
public static DotNetSubCommandBase Create()
{
_msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), fileOrDirectory);
_frameworkOption = frameworkOption;
var command = new RemoveProjectToProjectReferenceCommand()
{
Name = "p2p",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
HandleRemainingArguments = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText,
};
command.HelpOption("-h|--help");
command._frameworkOption = command.Option(
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
return command;
}
public void Remove(IList<string> references)
public override int Run(string fileOrDirectory)
{
if (references.Count == 0)
var msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), fileOrDirectory);
if (RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToRemove);
}
int numberOfRemovedReferences = _msbuildProj.RemoveProjectToProjectReferences(
int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences(
_frameworkOption.Value(),
references);
RemainingArguments);
if (numberOfRemovedReferences != 0)
{
_msbuildProj.ProjectRootElement.Save();
msbuildProj.ProjectRootElement.Save();
}
}
}
public class RemoveProjectToProjectReferenceCommand : RemoveSubCommandBase
{
private CommandOption _frameworkOption;
protected override string CommandName => "p2p";
protected override string LocalizedDisplayName => LocalizableStrings.AppFullName;
protected override string LocalizedDescription => LocalizableStrings.AppDescription;
protected override string LocalizedHelpText => LocalizableStrings.AppHelpText;
internal override void AddCustomOptions(CommandLineApplication app)
{
_frameworkOption = app.Option(
$"-f|--framework <{CommonLocalizableStrings.CmdFramework}>",
LocalizableStrings.CmdFrameworkDescription,
CommandOptionType.SingleValue);
}
protected override IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory)
{
return new RemoveProjectToProjectReference(fileOrDirectory, _frameworkOption);
}
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
var removeSubCommand = new RemoveProjectToProjectReferenceCommand();
return removeSubCommand.Create(parentApp);
return 0;
}
}
}

View file

@ -1,56 +1,67 @@
// 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.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Tools.Remove;
namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
{
public class RemoveProjectFromSolution : IRemoveSubCommand
internal class RemoveProjectFromSolutionCommand : DotNetSubCommandBase
{
private SlnFile _slnFile;
public RemoveProjectFromSolution(string fileOrDirectory)
public static DotNetSubCommandBase Create()
{
_slnFile = SlnFileFactory.CreateFromFileOrDirectory(fileOrDirectory);
var command = new RemoveProjectFromSolutionCommand()
{
Name = "project",
FullName = LocalizableStrings.AppFullName,
Description = LocalizableStrings.AppDescription,
HandleRemainingArguments = true,
ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText,
};
command.HelpOption("-h|--help");
return command;
}
public void Remove(IList<string> projectPaths)
public override int Run(string fileOrDirectory)
{
if (projectPaths.Count == 0)
SlnFile slnFile = SlnFileFactory.CreateFromFileOrDirectory(fileOrDirectory);
if (RemainingArguments.Count == 0)
{
throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToRemove);
}
var relativeProjectPaths = projectPaths.Select((p) =>
var relativeProjectPaths = RemainingArguments.Select((p) =>
PathUtility.GetRelativePath(
PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory),
PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory),
Path.GetFullPath(p))).ToList();
bool slnChanged = false;
foreach (var path in relativeProjectPaths)
{
slnChanged |= RemoveProject(path);
slnChanged |= RemoveProject(slnFile, path);
}
if (slnChanged)
{
_slnFile.Write();
slnFile.Write();
}
return 0;
}
private bool RemoveProject(string projectPath)
private bool RemoveProject(SlnFile slnFile, string projectPath)
{
var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath);
var projectsToRemove = _slnFile.Projects.Where((p) =>
var projectsToRemove = slnFile.Projects.Where((p) =>
string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)).ToList();
bool projectRemoved = false;
@ -64,7 +75,7 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
{
foreach (var slnProject in projectsToRemove)
{
_slnFile.Projects.Remove(slnProject);
slnFile.Projects.Remove(slnProject);
Reporter.Output.WriteLine(
string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, slnProject.FilePath));
}
@ -75,27 +86,4 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
return projectRemoved;
}
}
public class RemoveProjectFromSolutionCommand : RemoveSubCommandBase
{
protected override string CommandName => "project";
protected override string LocalizedDisplayName => LocalizableStrings.AppFullName;
protected override string LocalizedDescription => LocalizableStrings.AppDescription;
protected override string LocalizedHelpText => LocalizableStrings.AppHelpText;
internal override void AddCustomOptions(CommandLineApplication app)
{
}
protected override IRemoveSubCommand CreateIRemoveSubCommand(string fileOrDirectory)
{
return new RemoveProjectFromSolution(fileOrDirectory);
}
internal static CommandLineApplication CreateApplication(CommandLineApplication parentApp)
{
var removeSubCommand = new RemoveProjectFromSolutionCommand();
return removeSubCommand.Create(parentApp);
}
}
}

View file

@ -14,6 +14,21 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{
public class GivenDotnetAddP2P : TestBase
{
private const string HelpText = @".NET Add Project to Project (p2p) reference Command
Usage: dotnet add <PROJECT_OR_SOLUTION> p2p [options] [args]
Arguments:
<PROJECT_OR_SOLUTION> The project or solution to operation on. If a file is not specified, the current directory is searched.
Options:
-h|--help Show help information
-f|--framework <FRAMEWORK> Add reference only when targetting a specific framework
Args:
Project to project references to add
";
const string FrameworkNet451Arg = "-f net451";
const string ConditionFrameworkNet451 = "== 'net451'";
const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0";
@ -77,7 +92,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{
var cmd = new AddP2PCommand().Execute(helpArg);
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Usage");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -87,7 +102,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject("one two three")
.Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Unrecognized command or argument");
cmd.StdErr.Should().Be("Unrecognized command or argument 'two'");
cmd.StdOut.Should().Be("Specify --help for a list of available options and commands.");
}
[Theory]
@ -102,8 +118,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Could not find");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Could not find project or directory `{projName}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -117,8 +133,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain(" is invalid.");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be("Project `Broken/Broken.csproj` is invalid.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -126,12 +142,13 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{
var setup = Setup();
var workingDir = Path.Combine(setup.TestRoot, "MoreThanOne");
var cmd = new AddP2PCommand()
.WithWorkingDirectory(Path.Combine(setup.TestRoot, "MoreThanOne"))
.WithWorkingDirectory(workingDir)
.Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("more than one");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Found more than one project in `{workingDir + Path.DirectorySeparatorChar}`. Please specify which one to use.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -143,8 +160,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithWorkingDirectory(setup.TestRoot)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("not find any");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Could not find any project in `{setup.TestRoot + Path.DirectorySeparatorChar}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -152,14 +169,14 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{
var lib = NewLibWithFrameworks();
var setup = Setup();
int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new AddP2PCommand()
.WithWorkingDirectory(setup.TestRoot)
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -178,7 +195,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
@ -203,7 +220,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -227,7 +244,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -251,7 +268,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -275,7 +292,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -299,7 +316,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj`.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
@ -318,7 +335,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `..\\Lib\\Lib.csproj`.");
proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -340,7 +357,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj`.");
lib.CsProjContent().Should().BeEquivalentTo(csprojContentBefore);
}
@ -356,7 +373,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `..\\Lib\\Lib.csproj`.");
proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -372,7 +389,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName)
.Execute($"\"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `..\\Lib\\Lib.csproj`.");
proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -388,7 +405,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -406,7 +423,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already has a reference");
cmd.StdOut.Should().Be("Project already has a reference to `..\\Lib\\Lib.csproj`.");
proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -422,7 +439,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -440,7 +457,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -449,6 +466,9 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
[Fact]
public void ItAddsMultipleRefsNoCondToTheSameItemGroup()
{
const string OutputText = @"Reference `DotnetAddP2PProjects\Lib\Lib.csproj` added to the project.
Reference `DotnetAddP2PProjects\ValidRef\ValidRef.csproj` added to the project.";
var lib = NewLibWithFrameworks();
var setup = Setup();
@ -458,7 +478,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project").And.NotContain("already has a reference");
cmd.StdOut.Should().Be(OutputText);
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -468,6 +488,9 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
[Fact]
public void ItAddsMultipleRefsWithCondToTheSameItemGroup()
{
const string OutputText = @"Reference `DotnetAddP2PProjects\Lib\Lib.csproj` added to the project.
Reference `DotnetAddP2PProjects\ValidRef\ValidRef.csproj` added to the project.";
var lib = NewLibWithFrameworks();
var setup = Setup();
@ -477,7 +500,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project").And.NotContain("already has a reference");
cmd.StdOut.Should().Be(OutputText);
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -495,7 +518,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithWorkingDirectory(lib.Path)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -513,7 +536,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
int state = 0;
@ -558,7 +581,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName)
.Execute("\"IDoNotExist.csproj\"");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdErr.Should().Be("Reference IDoNotExist.csproj does not exist.");
lib.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -574,8 +597,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\" \"IDoNotExist.csproj\"");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdErr.Should().NotMatchRegex("(.*does not exist.*){2,}");
cmd.StdErr.Should().Be("Reference IDoNotExist.csproj does not exist.");
lib.CsProjContent().Should().BeEquivalentTo(contentBefore);
}
@ -591,7 +613,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath.Replace('\\', '/')}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -610,7 +632,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(setup.LibCsprojPath)
.Execute($"\"{setup.ValidRefCsprojRelPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\ValidRef\\ValidRef.csproj` added to the project.");
cmd.StdErr.Should().BeEmpty();
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -629,7 +651,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{net45lib.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\Net45Lib\\Net45Lib.csproj` added to the project.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(net45lib.CsProjName, ConditionFrameworkNet451).Should().Be(1);
@ -647,7 +669,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(net452netcoreapp10lib.CsProjPath)
.Execute($"\"{lib.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the project");
cmd.StdOut.Should().Be("Reference `..\\Lib\\Lib.csproj` added to the project.");
var csproj = net452netcoreapp10lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(lib.CsProjName).Should().Be(1);
@ -669,8 +691,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"-f {framework} \"{net45lib.CsProjPath}\"");
cmd.Should().Fail();
cmd.StdErr.Should().MatchRegex(ProjectDoesNotTargetFrameworkErrorMessageRegEx);
cmd.StdErr.Should().Contain($"`{framework}`");
cmd.StdErr.Should().Be($"Project `{setup.LibCsprojPath}` does not target framework `{framework}`.");
lib.CsProjContent().Should().BeEquivalentTo(csProjContent);
}

View file

@ -14,6 +14,20 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
{
public class GivenDotnetAddProj : TestBase
{
private string HelpText = @".NET Add Project to Solution Command
Usage: dotnet add <PROJECT_OR_SOLUTION> project [options] [args]
Arguments:
<PROJECT_OR_SOLUTION> The project or solution to operation on. If a file is not specified, the current directory is searched.
Options:
-h|--help Show help information
Args:
Projects to add to solution
";
[Theory]
[InlineData("--help")]
[InlineData("-h")]
@ -22,7 +36,17 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add project {helpArg}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Usage");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenTooManyArgumentsArePassedItPrintsError()
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput("add one.sln two.sln three.sln project");
cmd.Should().Fail();
cmd.StdErr.Should().Be("Unrecognized command or argument 'two.sln'");
cmd.StdOut.Should().Be("Specify --help for a list of available options and commands.");
}
[Theory]
@ -36,86 +60,103 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add {solutionName} project p.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Could not find");
cmd.StdOut.Should().Contain("Usage:");
cmd.StdErr.Should().Be($"Could not find solution or directory `{solutionName}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("InvalidSolution")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add InvalidSolution.sln project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution ");
cmd.StdOut.Should().Contain("Usage:");
cmd.StdErr.Should().Be("Invalid solution `InvalidSolution.sln`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("InvalidSolution")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "InvalidSolution.sln");
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution ");
cmd.StdOut.Should().Contain("Usage:");
cmd.StdErr.Should().Be($"Invalid solution `{solutionPath}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenNoProjectIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput(@"add App.sln project");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("You must specify at least one project to add.");
cmd.StdOut.Should().Contain("Usage:");
cmd.StdErr.Should().Be("You must specify at least one project to add.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App");
var cmd = new DotnetCommand()
.WithWorkingDirectory(Path.Combine(projectDirectory, "App"))
.WithWorkingDirectory(solutionPath)
.ExecuteWithCapturedOutput(@"add project App.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdOut.Should().Contain("Usage:");
cmd.StdErr.Should().Be($"Specified solution file {solutionPath + Path.DirectorySeparatorChar} does not exist, or there is no solution file in the directory.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithMultipleSlnFiles")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("TestAppWithMultipleSlnFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("more than one");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Found more than one solution file in {projectDirectory + Path.DirectorySeparatorChar}. Please specify which one to use.");
cmd.StdOut.Should().Be(HelpText);
}
[Theory]
@ -125,9 +166,12 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
string testAsset,
string projectGuid)
{
var projectDirectory = TestAssetsManager.CreateTestInstance(testAsset)
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get(testAsset)
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = "Lib/Lib.csproj";
var normalizedProjectPath = @"Lib\Lib.csproj";
@ -135,7 +179,7 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("added to the solution");
cmd.StdOut.Should().Be($"Project `{Path.Combine("Lib", "Lib.csproj")}` added to the solution.");
cmd.StdErr.Should().BeEmpty();
var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln"));
@ -165,25 +209,32 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
[Fact]
public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndExistingCsprojReferences")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndExistingCsprojReferences")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("already contains project");
cmd.StdOut.Should().Be($"Solution {solutionPath} already contains project {projectToAdd}.");
cmd.StdErr.Should().BeEmpty();
}
[Fact]
public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation()
{
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles")
.WithLockFiles()
.Path;
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var slnFullPath = Path.Combine(projectDirectory, "App.sln");
var contentBefore = File.ReadAllText(slnFullPath);
@ -193,8 +244,7 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd} idonotexist.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist");
cmd.StdErr.Should().NotMatchRegex("(.*does not exist.*){2,}");
cmd.StdErr.Should().Be("Project `idonotexist.csproj` does not exist.");
File.ReadAllText(slnFullPath)
.Should().BeEquivalentTo(contentBefore);

View file

@ -13,6 +13,21 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
{
public class GivenDotnetRemoveP2P : TestBase
{
private const string HelpText = @".NET Remove Project to Project (p2p) reference Command
Usage: dotnet remove <PROJECT_OR_SOLUTION> p2p [options] [args]
Arguments:
<PROJECT_OR_SOLUTION> The project or solution to operation on. If a file is not specified, the current directory is searched.
Options:
-h|--help Show help information
-f|--framework <FRAMEWORK> Remove reference only when targetting a specific framework
Args:
Project to project references to remove
";
const string FrameworkNet451Arg = "-f net451";
const string ConditionFrameworkNet451 = "== 'net451'";
const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0";
@ -103,7 +118,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
{
var cmd = new RemoveP2PCommand().Execute(helpArg);
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Usage");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -113,7 +128,8 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject("one two three")
.Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Unrecognized command or argument");
cmd.StdErr.Should().Be("Unrecognized command or argument 'two'");
cmd.StdOut.Should().Be("Specify --help for a list of available options and commands.");
}
[Theory]
@ -128,8 +144,8 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Could not find");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Could not find project or directory `{projName}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -143,8 +159,8 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain(" is invalid.");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be("Project `Broken/Broken.csproj` is invalid.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -152,12 +168,13 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
{
var setup = Setup();
var workingDir = Path.Combine(setup.TestRoot, "MoreThanOne");
var cmd = new RemoveP2PCommand()
.WithWorkingDirectory(Path.Combine(setup.TestRoot, "MoreThanOne"))
.WithWorkingDirectory(workingDir)
.Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("more than one");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Found more than one project in `{workingDir + Path.DirectorySeparatorChar}`. Please specify which one to use.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -169,8 +186,8 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithWorkingDirectory(setup.TestRoot)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("not find any");
cmd.StdOut.Should().Contain("Usage");
cmd.StdErr.Should().Be($"Could not find any project in `{setup.TestRoot + Path.DirectorySeparatorChar}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -186,7 +203,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -205,7 +222,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(libref.Name, ConditionFrameworkNet451).Should().Be(0);
@ -225,8 +242,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().NotContain(validref.Name);
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -245,7 +261,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("could not be found");
cmd.StdOut.Should().Be($"Project reference `{libref.CsProjPath}` could not be found.");
lib.CsProjContent().Should().BeEquivalentTo(csprojContetntBefore);
}
@ -262,7 +278,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("could not be found");
cmd.StdOut.Should().Be($"Project reference `{libref.CsProjPath}` could not be found.");
lib.CsProjContent().Should().BeEquivalentTo(csprojContetntBefore);
}
@ -282,7 +298,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{librefNoCond.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(librefNoCond.Name).Should().Be(0);
@ -307,7 +323,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{librefCond.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(librefNoCond.Name).Should().Be(1);
@ -332,7 +348,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{librefCondNet451.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condNet451Before - 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(librefCondNet451.Name, ConditionFrameworkNet451).Should().Be(0);
@ -344,6 +360,9 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
[Fact]
public void WhenDuplicateReferencesArePresentItRemovesThemAll()
{
const string RemovedText = @"Project reference `..\Lib\Lib.csproj` removed.
Project reference `..\Lib\Lib.csproj` removed.";
var setup = Setup();
var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithDoubledRef"));
var libref = GetLibRef(setup);
@ -354,7 +373,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(proj.CsProjPath)
.Execute($"\"{libref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(RemovedText);
var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
@ -374,7 +393,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `..\ValidRef\ValidRef.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -393,7 +412,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `..\ValidRef\ValidRef.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -412,7 +431,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(@"Project reference `..\ValidRef\ValidRef.csproj` removed.");
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -421,6 +440,9 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
[Fact]
public void WhenPassingMultipleReferencesItRemovesThemAll()
{
const string OutputText = @"Project reference `DotnetAddP2PProjects\Lib\Lib.csproj` removed.
Project reference `DotnetAddP2PProjects\ValidRef\ValidRef.csproj` removed.";
var lib = NewLibWithFrameworks();
var setup = Setup();
var libref = AddLibRef(setup, lib);
@ -432,7 +454,7 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
.WithProject(lib.CsProjPath)
.Execute($"\"{libref.CsProjPath}\" \"{validref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Be(OutputText);
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(libref.Name).Should().Be(0);
@ -447,14 +469,16 @@ namespace Microsoft.DotNet.Cli.Remove.P2P.Tests
var libref = GetLibRef(setup);
var validref = AddValidRef(setup, lib);
string OutputText = $@"Project reference `{setup.LibCsprojPath}` could not be found.
Project reference `DotnetAddP2PProjects\ValidRef\ValidRef.csproj` removed.";
int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new RemoveP2PCommand()
.WithWorkingDirectory(setup.TestRoot)
.WithProject(lib.CsProjPath)
.Execute($"\"{libref.CsProjPath}\" \"{validref.CsProjPath}\"");
cmd.Should().Pass();
cmd.StdOut.Should().MatchRegex("(^|[\r\n])Project reference[^\r\n]*removed.($|[\r\n])");
cmd.StdOut.Should().Contain("could not be found");
cmd.StdOut.Should().Be(OutputText);
var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore - 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(validref.Name).Should().Be(0);

View file

@ -34,7 +34,7 @@ Args:
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"remove project {helpArg}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain(HelpText);
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -43,8 +43,8 @@ Args:
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput("remove one.sln two.sln three.sln project");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Unrecognized command or argument 'two.sln'");
cmd.StdOut.Should().Contain("Specify --help for a list of available options and commands.") ;
cmd.StdErr.Should().Be("Unrecognized command or argument 'two.sln'");
cmd.StdOut.Should().Be("Specify --help for a list of available options and commands.");
}
[Theory]
@ -58,8 +58,8 @@ Args:
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"remove {solutionName} project p.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain($"Could not find solution or directory `{solutionName}`.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be($"Could not find solution or directory `{solutionName}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -77,8 +77,8 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove InvalidSolution.sln project {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution `InvalidSolution.sln`.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be("Invalid solution `InvalidSolution.sln`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -97,8 +97,8 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove project {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain($"Invalid solution `{solutionPath}`.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be($"Invalid solution `{solutionPath}`.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -115,8 +115,8 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput(@"remove App.sln project");
cmd.Should().Fail();
cmd.StdErr.Should().Contain("You must specify at least one project to remove.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be("You must specify at least one project to remove.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -134,8 +134,8 @@ Args:
.WithWorkingDirectory(solutionPath)
.ExecuteWithCapturedOutput(@"remove project App.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Contain($"Specified solution file {solutionPath + Path.DirectorySeparatorChar} does not exist, or there is no solution file in the directory.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be($"Specified solution file {solutionPath + Path.DirectorySeparatorChar} does not exist, or there is no solution file in the directory.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -153,8 +153,8 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove project {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Contain($"Found more than one solution file in {projectDirectory + Path.DirectorySeparatorChar}. Please specify which one to use.");
cmd.StdOut.Should().Contain(HelpText);
cmd.StdErr.Should().Be($"Found more than one solution file in {projectDirectory + Path.DirectorySeparatorChar}. Please specify which one to use.");
cmd.StdOut.Should().Be(HelpText);
}
[Fact]
@ -173,7 +173,7 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput("remove project referenceDoesNotExistInSln.csproj");
cmd.Should().Pass();
cmd.StdOut.Should().Contain("Project reference `referenceDoesNotExistInSln.csproj` could not be found.");
cmd.StdOut.Should().Be("Project reference `referenceDoesNotExistInSln.csproj` could not be found.");
File.ReadAllText(solutionPath)
.Should().Be(contentBefore);
}
@ -197,7 +197,7 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove project {projectToRemove}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain($"Project reference `{projectToRemove}` removed.");
cmd.StdOut.Should().Be($"Project reference `{projectToRemove}` removed.");
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);
@ -223,7 +223,10 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove project {projectToRemove}");
cmd.Should().Pass();
cmd.StdOut.Should().Contain($"Project reference `{projectToRemove}` removed.");
string outputText = $@"Project reference `{projectToRemove}` removed.
Project reference `{projectToRemove}` removed.";
cmd.StdOut.Should().Be(outputText);
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);
@ -249,7 +252,11 @@ Args:
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"remove project idontexist.csproj {projectToRemove} idontexisteither.csproj");
cmd.Should().Pass();
cmd.StdOut.Should().Contain($"Project reference `{projectToRemove}` removed.");
string outputText = $@"Project reference `idontexist.csproj` could not be found.
Project reference `{projectToRemove}` removed.
Project reference `idontexisteither.csproj` could not be found.";
cmd.StdOut.Should().Be(outputText);
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);