dotnet-installer/test/dotnet-sln-remove.Tests/GivenDotnetSlnRemove.cs
Peter Huene 6210dab09c Remove project dependencies when removing a project from a solution.
This commit fixes #6198.

When a project is removed from a solution using the `sln remove`
command, any projects in the solution with a project dependency (note:
this is different from a project reference) on the project should have
the project removed as a dependency.

The fix is to scan the projects in the solution and remove any
dependencies on the projects being removed.  If the dependencies section
is empty after the remove, we skip serialization of the section like
Visual Studio does.
2017-11-21 18:20:05 -08:00

618 lines
27 KiB
C#

// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using FluentAssertions;
using Microsoft.DotNet.Cli.Sln.Internal;
using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Test.Utilities;
using System;
using System.IO;
using System.Linq;
using Xunit;
namespace Microsoft.DotNet.Cli.Sln.Remove.Tests
{
public class GivenDotnetSlnRemove : TestBase
{
private const string HelpText = @"Usage: dotnet sln <SLN_FILE> remove [options] <args>
Arguments:
<SLN_FILE> Solution file to operate on. If not specified, the command will search the current directory for one.
<args> Remove the specified project(s) from the solution. The project is not impacted.
Options:
-h, --help Show help information.
";
private const string SlnCommandHelpText = @"Usage: dotnet sln [options] <SLN_FILE> [command]
Arguments:
<SLN_FILE> Solution file to operate on. If not specified, the command will search the current directory for one.
Options:
-h, --help Show help information.
Commands:
add <args> .NET Add project(s) to a solution file Command
list .NET List project(s) in a solution file Command
remove <args> .NET Remove project(s) from a solution file Command
";
private const string ExpectedSlnContentsAfterRemove = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App\App.csproj"", ""{7072A694-548F-4CAE-A58F-12D257D5F486}""
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal
";
private const string ExpectedSlnContentsAfterRemoveAllProjects = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Global
EndGlobal
";
private const string ExpectedSlnContentsAfterRemoveNestedProj = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App.csproj"", ""{7072A694-548F-4CAE-A58F-12D257D5F486}""
EndProject
Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""src"", ""src"", ""{7B86CE74-F620-4B32-99FE-82D40F8D6BF2}""
EndProject
Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""{EAB71280-AF32-4531-8703-43CDBA261AA3}""
EndProject
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""Lib"", ""src\Lib\Lib.csproj"", ""{84A45D44-B677-492D-A6DA-B3A71135AB8E}""
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x64.ActiveCfg = Debug|x64
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x64.Build.0 = Debug|x64
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x86.ActiveCfg = Debug|x86
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x86.Build.0 = Debug|x86
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|Any CPU.Build.0 = Release|Any CPU
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x64.ActiveCfg = Release|x64
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x64.Build.0 = Release|x64
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x86.ActiveCfg = Release|x86
{84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EAB71280-AF32-4531-8703-43CDBA261AA3} = {7B86CE74-F620-4B32-99FE-82D40F8D6BF2}
{84A45D44-B677-492D-A6DA-B3A71135AB8E} = {EAB71280-AF32-4531-8703-43CDBA261AA3}
EndGlobalSection
EndGlobal
";
private const string ExpectedSlnContentsAfterRemoveLastNestedProj = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26006.2
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App.csproj"", ""{7072A694-548F-4CAE-A58F-12D257D5F486}""
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.ActiveCfg = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x64.Build.0 = Debug|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.ActiveCfg = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Debug|x86.Build.0 = Debug|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|Any CPU.Build.0 = Release|Any CPU
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.ActiveCfg = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x64.Build.0 = Release|x64
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.ActiveCfg = Release|x86
{7072A694-548F-4CAE-A58F-12D257D5F486}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal
";
private const string ExpectedSlnContentsAfterRemoveProjectWithDependencies = @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27110.0
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""App"", ""App\App.csproj"", ""{BB02B949-F6BD-4872-95CB-96A05B1FE026}""
ProjectSection(ProjectDependencies) = postProject
{D53E177A-8ECF-43D5-A01E-98B884D53CA6} = {D53E177A-8ECF-43D5-A01E-98B884D53CA6}
EndProjectSection
EndProject
Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""First"", ""First\First.csproj"", ""{D53E177A-8ECF-43D5-A01E-98B884D53CA6}""
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BB02B949-F6BD-4872-95CB-96A05B1FE026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB02B949-F6BD-4872-95CB-96A05B1FE026}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB02B949-F6BD-4872-95CB-96A05B1FE026}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB02B949-F6BD-4872-95CB-96A05B1FE026}.Release|Any CPU.Build.0 = Release|Any CPU
{D53E177A-8ECF-43D5-A01E-98B884D53CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D53E177A-8ECF-43D5-A01E-98B884D53CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D53E177A-8ECF-43D5-A01E-98B884D53CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D53E177A-8ECF-43D5-A01E-98B884D53CA6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F6D9A973-1CFD-41C9-84F2-1471C0FE67DF}
EndGlobalSection
EndGlobal
";
[Theory]
[InlineData("--help")]
[InlineData("-h")]
public void WhenHelpOptionIsPassedItPrintsUsage(string helpArg)
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"sln remove {helpArg}");
cmd.Should().Pass();
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenTooManyArgumentsArePassedItPrintsError()
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput("sln one.sln two.sln three.sln remove");
cmd.Should().Fail();
cmd.StdErr.Should().BeVisuallyEquivalentTo($@"{string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "two.sln")}
{string.Format(CommandLine.LocalizableStrings.UnrecognizedCommandOrArgument, "three.sln")}
{CommonLocalizableStrings.SpecifyAtLeastOneProjectToRemove}");
}
[Theory]
[InlineData("")]
[InlineData("unknownCommandName")]
public void WhenNoCommandIsPassedItPrintsError(string commandName)
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"sln {commandName}");
cmd.Should().Fail();
cmd.StdErr.Should().Be(CommonLocalizableStrings.RequiredCommandNotPassed);
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(SlnCommandHelpText);
}
[Theory]
[InlineData("idontexist.sln")]
[InlineData("ihave?invalidcharacters")]
[InlineData("ihaveinv@lidcharacters")]
[InlineData("ihaveinvalid/characters")]
[InlineData("ihaveinvalidchar\\acters")]
public void WhenNonExistingSolutionIsPassedItPrintsErrorAndUsage(string solutionName)
{
var cmd = new DotnetCommand()
.ExecuteWithCapturedOutput($"sln {solutionName} remove p.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindSolutionOrDirectory, solutionName));
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssets
.Get("InvalidSolution")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln InvalidSolution.sln remove {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, "InvalidSolution.sln", LocalizableStrings.FileHeaderMissingError));
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenInvalidSolutionIsFoundItPrintsErrorAndUsage()
{
var projectDirectory = TestAssets
.Get("InvalidSolution")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "InvalidSolution.sln");
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, solutionPath, LocalizableStrings.FileHeaderMissingError));
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenNoProjectIsPassedItPrintsErrorAndUsage()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput(@"sln App.sln remove");
cmd.Should().Fail();
cmd.StdErr.Should().Be(CommonLocalizableStrings.SpecifyAtLeastOneProjectToRemove);
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenNoSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App");
var cmd = new DotnetCommand()
.WithWorkingDirectory(solutionPath)
.ExecuteWithCapturedOutput(@"sln remove App.csproj");
cmd.Should().Fail();
cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.SolutionDoesNotExist, solutionPath + Path.DirectorySeparatorChar));
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage()
{
var projectDirectory = TestAssets
.Get("TestAppWithMultipleSlnFiles")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Fail();
cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.MoreThanOneSolutionInDirectory, projectDirectory + Path.DirectorySeparatorChar));
cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(HelpText);
}
[Fact]
public void WhenPassedAReferenceNotInSlnItPrintsStatus()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndExistingCsprojReferences")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var contentBefore = File.ReadAllText(solutionPath);
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput("sln remove referenceDoesNotExistInSln.csproj");
cmd.Should().Pass();
cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "referenceDoesNotExistInSln.csproj"));
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(contentBefore);
}
[Fact]
public void WhenPassedAReferenceItRemovesTheReferenceButNotOtherReferences()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndExistingCsprojReferences")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(2);
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove));
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);
slnFile.Projects[0].FilePath.Should().Be(Path.Combine("App", "App.csproj"));
}
[Fact]
public void WhenDuplicateReferencesArePresentItRemovesThemAll()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndDuplicateProjectReferences")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(3);
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
string outputText = string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove);
outputText += Environment.NewLine + outputText;
cmd.StdOut.Should().BeVisuallyEquivalentTo(outputText);
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);
slnFile.Projects[0].FilePath.Should().Be(Path.Combine("App", "App.csproj"));
}
[Fact]
public void WhenPassedMultipleReferencesAndOneOfThemDoesNotExistItRemovesTheOneThatExists()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndExistingCsprojReferences")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(2);
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove idontexist.csproj {projectToRemove} idontexisteither.csproj");
cmd.Should().Pass();
string outputText = $@"{string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "idontexist.csproj")}
{string.Format(CommonLocalizableStrings.ProjectReferenceRemoved, projectToRemove)}
{string.Format(CommonLocalizableStrings.ProjectReferenceCouldNotBeFound, "idontexisteither.csproj")}";
cmd.StdOut.Should().BeVisuallyEquivalentTo(outputText);
slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(1);
slnFile.Projects[0].FilePath.Should().Be(Path.Combine("App", "App.csproj"));
}
[Fact]
public void WhenReferenceIsRemovedBuildConfigsAreAlsoRemoved()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(2);
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemove);
}
[Fact]
public void WhenReferenceIsRemovedSlnBuilds()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(2);
var projectToRemove = Path.Combine("Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.Execute($"restore App.sln")
.Should().Pass();
new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.Execute("build App.sln --configuration Release")
.Should().Pass();
var reasonString = "should be built in release mode, otherwise it means build configurations are missing from the sln file";
var releaseDirectory = Directory.EnumerateDirectories(
Path.Combine(projectDirectory, "App", "bin"),
"Release",
SearchOption.AllDirectories);
releaseDirectory.Count().Should().Be(1, $"App {reasonString}");
Directory.EnumerateFiles(releaseDirectory.Single(), "App.dll", SearchOption.AllDirectories)
.Count().Should().Be(1, $"App {reasonString}");
}
[Fact]
public void WhenFinalReferenceIsRemovedEmptySectionsAreRemoved()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
SlnFile slnFile = SlnFile.Read(solutionPath);
slnFile.Projects.Count.Should().Be(2);
var appPath = Path.Combine("App", "App.csproj");
var libPath = Path.Combine("Lib", "Lib.csproj");
var projectsToRemove = $"{libPath} {appPath}";
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectsToRemove}");
cmd.Should().Pass();
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemoveAllProjects);
}
[Fact]
public void WhenNestedProjectIsRemovedItsSolutionFoldersAreRemoved()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndCsprojInSubDirToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var projectToRemove = Path.Combine("src", "NotLastProjInSrc", "NotLastProjInSrc.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemoveNestedProj);
}
[Fact]
public void WhenFinalNestedProjectIsRemovedSolutionFoldersAreRemoved()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnAndLastCsprojInSubDirToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var projectToRemove = Path.Combine("src", "Lib", "Lib.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemoveLastNestedProj);
}
[Fact]
public void WhenProjectIsRemovedThenDependenciesOnProjectAreAlsoRemoved()
{
var projectDirectory = TestAssets
.Get("TestAppWithSlnProjectDependencyToRemove")
.CreateInstance()
.WithSourceFiles()
.Root
.FullName;
var solutionPath = Path.Combine(projectDirectory, "App.sln");
var projectToRemove = Path.Combine("Second", "Second.csproj");
var cmd = new DotnetCommand()
.WithWorkingDirectory(projectDirectory)
.ExecuteWithCapturedOutput($"sln remove {projectToRemove}");
cmd.Should().Pass();
File.ReadAllText(solutionPath)
.Should().BeVisuallyEquivalentTo(ExpectedSlnContentsAfterRemoveProjectWithDependencies);
}
}
}