// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using FluentAssertions; using Microsoft.Build.Construction; using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Test.Utilities; using Msbuild.Tests.Utilities; using System; using System.IO; using System.Linq; using Xunit; namespace Microsoft.DotNet.Cli.Add.Reference.Tests { public class GivenDotnetAddReference : TestBase { private const string HelpText = @"Usage: dotnet add reference [options] Arguments: The project file to operate on. If a file is not specified, the command will search the current directory for one. The paths to the projects to add as references. Options: -h, --help Show command line help. -f, --framework Add the reference only when targeting a specific framework."; private const string AddCommandHelpText = @"Usage: dotnet add [options] [command] Arguments: The project file to operate on. If a file is not specified, the command will search the current directory for one. Options: -h, --help Show command line help. Commands: package Add a NuGet package reference to the project. reference Add a project-to-project reference to the project."; const string FrameworkNet451Arg = "-f net451"; const string ConditionFrameworkNet451 = "== 'net451'"; const string FrameworkNetCoreApp10Arg = "-f netcoreapp1.0"; const string ConditionFrameworkNetCoreApp10 = "== 'netcoreapp1.0'"; static readonly string ProjectNotCompatibleErrorMessageRegEx = string.Format(CommonLocalizableStrings.ProjectNotCompatibleWithFrameworks, "[^`]*"); static readonly string ProjectDoesNotTargetFrameworkErrorMessageRegEx = string.Format(CommonLocalizableStrings.ProjectDoesNotTargetFramework, "[^`]*", "[^`]*"); static readonly string[] DefaultFrameworks = new string[] { "netcoreapp1.0", "net451" }; private TestSetup Setup([System.Runtime.CompilerServices.CallerMemberName] string callingMethod = nameof(Setup), string identifier = "") { return new TestSetup( TestAssets.Get(TestSetup.TestGroup, TestSetup.ProjectName) .CreateInstance(callingMethod: callingMethod, identifier: identifier) .WithSourceFiles() .Root .FullName); } private ProjDir NewDir([System.Runtime.CompilerServices.CallerMemberName] string callingMethod = nameof(NewDir), string identifier = "") { return new ProjDir(TestAssets.CreateTestDirectory(callingMethod: callingMethod, identifier: identifier).FullName); } private ProjDir NewLib(string dir = null, [System.Runtime.CompilerServices.CallerMemberName] string callingMethod = nameof(NewDir), string identifier = "") { var projDir = dir == null ? NewDir(callingMethod: callingMethod, identifier: identifier) : new ProjDir(dir); try { string args = $"classlib -o \"{projDir.Path}\" --debug:ephemeral-hive --no-restore"; new NewCommandShim() .WithWorkingDirectory(projDir.Path) .ExecuteWithCapturedOutput(args) .Should().Pass(); } catch (System.ComponentModel.Win32Exception e) { throw new Exception($"Intermittent error in `dotnet new` occurred when running it in dir `{projDir.Path}`\nException:\n{e}"); } return projDir; } private static void SetTargetFrameworks(ProjDir proj, string[] frameworks) { var csproj = proj.CsProj(); csproj.AddProperty("TargetFrameworks", string.Join(";", frameworks)); csproj.Save(); } private ProjDir NewLibWithFrameworks(string dir = null, [System.Runtime.CompilerServices.CallerMemberName] string callingMethod = nameof(NewDir), string identifier = "") { var ret = NewLib(dir, callingMethod: callingMethod, identifier: identifier); SetTargetFrameworks(ret, DefaultFrameworks); return ret; } [Theory] [InlineData("--help")] [InlineData("-h")] public void WhenHelpOptionIsPassedItPrintsUsage(string helpArg) { var cmd = new AddReferenceCommand().Execute(helpArg); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Theory] [InlineData("")] [InlineData("unknownCommandName")] public void WhenNoCommandIsPassedItPrintsError(string commandName) { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput($"add {commandName}"); cmd.Should().Fail(); cmd.StdErr.Should().Be(CommonLocalizableStrings.RequiredCommandNotPassed); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(AddCommandHelpText); } [Fact] public void WhenTooManyArgumentsArePassedItPrintsError() { var cmd = new AddReferenceCommand() .WithProject("one two three") .Execute("proj.csproj"); cmd.ExitCode.Should().NotBe(0); cmd.StdErr.Should().BeVisuallyEquivalentTo($@"{string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "two")} {string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "three")}"); } [Theory] [InlineData("idontexist.csproj")] [InlineData("ihave?inv@lid/char\\acters")] public void WhenNonExistingProjectIsPassedItPrintsErrorAndUsage(string projName) { var setup = Setup(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(projName) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.ExitCode.Should().NotBe(0); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, projName)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenBrokenProjectIsPassedItPrintsErrorAndUsage() { string projName = "Broken/Broken.csproj"; var setup = Setup(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(projName) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.ExitCode.Should().NotBe(0); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.ProjectIsInvalid, "Broken/Broken.csproj")); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenMoreThanOneProjectExistsInTheDirectoryItPrintsErrorAndUsage() { var setup = Setup(); var workingDir = Path.Combine(setup.TestRoot, "MoreThanOne"); var cmd = new AddReferenceCommand() .WithWorkingDirectory(workingDir) .Execute($"\"{setup.ValidRefCsprojRelToOtherProjPath}\""); cmd.ExitCode.Should().NotBe(0); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneProjectInDirectory, workingDir + Path.DirectorySeparatorChar)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void WhenNoProjectsExistsInTheDirectoryItPrintsErrorAndUsage() { var setup = Setup(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.ExitCode.Should().NotBe(0); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, setup.TestRoot + Path.DirectorySeparatorChar)); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); } [Fact] public void ItAddsRefWithoutCondAndPrintsStatus() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); cmd.StdErr.Should().BeEmpty(); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void ItAddsRefWithCondAndPrintsStatus() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int condBefore = lib.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); cmd.StdErr.Should().BeEmpty(); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void WhenRefWithoutCondIsPresentItAddsDifferentRefWithoutCond() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.LibCsprojPath}\"") .Should().Pass(); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(lib.Path) .WithProject(lib.CsProjName) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void WhenRefWithCondIsPresentItAddsDifferentRefWithCond() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\"") .Should().Pass(); int condBefore = lib.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); ; var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void WhenRefWithCondIsPresentItAddsRefWithDifferentCond() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNetCoreApp10Arg} \"{setup.ValidRefCsprojPath}\"") .Should().Pass(); int condBefore = lib.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void WhenRefWithConditionIsPresentItAddsDifferentRefWithoutCond() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\"") .Should().Pass(); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void WhenRefWithNoCondAlreadyExistsItDoesntDuplicate() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\"") .Should().Pass(); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(lib.Path) .WithProject(lib.CsProjName) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"ValidRef\ValidRef.csproj")); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void WhenRefWithCondOnItemAlreadyExistsItDoesntDuplicate() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithExistingRefCondOnItem")); string contentBefore = proj.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(proj.Path) .WithProject(proj.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"..\Lib\Lib.csproj")); proj.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenRefWithCondOnItemGroupAlreadyExistsItDoesntDuplicate() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\"") .Should().Pass(); var csprojContentBefore = lib.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"ValidRef\ValidRef.csproj")); lib.CsProjContent().Should().BeEquivalentTo(csprojContentBefore); } [Fact] public void WhenRefWithCondWithWhitespaceOnItemGroupExistsItDoesntDuplicate() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithExistingRefCondWhitespaces")); string contentBefore = proj.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(proj.Path) .WithProject(proj.CsProjName) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"..\Lib\Lib.csproj")); proj.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenRefWithoutCondAlreadyExistsInNonUniformItemGroupItDoesntDuplicate() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithRefNoCondNonUniform")); string contentBefore = proj.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(proj.Path) .WithProject(proj.CsProjName) .Execute($"\"{setup.LibCsprojRelPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"..\Lib\Lib.csproj")); proj.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenRefWithoutCondAlreadyExistsInNonUniformItemGroupItAddsDifferentRefInDifferentGroup() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithRefNoCondNonUniform")); int noCondBefore = proj.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(proj.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"..\ValidRef\ValidRef.csproj")); var csproj = proj.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void WhenRefWithCondAlreadyExistsInNonUniformItemGroupItDoesntDuplicate() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithRefCondNonUniform")); string contentBefore = proj.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(proj.Path) .WithProject(proj.CsProjName) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojRelPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAlreadyHasAreference, @"..\Lib\Lib.csproj")); proj.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenRefWithCondAlreadyExistsInNonUniformItemGroupItAddsDifferentRefInDifferentGroup() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "WithRefCondNonUniform")); int condBefore = proj.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(proj.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, "..\\ValidRef\\ValidRef.csproj")); var csproj = proj.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void WhenEmptyItemGroupPresentItAddsRefInIt() { var setup = Setup(); var proj = new ProjDir(Path.Combine(setup.TestRoot, "EmptyItemGroup")); int noCondBefore = proj.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(proj.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"..\ValidRef\ValidRef.csproj")); var csproj = proj.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void ItAddsMultipleRefsNoCondToTheSameItemGroup() { string OutputText = $@"{string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"Lib\Lib.csproj")} {string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")}"; var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentTo(OutputText); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.LibCsprojName).Should().Be(1); } [Fact] public void ItAddsMultipleRefsWithCondToTheSameItemGroup() { string OutputText = $@"{string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"Lib\Lib.csproj")} {string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")}"; var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{setup.LibCsprojPath}\" \"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentTo(OutputText); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.ValidRefCsprojName, ConditionFrameworkNet451).Should().Be(1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(setup.LibCsprojName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void WhenProjectNameIsNotPassedItFindsItAndAddsReference() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(lib.Path) .Execute($"\"{setup.ValidRefCsprojPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); cmd.StdErr.Should().BeEmpty(); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojName).Should().Be(1); } [Fact] public void WhenPassedReferenceDoesNotExistItShowsAnError() { var lib = NewLibWithFrameworks(); var contentBefore = lib.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(lib.Path) .WithProject(lib.CsProjName) .Execute("\"IDoNotExist.csproj\""); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "IDoNotExist.csproj")); lib.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenPassedMultipleRefsAndOneOfthemDoesNotExistItCancelsWholeOperation() { var lib = NewLibWithFrameworks(); var setup = Setup(); var contentBefore = lib.CsProjContent(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{setup.ValidRefCsprojPath}\" \"IDoNotExist.csproj\""); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "IDoNotExist.csproj")); lib.CsProjContent().Should().BeEquivalentTo(contentBefore); } [Fact] public void WhenPassedReferenceIsUsingSlashesItNormalizesItToBackslashes() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); int noCondBefore = lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(lib.Path) .WithProject(lib.CsProjName) .Execute($"\"{setup.ValidRefCsprojPath.Replace('\\', '/')}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); cmd.StdErr.Should().BeEmpty(); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojRelPath.Replace('/', '\\')).Should().Be(1); } [Fact] public void WhenReferenceIsRelativeAndProjectIsNotInCurrentDirectoryReferencePathIsFixed() { var setup = Setup(); var proj = new ProjDir(setup.LibDir); int noCondBefore = proj.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(setup.LibCsprojPath) .Execute($"\"{setup.ValidRefCsprojRelPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"..\ValidRef\ValidRef.csproj")); cmd.StdErr.Should().BeEmpty(); var csproj = proj.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(setup.ValidRefCsprojRelToOtherProjPath.Replace('/', '\\')).Should().Be(1); } [Fact] public void ItCanAddReferenceWithConditionOnCompatibleFramework() { var setup = Setup(); var lib = new ProjDir(setup.LibDir); var net45lib = new ProjDir(Path.Combine(setup.TestRoot, "Net45Lib")); int condBefore = lib.CsProj().NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451); var cmd = new AddReferenceCommand() .WithProject(lib.CsProjPath) .Execute($"{FrameworkNet451Arg} \"{net45lib.CsProjPath}\""); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"..\Net45Lib\Net45Lib.csproj")); var csproj = lib.CsProj(); csproj.NumberOfItemGroupsWithConditionContaining(ConditionFrameworkNet451).Should().Be(condBefore + 1); csproj.NumberOfProjectReferencesWithIncludeAndConditionContaining(net45lib.CsProjName, ConditionFrameworkNet451).Should().Be(1); } [Fact] public void ItCanAddRefWithoutCondAndTargetingSupersetOfFrameworksAndOneOfReferencesCompatible() { var setup = Setup(); var lib = new ProjDir(setup.LibDir); var net452netcoreapp10lib = new ProjDir(Path.Combine(setup.TestRoot, "Net452AndNetCoreApp10Lib")); int noCondBefore = net452netcoreapp10lib.CsProj().NumberOfItemGroupsWithoutCondition(); var cmd = new AddReferenceCommand() .WithProject(net452netcoreapp10lib.CsProjPath) .Execute($"\"{lib.CsProjPath}\""); cmd.Should().Pass(); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"..\Lib\Lib.csproj")); var csproj = net452netcoreapp10lib.CsProj(); csproj.NumberOfItemGroupsWithoutCondition().Should().Be(noCondBefore + 1); csproj.NumberOfProjectReferencesWithIncludeContaining(lib.CsProjName).Should().Be(1); } [Theory] [InlineData("net45")] [InlineData("net40")] [InlineData("netcoreapp1.1")] [InlineData("nonexistingframeworkname")] public void WhenFrameworkSwitchIsNotMatchingAnyOfTargetedFrameworksItPrintsError(string framework) { var setup = Setup(framework); var lib = new ProjDir(setup.LibDir); var net45lib = new ProjDir(Path.Combine(setup.TestRoot, "Net45Lib")); var csProjContent = lib.CsProjContent(); var cmd = new AddReferenceCommand() .WithProject(lib.CsProjPath) .Execute($"-f {framework} \"{net45lib.CsProjPath}\""); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.ProjectDoesNotTargetFramework, setup.LibCsprojPath, framework)); lib.CsProjContent().Should().BeEquivalentTo(csProjContent); } [Theory] [InlineData("")] [InlineData("-f net45")] public void WhenIncompatibleFrameworkDetectedItPrintsError(string frameworkArg) { var setup = Setup(); var lib = new ProjDir(setup.LibDir); var net45lib = new ProjDir(Path.Combine(setup.TestRoot, "Net45Lib")); var csProjContent = net45lib.CsProjContent(); var cmd = new AddReferenceCommand() .WithProject(net45lib.CsProjPath) .Execute($"{frameworkArg} \"{lib.CsProjPath}\""); cmd.Should().Fail(); cmd.StdErr.Should().MatchRegex(ProjectNotCompatibleErrorMessageRegEx); cmd.StdErr.Should().MatchRegex(" - net45"); net45lib.CsProjContent().Should().BeEquivalentTo(csProjContent); } [Fact] public void WhenDirectoryContainingProjectIsGivenReferenceIsAdded() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); var result = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute($"\"{Path.GetDirectoryName(setup.ValidRefCsprojPath)}\""); result.Should().Pass(); result.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ReferenceAddedToTheProject, @"ValidRef\ValidRef.csproj")); result.StdErr.Should().BeEmpty(); } [Fact] public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); var reference = "Empty"; var result = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute(reference); result.Should().Fail(); result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, reference)); } [Fact] public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation() { var setup = Setup(); var lib = NewLibWithFrameworks(dir: setup.TestRoot); var reference = "MoreThanOne"; var result = new AddReferenceCommand() .WithWorkingDirectory(setup.TestRoot) .WithProject(lib.CsProjPath) .Execute(reference); result.Should().Fail(); result.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText); result.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneProjectInDirectory, reference)); } } }