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, public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true) 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); Commands.Add(command);
configuration(command); configuration(command);
return 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference; using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Cli namespace Microsoft.DotNet.Cli
{ {
@ -14,37 +16,62 @@ namespace Microsoft.DotNet.Cli
{ {
protected abstract string CommandName { get; } protected abstract string CommandName { get; }
protected abstract string FullCommandNameLocalized { 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) public int RunCommand(string[] args)
{ {
DebugHelper.HandleDebugSwitch(ref args); DebugHelper.HandleDebugSwitch(ref args);
CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: true) CommandLineApplication command = new CommandLineApplication(throwOnUnexpectedArg: true)
{ {
Name = $"dotnet {CommandName}", Name = $"dotnet {CommandName}",
FullName = FullCommandNameLocalized, FullName = FullCommandNameLocalized,
}; };
app.HelpOption("-h|--help"); command.HelpOption("-h|--help");
app.Argument( command.Argument(
Constants.ProjectOrSolutionArgumentName, Constants.ProjectOrSolutionArgumentName,
CommonLocalizableStrings.ArgumentsProjectOrSolutionDescription); CommonLocalizableStrings.ArgumentsProjectOrSolutionDescription);
foreach (var subCommandCreator in SubCommands) 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 try
{ {
return app.Execute(args); return command.Execute(args);
} }
catch (GracefulException e) catch (GracefulException e)
{ {
Reporter.Error.WriteLine(e.Message.Red()); Reporter.Error.WriteLine(e.Message.Red());
app.ShowHelp(); command.ShowHelp();
return 1; return 1;
} }
catch (CommandParsingException e) 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;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Add.ProjectToProjectReference; using Microsoft.DotNet.Tools.Add.ProjectToProjectReference;
using Microsoft.DotNet.Tools.Add.ProjectToSolution; using Microsoft.DotNet.Tools.Add.ProjectToSolution;
@ -14,11 +13,11 @@ namespace Microsoft.DotNet.Tools.Add
{ {
protected override string CommandName => "add"; protected override string CommandName => "add";
protected override string FullCommandNameLocalized => LocalizableStrings.NetAddCommand; protected override string FullCommandNameLocalized => LocalizableStrings.NetAddCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands => internal override List<Func<DotNetSubCommandBase>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>> new List<Func<DotNetSubCommandBase>>
{ {
AddProjectToSolutionCommand.CreateApplication, AddProjectToSolutionCommand.Create,
AddProjectToProjectReferenceCommand.CreateApplication, AddProjectToProjectReferenceCommand.Create,
}; };
public static int Run(string[] args) 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. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Build.Evaluation; using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Add;
using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.Common;
using NuGet.Frameworks; using NuGet.Frameworks;
using System.Collections.Generic; using System.Collections.Generic;
@ -14,33 +14,48 @@ using System.Text;
namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{ {
public class AddProjectToProjectReference : IAddSubCommand internal class AddProjectToProjectReferenceCommand : DotNetSubCommandBase
{ {
private CommandOption _frameworkOption; private CommandOption _frameworkOption;
private MsbuildProject _msbuildProj;
private ProjectCollection _projects;
internal AddProjectToProjectReference(string fileOrDirectory, CommandOption frameworkOption) public static DotNetSubCommandBase Create()
{ {
_projects = new ProjectCollection(); var command = new AddProjectToProjectReferenceCommand()
_msbuildProj = MsbuildProject.FromFileOrDirectory(_projects, fileOrDirectory); {
_frameworkOption = frameworkOption; 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); throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToAdd);
} }
string frameworkString = _frameworkOption.Value(); string frameworkString = _frameworkOption.Value();
PathUtility.EnsureAllPathsExist(references, CommonLocalizableStrings.ReferenceDoesNotExist); PathUtility.EnsureAllPathsExist(RemainingArguments, CommonLocalizableStrings.ReferenceDoesNotExist);
IEnumerable<MsbuildProject> refs = references.Select((r) => MsbuildProject.FromFile(_projects, r)); IEnumerable<MsbuildProject> refs = RemainingArguments.Select((r) => MsbuildProject.FromFile(projects, r));
if (frameworkString == null) if (frameworkString == null)
{ {
foreach (var tfm in _msbuildProj.GetTargetFrameworks()) foreach (var tfm in msbuildProj.GetTargetFrameworks())
{ {
foreach (var @ref in refs) foreach (var @ref in refs)
{ {
@ -48,7 +63,7 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
{ {
Reporter.Error.Write(GetProjectNotCompatibleWithFrameworksDisplayString( Reporter.Error.Write(GetProjectNotCompatibleWithFrameworksDisplayString(
@ref, @ref,
_msbuildProj.GetTargetFrameworks().Select((fx) => fx.GetShortFolderName()))); msbuildProj.GetTargetFrameworks().Select((fx) => fx.GetShortFolderName())));
return 1; return 1;
} }
} }
@ -57,11 +72,11 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
else else
{ {
var framework = NuGetFramework.Parse(frameworkString); var framework = NuGetFramework.Parse(frameworkString);
if (!_msbuildProj.IsTargettingFramework(framework)) if (!msbuildProj.IsTargettingFramework(framework))
{ {
Reporter.Error.WriteLine(string.Format( Reporter.Error.WriteLine(string.Format(
CommonLocalizableStrings.ProjectDoesNotTargetFramework, CommonLocalizableStrings.ProjectDoesNotTargetFramework,
_msbuildProj.ProjectRootElement.FullPath, msbuildProj.ProjectRootElement.FullPath,
frameworkString)); frameworkString));
return 1; return 1;
} }
@ -78,16 +93,16 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
} }
} }
var relativePathReferences = references.Select((r) => var relativePathReferences = RemainingArguments.Select((r) =>
PathUtility.GetRelativePath(_msbuildProj.ProjectDirectory, Path.GetFullPath(r))).ToList(); PathUtility.GetRelativePath(msbuildProj.ProjectDirectory, Path.GetFullPath(r))).ToList();
int numberOfAddedReferences = _msbuildProj.AddProjectToProjectReferences( int numberOfAddedReferences = msbuildProj.AddProjectToProjectReferences(
_frameworkOption.Value(), _frameworkOption.Value(),
relativePathReferences); relativePathReferences);
if (numberOfAddedReferences != 0) if (numberOfAddedReferences != 0)
{ {
_msbuildProj.ProjectRootElement.Save(); msbuildProj.ProjectRootElement.Save();
} }
return 0; return 0;
@ -105,33 +120,4 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToProjectReference
return sb.ToString(); 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.Construction;
using Microsoft.Build.Evaluation; using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Sln.Internal; using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.Common;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.Tools.Add;
namespace Microsoft.DotNet.Tools.Add.ProjectToSolution namespace Microsoft.DotNet.Tools.Add.ProjectToSolution
{ {
public class AddProjectToSolution : IAddSubCommand internal class AddProjectToSolutionCommand : DotNetSubCommandBase
{ {
private SlnFile _slnFile; public static DotNetSubCommandBase Create()
public AddProjectToSolution(string fileOrDirectory)
{ {
_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); throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd);
} }
PathUtility.EnsureAllPathsExist(projectPaths, CommonLocalizableStrings.ProjectDoesNotExist); PathUtility.EnsureAllPathsExist(RemainingArguments, CommonLocalizableStrings.ProjectDoesNotExist);
var relativeProjectPaths = projectPaths.Select((p) => var relativeProjectPaths = RemainingArguments.Select((p) =>
PathUtility.GetRelativePath( PathUtility.GetRelativePath(
PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory), PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory),
Path.GetFullPath(p))).ToList(); Path.GetFullPath(p))).ToList();
int preAddProjectCount = _slnFile.Projects.Count; int preAddProjectCount = slnFile.Projects.Count;
foreach (var project in relativeProjectPaths) 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; return 0;
} }
private void AddProject(string projectPath) private void AddProject(SlnFile slnFile, string projectPath)
{ {
var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath); var projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath);
if (_slnFile.Projects.Any((p) => if (slnFile.Projects.Any((p) =>
string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase))) string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)))
{ {
Reporter.Output.WriteLine(string.Format( Reporter.Output.WriteLine(string.Format(
CommonLocalizableStrings.SolutionAlreadyContainsProject, CommonLocalizableStrings.SolutionAlreadyContainsProject,
_slnFile.FullPath, slnFile.FullPath,
projectPath)); projectPath));
} }
else else
@ -94,33 +103,10 @@ namespace Microsoft.DotNet.Tools.Add.ProjectToSolution
FilePath = projectPathNormalized FilePath = projectPathNormalized
}; };
_slnFile.Projects.Add(slnProject); slnFile.Projects.Add(slnProject);
Reporter.Output.WriteLine( Reporter.Output.WriteLine(
string.Format(CommonLocalizableStrings.ProjectAddedToTheSolution, projectPath)); 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;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Tools.Remove.ProjectFromSolution; using Microsoft.DotNet.Tools.Remove.ProjectFromSolution;
using Microsoft.DotNet.Tools.Remove.ProjectToProjectReference; using Microsoft.DotNet.Tools.Remove.ProjectToProjectReference;
@ -14,11 +13,11 @@ namespace Microsoft.DotNet.Tools.Remove
{ {
protected override string CommandName => "remove"; protected override string CommandName => "remove";
protected override string FullCommandNameLocalized => LocalizableStrings.NetRemoveCommand; protected override string FullCommandNameLocalized => LocalizableStrings.NetRemoveCommand;
internal override List<Func<CommandLineApplication, CommandLineApplication>> SubCommands => internal override List<Func<DotNetSubCommandBase>> SubCommands =>
new List<Func<CommandLineApplication, CommandLineApplication>> new List<Func<DotNetSubCommandBase>>
{ {
RemoveProjectFromSolutionCommand.CreateApplication, RemoveProjectFromSolutionCommand.Create,
RemoveProjectToProjectReferenceCommand.CreateApplication, RemoveProjectToProjectReferenceCommand.Create,
}; };
public static int Run(string[] args) 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. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Build.Evaluation; using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using System.Collections.Generic;
using Microsoft.DotNet.Tools.Remove;
namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference namespace Microsoft.DotNet.Tools.Remove.ProjectToProjectReference
{ {
public class RemoveProjectToProjectReference : IRemoveSubCommand internal class RemoveProjectToProjectReferenceCommand : DotNetSubCommandBase
{ {
private CommandOption _frameworkOption; private CommandOption _frameworkOption;
private MsbuildProject _msbuildProj;
internal RemoveProjectToProjectReference(string fileOrDirectory, CommandOption frameworkOption) public static DotNetSubCommandBase Create()
{ {
_msbuildProj = MsbuildProject.FromFileOrDirectory(new ProjectCollection(), fileOrDirectory); var command = new RemoveProjectToProjectReferenceCommand()
_frameworkOption = frameworkOption; {
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); throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneReferenceToRemove);
} }
int numberOfRemovedReferences = _msbuildProj.RemoveProjectToProjectReferences( int numberOfRemovedReferences = msbuildProj.RemoveProjectToProjectReferences(
_frameworkOption.Value(), _frameworkOption.Value(),
references); RemainingArguments);
if (numberOfRemovedReferences != 0) if (numberOfRemovedReferences != 0)
{ {
_msbuildProj.ProjectRootElement.Save(); msbuildProj.ProjectRootElement.Save();
} }
}
}
public class RemoveProjectToProjectReferenceCommand : RemoveSubCommandBase return 0;
{
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);
} }
} }
} }

View file

@ -1,56 +1,67 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. // 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. // 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.Sln.Internal;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.Common;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.Tools.Remove;
namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
{ {
public class RemoveProjectFromSolution : IRemoveSubCommand internal class RemoveProjectFromSolutionCommand : DotNetSubCommandBase
{ {
private SlnFile _slnFile; public static DotNetSubCommandBase Create()
public RemoveProjectFromSolution(string fileOrDirectory)
{ {
_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); throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToRemove);
} }
var relativeProjectPaths = projectPaths.Select((p) => var relativeProjectPaths = RemainingArguments.Select((p) =>
PathUtility.GetRelativePath( PathUtility.GetRelativePath(
PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory), PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory),
Path.GetFullPath(p))).ToList(); Path.GetFullPath(p))).ToList();
bool slnChanged = false; bool slnChanged = false;
foreach (var path in relativeProjectPaths) foreach (var path in relativeProjectPaths)
{ {
slnChanged |= RemoveProject(path); slnChanged |= RemoveProject(slnFile, path);
} }
if (slnChanged) 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 projectPathNormalized = PathUtility.GetPathWithBackSlashes(projectPath);
var projectsToRemove = _slnFile.Projects.Where((p) => var projectsToRemove = slnFile.Projects.Where((p) =>
string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)).ToList(); string.Equals(p.FilePath, projectPathNormalized, StringComparison.OrdinalIgnoreCase)).ToList();
bool projectRemoved = false; bool projectRemoved = false;
@ -64,7 +75,7 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
{ {
foreach (var slnProject in projectsToRemove) foreach (var slnProject in projectsToRemove)
{ {
_slnFile.Projects.Remove(slnProject); slnFile.Projects.Remove(slnProject);
Reporter.Output.WriteLine( Reporter.Output.WriteLine(
string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, slnProject.FilePath)); string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, slnProject.FilePath));
} }
@ -75,27 +86,4 @@ namespace Microsoft.DotNet.Tools.Remove.ProjectFromSolution
return projectRemoved; 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 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 FrameworkNet451Arg = "-f net451";
const string ConditionFrameworkNet451 = "== 'net451'"; const string ConditionFrameworkNet451 = "== 'net451'";
const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0"; const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0";
@ -77,7 +92,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{ {
var cmd = new AddP2PCommand().Execute(helpArg); var cmd = new AddP2PCommand().Execute(helpArg);
cmd.Should().Pass(); cmd.Should().Pass();
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
@ -87,7 +102,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject("one two three") .WithProject("one two three")
.Execute("proj.csproj"); .Execute("proj.csproj");
cmd.ExitCode.Should().NotBe(0); 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] [Theory]
@ -102,8 +118,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(projName) .WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0); cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("Could not find"); cmd.StdErr.Should().Be($"Could not find project or directory `{projName}`.");
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
@ -117,8 +133,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(projName) .WithProject(projName)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0); cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain(" is invalid."); cmd.StdErr.Should().Be("Project `Broken/Broken.csproj` is invalid.");
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
@ -126,12 +142,13 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{ {
var setup = Setup(); var setup = Setup();
var workingDir = Path.Combine(setup.TestRoot, "MoreThanOne");
var cmd = new AddP2PCommand() var cmd = new AddP2PCommand()
.WithWorkingDirectory(Path.Combine(setup.TestRoot, "MoreThanOne")) .WithWorkingDirectory(workingDir)
.Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\""); .Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\"");
cmd.ExitCode.Should().NotBe(0); cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("more than one"); cmd.StdErr.Should().Be($"Found more than one project in `{workingDir + Path.DirectorySeparatorChar}`. Please specify which one to use.");
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
@ -143,8 +160,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithWorkingDirectory(setup.TestRoot) .WithWorkingDirectory(setup.TestRoot)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.ExitCode.Should().NotBe(0); cmd.ExitCode.Should().NotBe(0);
cmd.StdErr.Should().Contain("not find any"); cmd.StdErr.Should().Be($"Could not find any project in `{setup.TestRoot + Path.DirectorySeparatorChar}`.");
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
@ -152,14 +169,14 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
{ {
var lib = NewLibWithFrameworks(); var lib = NewLibWithFrameworks();
var setup = Setup(); var setup = Setup();
int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition();
var cmd = new AddP2PCommand() var cmd = new AddP2PCommand()
.WithWorkingDirectory(setup.TestRoot) .WithWorkingDirectory(setup.TestRoot)
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -178,7 +195,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
@ -203,7 +220,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName) .WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -227,7 +244,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -251,7 +268,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -275,7 +292,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); cmd.Should().Pass();
cmd.StdOut.Should().Be("Reference `DotnetAddP2PProjects\\ValidRef\\ValidRef.csproj` added to the project.");
var csproj = lib.CsProj(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -299,7 +316,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName) .WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
@ -318,7 +335,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath) .WithProject(proj.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass(); 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); proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -340,7 +357,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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); lib.CsProjContent().Should().BeEquivalentTo(csprojContentBefore);
} }
@ -356,7 +373,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName) .WithProject(proj.CsProjName)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass(); 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); proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -372,7 +389,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName) .WithProject(proj.CsProjName)
.Execute($"\"{setup.LibCsprojRelPath}\""); .Execute($"\"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass(); 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); proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -388,7 +405,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath) .WithProject(proj.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -406,7 +423,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjName) .WithProject(proj.CsProjName)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\"");
cmd.Should().Pass(); 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); proj.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -422,7 +439,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath) .WithProject(proj.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -440,7 +457,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(proj.CsProjPath) .WithProject(proj.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -449,6 +466,9 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
[Fact] [Fact]
public void ItAddsMultipleRefsNoCondToTheSameItemGroup() 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 lib = NewLibWithFrameworks();
var setup = Setup(); var setup = Setup();
@ -458,7 +478,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"\"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1);
@ -468,6 +488,9 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
[Fact] [Fact]
public void ItAddsMultipleRefsWithCondToTheSameItemGroup() 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 lib = NewLibWithFrameworks();
var setup = Setup(); var setup = Setup();
@ -477,7 +500,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\""); .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1);
@ -495,7 +518,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithWorkingDirectory(lib.Path) .WithWorkingDirectory(lib.Path)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -513,7 +536,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName) .WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath}\""); .Execute($"\"{setup.ValidRefCsprojPath}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
int state = 0; int state = 0;
@ -558,7 +581,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName) .WithProject(lib.CsProjName)
.Execute("\"IDoNotExist.csproj\""); .Execute("\"IDoNotExist.csproj\"");
cmd.Should().Fail(); 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); lib.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -574,8 +597,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"\"{setup.ValidRefCsprojPath}\" \"IDoNotExist.csproj\""); .Execute($"\"{setup.ValidRefCsprojPath}\" \"IDoNotExist.csproj\"");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist"); cmd.StdErr.Should().Be("Reference IDoNotExist.csproj does not exist.");
cmd.StdErr.Should().NotMatchRegex("(.*does not exist.*){2,}");
lib.CsProjContent().Should().BeEquivalentTo(contentBefore); lib.CsProjContent().Should().BeEquivalentTo(contentBefore);
} }
@ -591,7 +613,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjName) .WithProject(lib.CsProjName)
.Execute($"\"{setup.ValidRefCsprojPath.Replace('\\', '/')}\""); .Execute($"\"{setup.ValidRefCsprojPath.Replace('\\', '/')}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var csproj = lib.CsProj(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -610,7 +632,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(setup.LibCsprojPath) .WithProject(setup.LibCsprojPath)
.Execute($"\"{setup.ValidRefCsprojRelPath}\""); .Execute($"\"{setup.ValidRefCsprojRelPath}\"");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var csproj = proj.CsProj(); var csproj = proj.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
@ -629,7 +651,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"{FrameworkNet451Arg} \"{net45lib.CsProjPath}\""); .Execute($"{FrameworkNet451Arg} \"{net45lib.CsProjPath}\"");
cmd.Should().Pass(); 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(); var csproj = lib.CsProj();
csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(net45lib.CsProjName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(net45lib.CsProjName, ConditionFrameworkNet451).Should().Be(1);
@ -647,7 +669,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(net452netcoreapp10lib.CsProjPath) .WithProject(net452netcoreapp10lib.CsProjPath)
.Execute($"\"{lib.CsProjPath}\""); .Execute($"\"{lib.CsProjPath}\"");
cmd.Should().Pass(); 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(); var csproj = net452netcoreapp10lib.CsProj();
csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1);
csproj.NumberOfProjectReferencesWithIncludeContaining(lib.CsProjName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(lib.CsProjName).Should().Be(1);
@ -669,8 +691,8 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
.WithProject(lib.CsProjPath) .WithProject(lib.CsProjPath)
.Execute($"-f {framework} \"{net45lib.CsProjPath}\""); .Execute($"-f {framework} \"{net45lib.CsProjPath}\"");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().MatchRegex(ProjectDoesNotTargetFrameworkErrorMessageRegEx); cmd.StdErr.Should().Be($"Project `{setup.LibCsprojPath}` does not target framework `{framework}`.");
cmd.StdErr.Should().Contain($"`{framework}`");
lib.CsProjContent().Should().BeEquivalentTo(csProjContent); lib.CsProjContent().Should().BeEquivalentTo(csProjContent);
} }

View file

@ -14,6 +14,20 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
{ {
public class GivenDotnetAddProj : TestBase 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] [Theory]
[InlineData("--help")] [InlineData("--help")]
[InlineData("-h")] [InlineData("-h")]
@ -22,7 +36,17 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add project {helpArg}"); .ExecuteWithCapturedOutput($"add project {helpArg}");
cmd.Should().Pass(); 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] [Theory]
@ -36,86 +60,103 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"add {solutionName} project p.csproj"); .ExecuteWithCapturedOutput($"add {solutionName} project p.csproj");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("Could not find"); cmd.StdErr.Should().Be($"Could not find solution or directory `{solutionName}`.");
cmd.StdOut.Should().Contain("Usage:"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage() public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution") var projectDirectory = TestAssets
.WithLockFiles() .Get("InvalidSolution")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add InvalidSolution.sln project {projectToAdd}"); .ExecuteWithCapturedOutput($"add InvalidSolution.sln project {projectToAdd}");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution "); cmd.StdErr.Should().Be("Invalid solution `InvalidSolution.sln`.");
cmd.StdOut.Should().Contain("Usage:"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage() public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("InvalidSolution") var projectDirectory = TestAssets
.WithLockFiles() .Get("InvalidSolution")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "InvalidSolution.sln");
var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}"); .ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("Invalid solution "); cmd.StdErr.Should().Be($"Invalid solution `{solutionPath}`.");
cmd.StdOut.Should().Contain("Usage:"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
public void WhenNoProjectIsPassedItPrintsErrorAndUsage() public void WhenNoProjectIsPassedItPrintsErrorAndUsage()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles") var projectDirectory = TestAssets
.WithLockFiles() .Get("TestAppWithSlnAndCsprojFiles")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput(@"add App.sln project"); .ExecuteWithCapturedOutput(@"add App.sln project");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("You must specify at least one project to add."); cmd.StdErr.Should().Be("You must specify at least one project to add.");
cmd.StdOut.Should().Contain("Usage:"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage() public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles") var projectDirectory = TestAssets
.WithLockFiles() .Get("TestAppWithSlnAndCsprojFiles")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App");
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(Path.Combine(projectDirectory, "App")) .WithWorkingDirectory(solutionPath)
.ExecuteWithCapturedOutput(@"add project App.csproj"); .ExecuteWithCapturedOutput(@"add project App.csproj");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist"); 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().Contain("Usage:"); cmd.StdOut.Should().Be(HelpText);
} }
[Fact] [Fact]
public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage() public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithMultipleSlnFiles") var projectDirectory = TestAssets
.WithLockFiles() .Get("TestAppWithMultipleSlnFiles")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add project {projectToAdd}"); .ExecuteWithCapturedOutput($"add project {projectToAdd}");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("more than one"); cmd.StdErr.Should().Be($"Found more than one solution file in {projectDirectory + Path.DirectorySeparatorChar}. Please specify which one to use.");
cmd.StdOut.Should().Contain("Usage"); cmd.StdOut.Should().Be(HelpText);
} }
[Theory] [Theory]
@ -125,9 +166,12 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
string testAsset, string testAsset,
string projectGuid) string projectGuid)
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance(testAsset) var projectDirectory = TestAssets
.WithLockFiles() .Get(testAsset)
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToAdd = "Lib/Lib.csproj"; var projectToAdd = "Lib/Lib.csproj";
var normalizedProjectPath = @"Lib\Lib.csproj"; var normalizedProjectPath = @"Lib\Lib.csproj";
@ -135,7 +179,7 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}"); .ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass(); 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(); cmd.StdErr.Should().BeEmpty();
var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln"));
@ -165,25 +209,32 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
[Fact] [Fact]
public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate() public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndExistingCsprojReferences") var projectDirectory = TestAssets
.WithLockFiles() .Get("TestAppWithSlnAndExistingCsprojReferences")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var projectToAdd = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand() var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}"); .ExecuteWithCapturedOutput($"add App.sln project {projectToAdd}");
cmd.Should().Pass(); cmd.Should().Pass();
cmd.StdOut.Should().Contain("already contains project"); cmd.StdOut.Should().Be($"Solution {solutionPath} already contains project {projectToAdd}.");
cmd.StdErr.Should().BeEmpty(); cmd.StdErr.Should().BeEmpty();
} }
[Fact] [Fact]
public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation() public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation()
{ {
var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSlnAndCsprojFiles") var projectDirectory = TestAssets
.WithLockFiles() .Get("TestAppWithSlnAndCsprojFiles")
.Path; .CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var slnFullPath = Path.Combine(projectDirectory, "App.sln"); var slnFullPath = Path.Combine(projectDirectory, "App.sln");
var contentBefore = File.ReadAllText(slnFullPath); var contentBefore = File.ReadAllText(slnFullPath);
@ -193,8 +244,7 @@ namespace Microsoft.DotNet.Cli.Add.Proj.Tests
.WithWorkingDirectory(projectDirectory) .WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"add App.sln project {projectToAdd} idonotexist.csproj"); .ExecuteWithCapturedOutput($"add App.sln project {projectToAdd} idonotexist.csproj");
cmd.Should().Fail(); cmd.Should().Fail();
cmd.StdErr.Should().Contain("does not exist"); cmd.StdErr.Should().Be("Project `idonotexist.csproj` does not exist.");
cmd.StdErr.Should().NotMatchRegex("(.*does not exist.*){2,}");
File.ReadAllText(slnFullPath) File.ReadAllText(slnFullPath)
.Should().BeEquivalentTo(contentBefore); .Should().BeEquivalentTo(contentBefore);

View file

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

View file

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