diff --git a/src/Cli/dotnet/commands/dotnet-sln/add/Program.cs b/src/Cli/dotnet/commands/dotnet-sln/add/Program.cs index ded4c5fc3968..2d569becac9f 100644 --- a/src/Cli/dotnet/commands/dotnet-sln/add/Program.cs +++ b/src/Cli/dotnet/commands/dotnet-sln/add/Program.cs @@ -2,10 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; +using Microsoft.Build.Construction; +using Microsoft.Build.Exceptions; +using Microsoft.Build.Execution; using Microsoft.DotNet.Cli; -using Microsoft.DotNet.Cli.Sln.Internal; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Tools.Common; +using Microsoft.VisualStudio.SolutionPersistence; +using Microsoft.VisualStudio.SolutionPersistence.Model; +using Microsoft.VisualStudio.SolutionPersistence.Serializer.SlnV12; namespace Microsoft.DotNet.Tools.Sln.Add { @@ -13,132 +18,167 @@ internal class AddProjectToSolutionCommand : CommandBase { private readonly string _fileOrDirectory; private readonly bool _inRoot; - private readonly IList _relativeRootSolutionFolders; - private readonly IReadOnlyCollection _arguments; + private readonly IReadOnlyCollection _projects; + private readonly string? _solutionFolderPath; + private static string GetSolutionFolderPathWithForwardSlashes(string path) + { + // SolutionModel::AddFolder expects paths to have leading, trailing and inner forward slashes + return "/" + string.Join("/", PathUtility.GetPathWithDirectorySeparator(path).Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries)) + "/"; + } public AddProjectToSolutionCommand(ParseResult parseResult) : base(parseResult) { _fileOrDirectory = parseResult.GetValue(SlnCommandParser.SlnArgument); - - _arguments = parseResult.GetValue(SlnAddParser.ProjectPathArgument)?.ToArray() ?? (IReadOnlyCollection)Array.Empty(); - + _projects = (IReadOnlyCollection)(parseResult.GetValue(SlnAddParser.ProjectPathArgument) ?? []); _inRoot = parseResult.GetValue(SlnAddParser.InRootOption); - string relativeRoot = parseResult.GetValue(SlnAddParser.SolutionFolderOption); - - SlnArgumentValidator.ParseAndValidateArguments(_fileOrDirectory, _arguments, SlnArgumentValidator.CommandType.Add, _inRoot, relativeRoot); - - bool hasRelativeRoot = !string.IsNullOrEmpty(relativeRoot); - - if (hasRelativeRoot) - { - relativeRoot = PathUtility.GetPathWithDirectorySeparator(relativeRoot); - _relativeRootSolutionFolders = relativeRoot.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries); - } - else - { - _relativeRootSolutionFolders = null; - } + _solutionFolderPath = parseResult.GetValue(SlnAddParser.SolutionFolderOption); + SlnArgumentValidator.ParseAndValidateArguments(_fileOrDirectory, _projects, SlnArgumentValidator.CommandType.Add, _inRoot, _solutionFolderPath); } public override int Execute() { - SlnFile slnFile = SlnFileFactory.CreateFromFileOrDirectory(_fileOrDirectory); - - var arguments = (_parseResult.GetValue>(SlnAddParser.ProjectPathArgument) ?? Array.Empty()).ToList().AsReadOnly(); - if (arguments.Count == 0) + string solutionFileFullPath = SlnCommandParser.GetSlnFileFullPath(_fileOrDirectory); + if (_projects.Count == 0) { throw new GracefulException(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd); } - - PathUtility.EnsureAllPathsExist(arguments, CommonLocalizableStrings.CouldNotFindProjectOrDirectory, true); - - var fullProjectPaths = _arguments.Select(p => + try { - var fullPath = Path.GetFullPath(p); - return Directory.Exists(fullPath) ? - MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : - fullPath; - }).ToList(); - - var preAddProjectCount = slnFile.Projects.Count; - - foreach (var fullProjectPath in fullProjectPaths) + PathUtility.EnsureAllPathsExist(_projects, CommonLocalizableStrings.CouldNotFindProjectOrDirectory, true); + IEnumerable fullProjectPaths = _projects.Select(project => + { + var fullPath = Path.GetFullPath(project); + return Directory.Exists(fullPath) ? MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : fullPath; + }); + AddProjectsToSolutionAsync(solutionFileFullPath, fullProjectPaths, CancellationToken.None).Wait(); + return 0; + } + catch (GracefulException) { - // Identify the intended solution folders - var solutionFolders = DetermineSolutionFolder(slnFile, fullProjectPath); - - slnFile.AddProject(fullProjectPath, solutionFolders); + throw; } - - if (slnFile.Projects.Count > preAddProjectCount) + catch (Exception ex) when (ex is not GracefulException) { - slnFile.Write(); + { + if (ex is SolutionException || ex.InnerException is SolutionException) + { + throw new GracefulException(CommonLocalizableStrings.InvalidSolutionFormatString, solutionFileFullPath, ex.Message); + } + throw new GracefulException(ex.Message, ex); + } } - - return 0; } - private static IList GetSolutionFoldersFromProjectPath(string projectFilePath) + private async Task AddProjectsToSolutionAsync(string solutionFileFullPath, IEnumerable projectPaths, CancellationToken cancellationToken) { - var solutionFolders = new List(); - - if (!IsPathInTreeRootedAtSolutionDirectory(projectFilePath)) - return solutionFolders; - - var currentDirString = $".{Path.DirectorySeparatorChar}"; - if (projectFilePath.StartsWith(currentDirString)) + ISolutionSerializer serializer = SlnCommandParser.GetSolutionSerializer(solutionFileFullPath); + SolutionModel solution = await serializer.OpenAsync(solutionFileFullPath, cancellationToken); + // set UTF8 BOM encoding for .sln + if (serializer is ISolutionSerializer v12Serializer) { - projectFilePath = projectFilePath.Substring(currentDirString.Length); + solution.SerializerExtension = v12Serializer.CreateModelExtension(new() + { + Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true) + }); } - - var projectDirectoryPath = TrimProject(projectFilePath); - if (string.IsNullOrEmpty(projectDirectoryPath)) - return solutionFolders; - - var solutionFoldersPath = TrimProjectDirectory(projectDirectoryPath); - if (string.IsNullOrEmpty(solutionFoldersPath)) - return solutionFolders; - - solutionFolders.AddRange(solutionFoldersPath.Split(Path.DirectorySeparatorChar)); - - return solutionFolders; - } - - private IList DetermineSolutionFolder(SlnFile slnFile, string fullProjectPath) - { - if (_inRoot) + // Set default configurations and platforms for sln file + foreach (var platform in new[]{ "Any CPU", "x64", "x86" }) { - // The user requested all projects go to the root folder - return null; + solution.AddPlatform(platform); } - - if (_relativeRootSolutionFolders != null) + foreach (var buildType in new []{ "Debug", "Release" }) { - // The user has specified an explicit root - return _relativeRootSolutionFolders; + solution.AddBuildType(buildType); } - // We determine the root for each individual project - var relativeProjectPath = Path.GetRelativePath( - PathUtility.EnsureTrailingSlash(slnFile.BaseDirectory), - fullProjectPath); + SolutionFolderModel? solutionFolder = (!_inRoot && _solutionFolderPath != null) + ? solution.AddFolder(GetSolutionFolderPathWithForwardSlashes(_solutionFolderPath)) + : null; - return GetSolutionFoldersFromProjectPath(relativeProjectPath); + foreach (var projectPath in projectPaths) + { + string relativePath = Path.GetRelativePath(Path.GetDirectoryName(solutionFileFullPath), projectPath); + try + { + AddProject(solution, relativePath, projectPath, solutionFolder); + } + catch (InvalidProjectFileException ex) + { + Reporter.Error.WriteLine(string.Format(CommonLocalizableStrings.InvalidProjectWithExceptionMessage, projectPath, ex.Message)); + } + catch (SolutionArgumentException ex) when (solution.FindProject(relativePath) != null || ex.Type == SolutionErrorType.DuplicateProjectName) + { + Reporter.Output.WriteLine(CommonLocalizableStrings.SolutionAlreadyContainsProject, solutionFileFullPath, relativePath); + } + } + if (solution.SolutionProjects.Count > 1) + { + // https://stackoverflow.com/a/14714485 + solution.RemoveProperties("HideSolutionNode"); + } + await serializer.SaveAsync(solutionFileFullPath, solution, cancellationToken); } - private static bool IsPathInTreeRootedAtSolutionDirectory(string path) + private void AddProject(SolutionModel solution, string pathRelativeToSolutionFile, string fullPath, SolutionFolderModel solutionFolder) { - return !path.StartsWith(".."); - } + // Open project instance to see if it is a valid project + ProjectRootElement projectRootElement = ProjectRootElement.Open(fullPath); + SolutionProjectModel project; + try + { + project = solution.AddProject(pathRelativeToSolutionFile, null, solutionFolder); + } + catch (SolutionArgumentException ex) when (ex.ParamName == "projectTypeName") + { + // If guid is not identified by vs-solutionpersistence, check in project element itself + var guid = projectRootElement.GetProjectTypeGuid(); + if (string.IsNullOrEmpty(guid)) + { + Reporter.Error.WriteLine(CommonLocalizableStrings.UnsupportedProjectType, fullPath); + return; + } + project = solution.AddProject(pathRelativeToSolutionFile, guid, solutionFolder); + } + // Generate intermediate solution folders + if (solutionFolder is null && !_inRoot) + { + var relativePathDirectory = Path.GetDirectoryName(pathRelativeToSolutionFile); + if (!string.IsNullOrEmpty(relativePathDirectory)) + { + SolutionFolderModel relativeSolutionFolder = solution.AddFolder(GetSolutionFolderPathWithForwardSlashes(relativePathDirectory)); + project.MoveToFolder(relativeSolutionFolder); + // Avoid duplicate folder/project names + if (project.Parent is not null && project.Parent.ActualDisplayName == project.ActualDisplayName) + { + solution.RemoveFolder(project.Parent); + } + } + } + // Add settings based on existing project instance + ProjectInstance projectInstance = new ProjectInstance(projectRootElement); + string projectInstanceId = projectInstance.GetProjectId(); + if (!string.IsNullOrEmpty(projectInstanceId)) + { + project.Id = new Guid(projectInstanceId); + } + var projectInstanceBuildTypes = projectInstance.GetConfigurations(); + var projectInstancePlatforms = projectInstance.GetPlatforms(); - private static string TrimProject(string path) - { - return Path.GetDirectoryName(path); - } + foreach (var solutionPlatform in solution.Platforms) + { + var projectPlatform = projectInstancePlatforms.FirstOrDefault( + x => x.Replace(" ", string.Empty) == solutionPlatform.Replace(" ", string.Empty), projectInstancePlatforms.FirstOrDefault("Any CPU")); + project.AddProjectConfigurationRule(new ConfigurationRule(BuildDimension.Platform, "*", solutionPlatform, projectPlatform)); + } - private static string TrimProjectDirectory(string path) - { - return Path.GetDirectoryName(path); + foreach (var solutionBuildType in solution.BuildTypes) + { + var projectBuildType = projectInstanceBuildTypes.FirstOrDefault( + x => x.Replace(" ", string.Empty) == solutionBuildType.Replace(" ", string.Empty), projectInstanceBuildTypes.FirstOrDefault("Debug")); + project.AddProjectConfigurationRule(new ConfigurationRule(BuildDimension.BuildType, solutionBuildType, "*", projectBuildType)); + } + + Reporter.Output.WriteLine(CommonLocalizableStrings.ProjectAddedToTheSolution, pathRelativeToSolutionFile); } } } diff --git a/test/TestAssets/TestProjects/InvalidSolution/InvalidSolution.slnx b/test/TestAssets/TestProjects/InvalidSolution/InvalidSolution.slnx new file mode 100644 index 000000000000..f19e25b82be9 --- /dev/null +++ b/test/TestAssets/TestProjects/InvalidSolution/InvalidSolution.slnx @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/TestAssets/TestProjects/InvalidSolution/Sln/InvalidSolution.sln b/test/TestAssets/TestProjects/InvalidSolution/Sln/InvalidSolution.sln new file mode 100644 index 000000000000..6527f5d32ab6 --- /dev/null +++ b/test/TestAssets/TestProjects/InvalidSolution/Sln/InvalidSolution.sln @@ -0,0 +1 @@ +This is a test of an invalid solution. diff --git a/test/TestAssets/TestProjects/InvalidSolution/Slnx/InvalidSolution.slnx b/test/TestAssets/TestProjects/InvalidSolution/Slnx/InvalidSolution.slnx new file mode 100644 index 000000000000..f19e25b82be9 --- /dev/null +++ b/test/TestAssets/TestProjects/InvalidSolution/Slnx/InvalidSolution.slnx @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SlnFileWithNoProjectReferencesAndUnknownProjectType/App.slnx b/test/TestAssets/TestProjects/SlnFileWithNoProjectReferencesAndUnknownProjectType/App.slnx new file mode 100644 index 000000000000..70f4bc532c1a --- /dev/null +++ b/test/TestAssets/TestProjects/SlnFileWithNoProjectReferencesAndUnknownProjectType/App.slnx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.sln b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.sln new file mode 100644 index 000000000000..583ce967acdc --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.sln @@ -0,0 +1,47 @@ +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 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "Lib\Lib.csproj", "__LIB_PROJECT_GUID__" +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 + __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.slnx b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.slnx new file mode 100644 index 000000000000..7fcda19ce217 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProj.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.sln b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.sln new file mode 100644 index 000000000000..bb11b322c35d --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.sln @@ -0,0 +1,33 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "Lib\Lib.csproj", "__LIB_PROJECT_GUID__" +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 + __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.slnx b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.slnx new file mode 100644 index 000000000000..0f8bf2b15b63 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingLibProjToEmptySln.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.sln b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.sln new file mode 100644 index 000000000000..c15ad66b40ab --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.sln @@ -0,0 +1,52 @@ +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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "src\Lib\Lib.csproj", "__LIB_PROJECT_GUID__" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "__SRC_FOLDER_GUID__" +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 + __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + __LIB_PROJECT_GUID__ = __SRC_FOLDER_GUID__ + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.slnx b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.slnx new file mode 100644 index 000000000000..96ecc778b697 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingNestedProj.slnx @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.sln b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.sln new file mode 100644 index 000000000000..ea60a2243d15 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.sln @@ -0,0 +1,47 @@ +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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "src\Lib\Lib.csproj", "__LIB_PROJECT_GUID__" +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 + "__LIB_PROJECT_GUID__".Debug|Any CPU.ActiveCfg = Debug|Any CPU + "__LIB_PROJECT_GUID__".Debug|Any CPU.Build.0 = Debug|Any CPU + "__LIB_PROJECT_GUID__".Debug|x64.ActiveCfg = Debug|Any CPU + "__LIB_PROJECT_GUID__".Debug|x64.Build.0 = Debug|Any CPU + "__LIB_PROJECT_GUID__".Debug|x86.ActiveCfg = Debug|Any CPU + "__LIB_PROJECT_GUID__".Debug|x86.Build.0 = Debug|Any CPU + "__LIB_PROJECT_GUID__".Release|Any CPU.ActiveCfg = Release|Any CPU + "__LIB_PROJECT_GUID__".Release|Any CPU.Build.0 = Release|Any CPU + "__LIB_PROJECT_GUID__".Release|x64.ActiveCfg = Release|Any CPU + "__LIB_PROJECT_GUID__".Release|x64.Build.0 = Release|Any CPU + "__LIB_PROJECT_GUID__".Release|x86.ActiveCfg = Release|Any CPU + "__LIB_PROJECT_GUID__".Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.slnx b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.slnx new file mode 100644 index 000000000000..5eb44301b7e2 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithInRootOption.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.sln b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.sln new file mode 100644 index 000000000000..64c7db347050 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.sln @@ -0,0 +1,52 @@ +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}") = "TestFolder", "TestFolder", "__SOLUTION_FOLDER_GUID__" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "src\Lib\Lib.csproj", "__LIB_PROJECT_GUID__" +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 + __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU + __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU + __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + __LIB_PROJECT_GUID__ = __SOLUTION_FOLDER_GUID__ + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.slnx b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.slnx new file mode 100644 index 000000000000..238f33b90636 --- /dev/null +++ b/test/TestAssets/TestProjects/SolutionFilesTemplates/ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption.slnx @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithEmptySln/App.slnx b/test/TestAssets/TestProjects/TestAppWithEmptySln/App.slnx new file mode 100644 index 000000000000..4e2253ddceed --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithEmptySln/App.slnx @@ -0,0 +1 @@ + diff --git a/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App.slnx b/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App.slnx new file mode 100644 index 000000000000..9d9f6a7f5faa --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App2.slnx b/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App2.slnx new file mode 100644 index 000000000000..9d9f6a7f5faa --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithMultipleSlnFiles/App2.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAnd472CsprojFiles/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAnd472CsprojFiles/App.slnx new file mode 100644 index 000000000000..9d9f6a7f5faa --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAnd472CsprojFiles/App.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndCaseSensitiveSolutionFolders/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndCaseSensitiveSolutionFolders/App.slnx new file mode 100644 index 000000000000..3704c0910c8f --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndCaseSensitiveSolutionFolders/App.slnx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/App.slnx new file mode 100644 index 000000000000..9d9f6a7f5faa --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojFiles/App.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDir/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDir/App.slnx new file mode 100644 index 000000000000..1d64de45b461 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDir/App.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDirVS/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDirVS/App.slnx new file mode 100644 index 000000000000..70f4bc532c1a --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojInSubDirVS/App.slnx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojProjectGuidFiles/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojProjectGuidFiles/App.slnx new file mode 100644 index 000000000000..9d9f6a7f5faa --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndCsprojProjectGuidFiles/App.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferences/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferences/App.slnx new file mode 100644 index 000000000000..d44674932ffd --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferences/App.slnx @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep/App.slnx new file mode 100644 index 000000000000..effb93109e33 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep/App.slnx @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.slnx new file mode 100644 index 000000000000..17bc938af284 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.slnx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.sln b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.sln new file mode 100644 index 000000000000..e4fe8f9a3765 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectWithAdditionalConfigs", "ProjectWithAdditionalConfigs\ProjectWithAdditionalConfigs.csproj", "{A302325B-D680-4C0E-8680-7AE283981624}" +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 + Foo Bar|Any CPU = Foo Bar|Any CPU + Foo Bar|x64 = Foo Bar|x64 + Foo Bar|x86 = Foo Bar|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x64.ActiveCfg = Debug|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x64.Build.0 = Debug|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x86.ActiveCfg = Debug|x86 + {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x86.Build.0 = Debug|x86 + {A302325B-D680-4C0E-8680-7AE283981624}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Release|Any CPU.Build.0 = Release|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Release|x64.ActiveCfg = Release|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Release|x64.Build.0 = Release|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Release|x86.ActiveCfg = Release|x86 + {A302325B-D680-4C0E-8680-7AE283981624}.Release|x86.Build.0 = Release|x86 + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|Any CPU.ActiveCfg = FooBar|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|Any CPU.Build.0 = FooBar|Any CPU + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x64.ActiveCfg = FooBar|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x64.Build.0 = FooBar|x64 + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x86.ActiveCfg = FooBar|x86 + {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x86.Build.0 = FooBar|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.slnx new file mode 100644 index 000000000000..740e1b4fed5a --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs.slnx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.sln b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.sln new file mode 100644 index 000000000000..4b5fbb90532f --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectWithMatchingConfigs", "ProjectWithMatchingConfigs\ProjectWithMatchingConfigs.csproj", "{C9601CA2-DB64-4FB6-B463-368C7764BF0D}" +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 + Foo Bar|Any CPU = Foo Bar|Any CPU + Foo Bar|x64 = Foo Bar|x64 + Foo Bar|x86 = Foo Bar|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x64.ActiveCfg = Debug|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x64.Build.0 = Debug|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x86.ActiveCfg = Debug|x86 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x86.Build.0 = Debug|x86 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|Any CPU.Build.0 = Release|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x64.ActiveCfg = Release|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x64.Build.0 = Release|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x86.ActiveCfg = Release|x86 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x86.Build.0 = Release|x86 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|Any CPU.ActiveCfg = FooBar|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|Any CPU.Build.0 = FooBar|Any CPU + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x64.ActiveCfg = FooBar|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x64.Build.0 = FooBar|x64 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x86.ActiveCfg = FooBar|x86 + {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x86.Build.0 = FooBar|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.slnx new file mode 100644 index 000000000000..13d2aa95a9f9 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithMatchingConfigs.slnx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.sln b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.sln new file mode 100644 index 000000000000..e9cc5227b137 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.sln @@ -0,0 +1,42 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectWithoutMatchingConfigs", "ProjectWithoutMatchingConfigs\ProjectWithoutMatchingConfigs.csproj", "{C49B64DE-4401-4825-8A88-10DCB5950E57}" +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 + Foo Bar|Any CPU = Foo Bar|Any CPU + Foo Bar|x64 = Foo Bar|x64 + Foo Bar|x86 = Foo Bar|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x64.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x64.Build.0 = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x86.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x86.Build.0 = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|Any CPU.Build.0 = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x64.ActiveCfg = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x64.Build.0 = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x86.ActiveCfg = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x86.Build.0 = Release|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|Any CPU.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|Any CPU.Build.0 = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x64.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x64.Build.0 = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x86.ActiveCfg = Debug|Any CPU + {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x86.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.slnx new file mode 100644 index 000000000000..48f5fc01aaa2 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/Results/ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs.slnx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.slnx b/test/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.slnx new file mode 100644 index 000000000000..4bda18e4f194 --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.slnx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.slnx b/test/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.slnx new file mode 100644 index 000000000000..70f4bc532c1a --- /dev/null +++ b/test/TestAssets/TestProjects/TestAppsWithSlnAndMultitargetedProjects/TestAppsWithSlnAndMultitargetedProjects.slnx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/dotnet-restore.Tests/GivenThatIWantToRestoreApp.cs b/test/dotnet-restore.Tests/GivenThatIWantToRestoreApp.cs index a2ade77e8345..ff195897c56d 100644 --- a/test/dotnet-restore.Tests/GivenThatIWantToRestoreApp.cs +++ b/test/dotnet-restore.Tests/GivenThatIWantToRestoreApp.cs @@ -27,7 +27,7 @@ public void ItRestoresAppToSpecificDirectory(bool useStaticGraphEvaluation) .WithSource() .Path; - string[] args = new[] { "--packages", fullPath }; + string[] args = new[] { "App.sln", "--packages", fullPath }; args = HandleStaticGraphEvaluation(useStaticGraphEvaluation, args); new DotnetRestoreCommand(Log) .WithWorkingDirectory(projectDirectory) diff --git a/test/dotnet-sln.Tests/GivenDotnetSlnAdd.cs b/test/dotnet-sln.Tests/GivenDotnetSlnAdd.cs index 8c13d746f746..9ef74a6e1023 100644 --- a/test/dotnet-sln.Tests/GivenDotnetSlnAdd.cs +++ b/test/dotnet-sln.Tests/GivenDotnetSlnAdd.cs @@ -5,6 +5,10 @@ using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Tools; using Microsoft.DotNet.Tools.Common; +using Microsoft.VisualStudio.SolutionPersistence.Serializer; +using Microsoft.VisualStudio.SolutionPersistence; +using Microsoft.VisualStudio.SolutionPersistence.Model; +using Microsoft.VisualStudio.SolutionPersistence.Serializer.SlnV12; namespace Microsoft.DotNet.Cli.Sln.Add.Tests { @@ -29,384 +33,6 @@ public GivenDotnetSlnAdd(ITestOutputHelper log) : base(log) { } - private const string ExpectedSlnFileAfterAddingLibProj = @" -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 -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" -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 - __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingLibProjToEmptySln = @" -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26006.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" -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 - __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingNestedProj = @" -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"", ""__SRC_FOLDER_GUID__"" -EndProject -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Lib"", ""src\Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" -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 - __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __SRC_FOLDER_GUID__ - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs = @" -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26006.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ProjectWithoutMatchingConfigs"", ""ProjectWithoutMatchingConfigs\ProjectWithoutMatchingConfigs.csproj"", ""{C49B64DE-4401-4825-8A88-10DCB5950E57}"" -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 - Foo Bar|Any CPU = Foo Bar|Any CPU - Foo Bar|x64 = Foo Bar|x64 - Foo Bar|x86 = Foo Bar|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x64.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x64.Build.0 = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x86.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Debug|x86.Build.0 = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|Any CPU.Build.0 = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x64.ActiveCfg = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x64.Build.0 = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x86.ActiveCfg = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Release|x86.Build.0 = Release|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|Any CPU.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|Any CPU.Build.0 = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x64.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x64.Build.0 = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x86.ActiveCfg = Debug|Any CPU - {C49B64DE-4401-4825-8A88-10DCB5950E57}.Foo Bar|x86.Build.0 = Debug|Any CPU - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingProjectWithMatchingConfigs = @" -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26006.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ProjectWithMatchingConfigs"", ""ProjectWithMatchingConfigs\ProjectWithMatchingConfigs.csproj"", ""{C9601CA2-DB64-4FB6-B463-368C7764BF0D}"" -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 - Foo Bar|Any CPU = Foo Bar|Any CPU - Foo Bar|x64 = Foo Bar|x64 - Foo Bar|x86 = Foo Bar|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x64.ActiveCfg = Debug|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x64.Build.0 = Debug|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x86.ActiveCfg = Debug|x86 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Debug|x86.Build.0 = Debug|x86 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|Any CPU.Build.0 = Release|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x64.ActiveCfg = Release|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x64.Build.0 = Release|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x86.ActiveCfg = Release|x86 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Release|x86.Build.0 = Release|x86 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|Any CPU.ActiveCfg = FooBar|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|Any CPU.Build.0 = FooBar|Any CPU - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x64.ActiveCfg = FooBar|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x64.Build.0 = FooBar|x64 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x86.ActiveCfg = FooBar|x86 - {C9601CA2-DB64-4FB6-B463-368C7764BF0D}.Foo Bar|x86.Build.0 = FooBar|x86 - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs = @" -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26006.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ProjectWithAdditionalConfigs"", ""ProjectWithAdditionalConfigs\ProjectWithAdditionalConfigs.csproj"", ""{A302325B-D680-4C0E-8680-7AE283981624}"" -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 - Foo Bar|Any CPU = Foo Bar|Any CPU - Foo Bar|x64 = Foo Bar|x64 - Foo Bar|x86 = Foo Bar|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x64.ActiveCfg = Debug|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x64.Build.0 = Debug|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x86.ActiveCfg = Debug|x86 - {A302325B-D680-4C0E-8680-7AE283981624}.Debug|x86.Build.0 = Debug|x86 - {A302325B-D680-4C0E-8680-7AE283981624}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Release|Any CPU.Build.0 = Release|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Release|x64.ActiveCfg = Release|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Release|x64.Build.0 = Release|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Release|x86.ActiveCfg = Release|x86 - {A302325B-D680-4C0E-8680-7AE283981624}.Release|x86.Build.0 = Release|x86 - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|Any CPU.ActiveCfg = FooBar|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|Any CPU.Build.0 = FooBar|Any CPU - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x64.ActiveCfg = FooBar|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x64.Build.0 = FooBar|x64 - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x86.ActiveCfg = FooBar|x86 - {A302325B-D680-4C0E-8680-7AE283981624}.Foo Bar|x86.Build.0 = FooBar|x86 - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingProjectWithInRootOption = @" -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(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""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|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x64.Build.0 = Debug|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x86.ActiveCfg = Debug|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Debug|x86.Build.0 = Debug|Any CPU - {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|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x64.Build.0 = Release|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x86.ActiveCfg = Release|Any CPU - {84A45D44-B677-492D-A6DA-B3A71135AB8E}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal -"; - - private const string ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption = @" -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}"") = ""TestFolder"", ""TestFolder"", ""__SOLUTION_FOLDER_GUID__"" -EndProject -Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Lib"", ""src\Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" -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 - __LIB_PROJECT_GUID__.Debug|Any CPU.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|Any CPU.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|Any CPU - __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|Any CPU.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|Any CPU - __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __SOLUTION_FOLDER_GUID__ - EndGlobalSection -EndGlobal -"; - [Theory] [InlineData("sln", "--help")] [InlineData("sln", "-h")] @@ -443,10 +69,10 @@ public void WhenNoCommandIsPassedItPrintsError(string solutionCommand, string co public void WhenTooManyArgumentsArePassedItPrintsError(string solutionCommand) { var cmd = new DotnetCommand(Log) - .Execute(solutionCommand, "one.sln", "two.sln", "three.sln", "add"); + .Execute(solutionCommand, "one.sln", "two.sln", "three.slnx", "add"); cmd.Should().Fail(); cmd.StdErr.Should().BeVisuallyEquivalentTo($@"{string.Format(CommandLineValidation.LocalizableStrings.UnrecognizedCommandOrArgument, "two.sln")} -{string.Format(CommandLineValidation.LocalizableStrings.UnrecognizedCommandOrArgument, "three.sln")}"); +{string.Format(CommandLineValidation.LocalizableStrings.UnrecognizedCommandOrArgument, "three.slnx")}"); } [Theory] @@ -470,57 +96,68 @@ public void WhenNonExistingSolutionIsPassedItPrintsErrorAndUsage(string solution } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("InvalidSolution", identifier: $"{solutionCommand}") + .CopyTestAsset("InvalidSolution", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "InvalidSolution.sln", "add", projectToAdd); + .Execute(solutionCommand, $"InvalidSolution{solutionExtension}", "add", projectToAdd); cmd.Should().Fail(); - cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, "InvalidSolution.sln", LocalizableStrings.FileHeaderMissingError)); + cmd.StdErr.Should().Match(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, Path.Combine(projectDirectory, $"InvalidSolution{solutionExtension}"), "*")); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(""); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenInvalidSolutionIsFoundAddPrintsErrorAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenInvalidSolutionIsFoundAddPrintsErrorAndUsage(string solutionCommand, string solutionExtension) { - var projectDirectory = _testAssetsManager - .CopyTestAsset("InvalidSolution", identifier: $"{solutionCommand}") + var projectDirectoryRoot = _testAssetsManager + .CopyTestAsset("InvalidSolution", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var solutionPath = Path.Combine(projectDirectory, "InvalidSolution.sln"); - var projectToAdd = Path.Combine("Lib", "Lib.csproj"); + var projectDirectory = solutionExtension == ".sln" + ? Path.Join(projectDirectoryRoot, "Sln") + : Path.Join(projectDirectoryRoot, "Slnx"); + + var solutionPath = Path.Combine(projectDirectory, $"InvalidSolution{solutionExtension}"); + var projectToAdd = Path.Combine("..", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) .Execute(solutionCommand, "add", projectToAdd); cmd.Should().Fail(); - cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, solutionPath, LocalizableStrings.FileHeaderMissingError)); + cmd.StdErr.Should().Match(string.Format(CommonLocalizableStrings.InvalidSolutionFormatString, solutionPath, "*")); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(""); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenNoProjectIsPassedItPrintsErrorAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenNoProjectIsPassedItPrintsErrorAndUsage(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add"); + .Execute(solutionCommand, $"App{solutionExtension}", "add"); cmd.Should().Fail(); cmd.StdErr.Should().Be(CommonLocalizableStrings.SpecifyAtLeastOneProjectToAdd); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(""); @@ -532,7 +169,7 @@ public void WhenNoProjectIsPassedItPrintsErrorAndUsage(string solutionCommand) public void WhenNoSolutionExistsInTheDirectoryAddPrintsErrorAndUsage(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}") .WithSource() .Path; @@ -551,7 +188,7 @@ public void WhenNoSolutionExistsInTheDirectoryAddPrintsErrorAndUsage(string solu public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithMultipleSlnFiles", identifier: "GivenDotnetSlnAdd") + .CopyTestAsset("TestAppWithMultipleSlnFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}") .WithSource() .Path; @@ -565,41 +202,50 @@ public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage(str } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenNestedProjectIsAddedSolutionFoldersAreCreated(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenNestedProjectIsAddedSolutionFoldersAreCreated(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); - var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingNestedProj); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); + var expectedSlnContents = GetExpectedSlnContents( + slnPath, + $"ExpectedSlnFileAfterAddingNestedProj{solutionExtension}", + solutionExtension: solutionExtension); + File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute($"build", "App.sln"); + .Execute($"build", $"App{solutionExtension}"); cmd.Should().Pass(); } [Theory] - [InlineData("sln", true)] - [InlineData("sln", false)] - [InlineData("solution", true)] - [InlineData("solution", false)] - public void WhenNestedProjectIsAddedSolutionFoldersAreCreatedBuild(string solutionCommand, bool fooFirst) + [InlineData("sln", true, ".sln")] + [InlineData("sln", false, ".sln")] + [InlineData("solution", true, ".sln")] + [InlineData("solution", false, ".sln")] + [InlineData("sln", true, ".slnx")] + [InlineData("solution", false, ".slnx")] + public void WhenNestedProjectIsAddedSolutionFoldersAreCreatedBuild(string solutionCommand, bool fooFirst, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDirVS", identifier: $"{solutionCommand}{fooFirst}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDirVS", identifier: $"GivenDotnetSlnAdd{solutionCommand}{fooFirst}{solutionExtension}") .WithSource() .Path; string projectToAdd; @@ -610,14 +256,14 @@ public void WhenNestedProjectIsAddedSolutionFoldersAreCreatedBuild(string soluti projectToAdd = "foo"; cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); } projectToAdd = Path.Combine("foo", "bar"); cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); if (!fooFirst) @@ -625,24 +271,24 @@ public void WhenNestedProjectIsAddedSolutionFoldersAreCreatedBuild(string soluti projectToAdd = "foo"; cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); } cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute($"build", "App.sln"); + .Execute($"build", $"App{solutionExtension}"); cmd.Should().Pass(); } - [Theory] + [Theory(Skip = "Having projects with the same name in different paths is allowed.")] [InlineData("sln")] [InlineData("solution")] public void WhenNestedDuplicateProjectIsAddedToASolutionFolder(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDirVSErrors", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDirVSErrors", identifier: $"GivenDotnetSlnAdd-{solutionCommand}") .WithSource() .Path; string projectToAdd; @@ -666,47 +312,54 @@ public void WhenNestedDuplicateProjectIsAddedToASolutionFolder(string solutionCo } [Theory] - [InlineData("sln", "TestAppWithSlnAndCsprojFiles")] - [InlineData("sln", "TestAppWithSlnAnd472CsprojFiles")] - [InlineData("solution", "TestAppWithSlnAndCsprojFiles")] - [InlineData("solution", "TestAppWithSlnAnd472CsprojFiles")] - public void WhenDirectoryContainingProjectIsGivenProjectIsAdded(string solutionCommand, string testAsset) + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("sln", "TestAppWithSlnAnd472CsprojFiles", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("solution", "TestAppWithSlnAnd472CsprojFiles", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".slnx")] + [InlineData("solution", "TestAppWithSlnAnd472CsprojFiles", ".slnx")] + public void WhenDirectoryContainingProjectIsGivenProjectIsAdded(string solutionCommand, string testAsset, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, identifier: $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}{solutionExtension}") .WithSource() .Path; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "add", "Lib"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "Lib"); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); - var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingLibProj); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); + + var expectedSlnContents = GetExpectedSlnContents( + slnPath, + $"ExpectedSlnFileAfterAddingLibProj{solutionExtension}", solutionExtension: solutionExtension); File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(projectDirectory, "App.sln"); + var slnFullPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); var contentBefore = File.ReadAllText(slnFullPath); var directoryToAdd = "Empty"; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "add", directoryToAdd); + .Execute(solutionCommand, "App.sln", "add", directoryToAdd); cmd.Should().Fail(); - cmd.StdErr.Should().Be( + cmd.StdErr.Should().Contain( string.Format( CommonLocalizableStrings.CouldNotFindAnyProjectInDirectory, Path.Combine(projectDirectory, directoryToAdd))); @@ -716,24 +369,26 @@ public void WhenDirectoryContainsNoProjectsItCancelsWholeOperation(string soluti } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(projectDirectory, "App.sln"); + var slnFullPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); var contentBefore = File.ReadAllText(slnFullPath); var directoryToAdd = "Multiple"; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "add", directoryToAdd); + .Execute(solutionCommand, "App.sln", "add", directoryToAdd); cmd.Should().Fail(); - cmd.StdErr.Should().Be( + cmd.StdErr.Should().Contain( string.Format( CommonLocalizableStrings.MoreThanOneProjectInDirectory, Path.Combine(projectDirectory, directoryToAdd))); @@ -743,137 +398,147 @@ public void WhenDirectoryContainsMultipleProjectsItCancelsWholeOperation(string } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectDirectoryIsAddedSolutionFoldersAreNotCreated(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public async Task WhenProjectDirectoryIsAddedSolutionFoldersAreNotCreated(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); - var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - var solutionFolderProjects = slnFile.Projects.Where( - p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); - solutionFolderProjects.Count().Should().Be(0); - slnFile.Sections.GetSection("NestedProjects").Should().BeNull(); + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Combine(projectDirectory, $"App{solutionExtension}")); + SolutionModel solution = await serializer.OpenAsync(Path.Combine(projectDirectory, $"App{solutionExtension}"), CancellationToken.None); + + solution.SolutionFolders.Count().Should().Be(0); + solution.SolutionProjects + .Where(p => p.Parent != null) + .Count() + .Should().Be(0); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSharedProjectAddedShouldStillBuild(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenSharedProjectAddedShouldStillBuild(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("Shared", "Shared.shproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); cmd.StdErr.Should().BeEmpty(); - cmd = new DotnetBuildCommand(Log) + cmd = new DotnetBuildCommand(Log, $"App{solutionExtension}") .WithWorkingDirectory(projectDirectory) .Execute(); cmd.Should().Pass(); } [Theory] - [InlineData("sln", ".")] - [InlineData("sln", "")] - [InlineData("solution", ".")] - [InlineData("solution", "")] - public void WhenSolutionFolderExistsItDoesNotGetAdded(string solutionCommand, string firstComponent) + [InlineData("sln", ".", ".sln")] + [InlineData("sln", "", ".sln")] + [InlineData("solution", ".", ".sln")] + [InlineData("solution", "", ".sln")] + [InlineData("sln", ".", ".slnx")] + [InlineData("solution", "", ".slnx")] + public async Task WhenSolutionFolderExistsItDoesNotGetAdded(string solutionCommand, string firstComponent, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndSolutionFolders", identifier: $"{solutionCommand}{firstComponent}") + .CopyTestAsset("TestAppWithSlnAndSolutionFolders", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{firstComponent}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine($"{firstComponent}", "src", "src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); - var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - slnFile.Projects.Count().Should().Be(4); + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Combine(projectDirectory, $"App{solutionExtension}")); + SolutionModel solution = await serializer.OpenAsync(Path.Combine(projectDirectory, $"App{solutionExtension}"), CancellationToken.None); - var solutionFolderProjects = slnFile.Projects.Where( - p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); - solutionFolderProjects.Count().Should().Be(2); + solution.SolutionItems.Count().Should().Be(4); + solution.SolutionFolders.Count().Should().Be(2); - var solutionFolders = slnFile.Sections.GetSection("NestedProjects").Properties; - solutionFolders.Count.Should().Be(3); + solution.SolutionItems.Where(item => item.Parent != null).Count().Should().Be(3); - solutionFolders["{DDF3765C-59FB-4AA6-BE83-779ED13AA64A}"] - .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); + var newlyAddedSrcFolder = solution.SolutionFolders.Single(p => p.Parent != null); + newlyAddedSrcFolder.Parent.Id.Should().Be(solution.SolutionFolders.Single(p => p.Parent == null).Id); - var newlyAddedSrcFolder = solutionFolderProjects.Single(p => p.Id != "{72BFCA87-B033-4721-8712-4D12166B4A39}"); - solutionFolders[newlyAddedSrcFolder.Id] - .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); - - var libProject = slnFile.Projects.Single(p => p.Name == "Lib"); - solutionFolders[libProject.Id] - .Should().Be(newlyAddedSrcFolder.Id); + var libProject = solution.SolutionProjects.Single(p => p.ActualDisplayName.Contains("Lib")); + libProject.Parent.Id.Should().Be(newlyAddedSrcFolder.Id); } [Theory] - [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ExpectedSlnFileAfterAddingLibProj, "")] - [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles", ExpectedSlnFileAfterAddingLibProj, "{84A45D44-B677-492D-A6DA-B3A71135AB8E}")] - [InlineData("sln", "TestAppWithEmptySln", ExpectedSlnFileAfterAddingLibProjToEmptySln, "")] - [InlineData("solution", "TestAppWithSlnAndCsprojFiles", ExpectedSlnFileAfterAddingLibProj, "")] - [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ExpectedSlnFileAfterAddingLibProj, "{84A45D44-B677-492D-A6DA-B3A71135AB8E}")] - [InlineData("solution", "TestAppWithEmptySln", ExpectedSlnFileAfterAddingLibProjToEmptySln, "")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", "ExpectedSlnFileAfterAddingLibProj", "", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles", "ExpectedSlnFileAfterAddingLibProj", "84a45d44-b677-492d-a6da-b3a71135ab8e", ".sln")] + [InlineData("sln", "TestAppWithEmptySln", "ExpectedSlnFileAfterAddingLibProjToEmptySln", "", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojFiles", "ExpectedSlnFileAfterAddingLibProj", "", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", "ExpectedSlnFileAfterAddingLibProj", "84a45d44-b677-492d-a6da-b3a71135ab8e", ".sln")] + [InlineData("solution", "TestAppWithEmptySln", "ExpectedSlnFileAfterAddingLibProjToEmptySln", "", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", "ExpectedSlnFileAfterAddingLibProj", "", ".slnx")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", "ExpectedSlnFileAfterAddingLibProj", "84a45d44-b677-492d-a6da-b3a71135ab8e", ".slnx")] + [InlineData("solution", "TestAppWithEmptySln", "ExpectedSlnFileAfterAddingLibProjToEmptySln", "", ".slnx")] public void WhenValidProjectIsPassedBuildConfigsAreAdded( string solutionCommand, string testAsset, string expectedSlnContentsTemplate, - string expectedProjectGuid) + string expectedProjectGuid, + string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}") .WithSource() .Path; var projectToAdd = "Lib/Lib.csproj"; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); var expectedSlnContents = GetExpectedSlnContents( slnPath, - expectedSlnContentsTemplate, - expectedProjectGuid); + $"{expectedSlnContentsTemplate}{solutionExtension}", + expectedProjectGuid, + solutionExtension: solutionExtension); File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); } [Theory] - [InlineData("sln", "TestAppWithSlnAndCsprojFiles")] - [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("sln", "TestAppWithEmptySln")] - [InlineData("solution", "TestAppWithSlnAndCsprojFiles")] - [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("solution", "TestAppWithEmptySln")] - public void WhenValidProjectIsPassedItGetsAdded(string solutionCommand, string testAsset) + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("sln", "TestAppWithEmptySln", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("solution", "TestAppWithEmptySln", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".slnx")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".slnx")] + [InlineData("solution", "TestAppWithEmptySln", ".slnx")] + public void WhenValidProjectIsPassedItGetsAdded(string solutionCommand, string testAsset, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, identifier: $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}{solutionExtension}") .WithSource() .Path; @@ -881,7 +546,7 @@ public void WhenValidProjectIsPassedItGetsAdded(string solutionCommand, string t var projectPath = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAddedToTheSolution, projectPath)); cmd.StdErr.Should().BeEmpty(); @@ -893,7 +558,7 @@ public void WhenValidProjectIsPassedItGetsAdded(string solutionCommand, string t public void WhenProjectIsAddedSolutionHasUTF8BOM(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithEmptySln", $"{solutionCommand}") + .CopyTestAsset("TestAppWithEmptySln", $"GivenDotnetSlnAdd-{solutionCommand}") .WithSource() .Path; @@ -916,63 +581,72 @@ public void WhenProjectIsAddedSolutionHasUTF8BOM(string solutionCommand) } [Theory] - [InlineData("sln", "TestAppWithSlnAndCsprojFiles")] - [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("sln", "TestAppWithEmptySln")] - [InlineData("solution", "TestAppWithSlnAndCsprojFiles")] - [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("solution", "TestAppWithEmptySln")] - public void WhenInvalidProjectIsPassedItDoesNotGetAdded(string solutionCommand, string testAsset) + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("sln", "TestAppWithEmptySln", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("solution", "TestAppWithEmptySln", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".slnx")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".slnx")] + [InlineData("solution", "TestAppWithEmptySln", ".slnx")] + public async Task WhenInvalidProjectIsPassedItDoesNotGetAdded(string solutionCommand, string testAsset, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}{solutionExtension}") .WithSource() .Path; var projectToAdd = "Lib/Library.cs"; - var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - var expectedNumberOfProjects = slnFile.Projects.Count(); + + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Combine(projectDirectory, $"App{solutionExtension}")); + SolutionModel solution = await serializer.OpenAsync(Path.Combine(projectDirectory, $"App{solutionExtension}"), CancellationToken.None); + + var expectedNumberOfProjects = solution.SolutionProjects.Count(); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); cmd.StdOut.Should().BeEmpty(); cmd.StdErr.Should().Match(string.Format(CommonLocalizableStrings.InvalidProjectWithExceptionMessage, '*', '*')); - slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - slnFile.Projects.Count().Should().Be(expectedNumberOfProjects); + solution = await serializer.OpenAsync(Path.Combine(projectDirectory, $"App{solutionExtension}"), CancellationToken.None); + solution.SolutionProjects.Count().Should().Be(expectedNumberOfProjects); } [Theory] - [InlineData("sln", "TestAppWithSlnAndCsprojFiles")] - [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("sln", "TestAppWithEmptySln")] - [InlineData("solution", "TestAppWithSlnAndCsprojFiles")] - [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles")] - [InlineData("solution", "TestAppWithEmptySln")] - public void WhenValidProjectIsPassedTheSlnBuilds(string solutionCommand, string testAsset) + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("sln", "TestAppWithEmptySln", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojFiles", ".sln")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".sln")] + [InlineData("solution", "TestAppWithEmptySln", ".sln")] + [InlineData("sln", "TestAppWithSlnAndCsprojFiles", ".slnx")] + [InlineData("solution", "TestAppWithSlnAndCsprojProjectGuidFiles", ".slnx")] + [InlineData("solution", "TestAppWithEmptySln", ".slnx")] + public void WhenValidProjectIsPassedTheSlnBuilds(string solutionCommand, string testAsset, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, identifier: $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}{solutionExtension}") .WithSource() .Path; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", "App/App.csproj", "Lib/Lib.csproj"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "App/App.csproj", "Lib/Lib.csproj"); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute($"restore", "App.sln") + .Execute($"restore", $"App{solutionExtension}") .Should().Pass(); new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute("build", "App.sln", "--configuration", "Release") + .Execute("build", $"App{solutionExtension}", "--configuration", "Release") .Should().Pass(); var reasonString = "should be built in release mode, otherwise it means build configurations are missing from the sln file"; @@ -989,44 +663,47 @@ public void WhenValidProjectIsPassedTheSlnBuilds(string solutionCommand, string } [Theory] - [InlineData("sln", "TestAppWithSlnAndExistingCsprojReferences")] - [InlineData("sln", "TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep")] - [InlineData("solution", "TestAppWithSlnAndExistingCsprojReferences")] - [InlineData("solution", "TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep")] - public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate(string solutionCommand, string testAsset) + [InlineData("sln", "TestAppWithSlnAndExistingCsprojReferences", ".sln")] + [InlineData("sln", "TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep", ".sln")] + [InlineData("solution", "TestAppWithSlnAndExistingCsprojReferences", ".sln")] + [InlineData("solution", "TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep", ".sln")] + [InlineData("sln", "TestAppWithSlnAndExistingCsprojReferences", ".slnx")] + [InlineData("solution", "TestAppWithSlnAndExistingCsprojReferencesWithEscapedDirSep", ".slnx")] + public void WhenSolutionAlreadyContainsProjectItDoesntDuplicate(string solutionCommand, string testAsset, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, identifier: $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}{solutionExtension}") .WithSource() .Path; - var solutionPath = Path.Combine(projectDirectory, "App.sln"); + var solutionPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.SolutionAlreadyContainsProject, solutionPath, projectToAdd)); - cmd.StdErr.Should().BeEmpty(); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOperation(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(projectDirectory, "App.sln"); + var slnFullPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); var contentBefore = File.ReadAllText(slnFullPath); var projectToAdd = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd, "idonotexist.csproj"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd, "idonotexist.csproj"); cmd.Should().Fail(); cmd.StdErr.Should().Be(string.Format(CommonLocalizableStrings.CouldNotFindProjectOrDirectory, "idonotexist.csproj")); @@ -1040,7 +717,7 @@ public void WhenPassedMultipleProjectsAndOneOfthemDoesNotExistItCancelsWholeOper public void WhenPassedAnUnknownProjectTypeItFails(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("SlnFileWithNoProjectReferencesAndUnknownProject", identifier: $"{solutionCommand}") + .CopyTestAsset("SlnFileWithNoProjectReferencesAndUnknownProject", identifier: $"GivenDotnetSlnAdd-{solutionCommand}") .WithSource() .Path; @@ -1058,6 +735,7 @@ public void WhenPassedAnUnknownProjectTypeItFails(string solutionCommand) .Should().BeVisuallyEquivalentTo(contentBefore); } + // SLN ONLY [Theory] [InlineData("sln", "SlnFileWithNoProjectReferencesAndCSharpProject", "CSharpProject", "CSharpProject.csproj", ProjectTypeGuids.CSharpProjectTypeGuid)] [InlineData("sln", "SlnFileWithNoProjectReferencesAndFSharpProject", "FSharpProject", "FSharpProject.fsproj", ProjectTypeGuids.FSharpProjectTypeGuid)] @@ -1069,7 +747,7 @@ public void WhenPassedAnUnknownProjectTypeItFails(string solutionCommand) [InlineData("solution", "SlnFileWithNoProjectReferencesAndVBProject", "VBProject", "VBProject.vbproj", ProjectTypeGuids.VBProjectTypeGuid)] [InlineData("solution", "SlnFileWithNoProjectReferencesAndUnknownProjectWithSingleProjectTypeGuid", "UnknownProject", "UnknownProject.unknownproj", "{130159A9-F047-44B3-88CF-0CF7F02ED50F}")] [InlineData("solution", "SlnFileWithNoProjectReferencesAndUnknownProjectWithMultipleProjectTypeGuids", "UnknownProject", "UnknownProject.unknownproj", "{130159A9-F047-44B3-88CF-0CF7F02ED50F}")] - public void WhenPassedAProjectItAddsCorrectProjectTypeGuid( + public async Task WhenPassedAProjectItAddsCorrectProjectTypeGuid( string solutionCommand, string testAsset, string projectDir, @@ -1077,7 +755,7 @@ public void WhenPassedAProjectItAddsCorrectProjectTypeGuid( string expectedTypeGuid) { var projectDirectory = _testAssetsManager - .CopyTestAsset(testAsset, identifier: $"{solutionCommand}{testAsset}") + .CopyTestAsset(testAsset, identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testAsset}") .WithSource() .Path; @@ -1089,30 +767,32 @@ public void WhenPassedAProjectItAddsCorrectProjectTypeGuid( cmd.StdErr.Should().BeEmpty(); cmd.StdOut.Should().Be(string.Format(CommonLocalizableStrings.ProjectAddedToTheSolution, projectToAdd)); - var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - var nonSolutionFolderProjects = slnFile.Projects.Where( - p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid); + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Combine(projectDirectory, "App.sln")); + SolutionModel solution = await serializer.OpenAsync(Path.Combine(projectDirectory, "App.sln"), CancellationToken.None); + var nonSolutionFolderProjects = solution.SolutionProjects; nonSolutionFolderProjects.Count().Should().Be(1); - nonSolutionFolderProjects.Single().TypeGuid.Should().Be(expectedTypeGuid); + nonSolutionFolderProjects.Single().TypeId.Should().Be(new Guid(expectedTypeGuid)); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenPassedAProjectWithoutATypeGuidItErrors(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenPassedAProjectWithoutATypeGuidItErrors(string solutionCommand, string solutionExtension) { var solutionDirectory = _testAssetsManager - .CopyTestAsset("SlnFileWithNoProjectReferencesAndUnknownProjectType", identifier: $"{solutionCommand}") + .CopyTestAsset("SlnFileWithNoProjectReferencesAndUnknownProjectType", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var solutionPath = Path.Combine(solutionDirectory, "App.sln"); + var solutionPath = Path.Combine(solutionDirectory, $"App{solutionExtension}"); var contentBefore = File.ReadAllText(solutionPath); var projectToAdd = Path.Combine("UnknownProject", "UnknownProject.unknownproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(solutionDirectory) - .Execute(solutionCommand, "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); cmd.StdErr.Should().Be( string.Format( @@ -1126,97 +806,112 @@ public void WhenPassedAProjectWithoutATypeGuidItErrors(string solutionCommand) } [Theory] - [InlineData("sln")] - [InlineData("solution")] - private void WhenSlnContainsSolutionFolderWithDifferentCasingItDoesNotCreateDuplicate(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + private async Task WhenSlnContainsSolutionFolderWithDifferentCasingItDoesNotCreateDuplicate(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCaseSensitiveSolutionFolders", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCaseSensitiveSolutionFolders", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd); cmd.Should().Pass(); - var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); - var solutionFolderProjects = slnFile.Projects.Where( - p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); - solutionFolderProjects.Count().Should().Be(1); + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Combine(projectDirectory, $"App{solutionExtension}")); + SolutionModel solution = await serializer.OpenAsync(Path.Combine(projectDirectory, $"App{solutionExtension}"), CancellationToken.None); + solution.SolutionFolders.Count().Should().Be(1); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectWithoutMatchingConfigurationsIsAddedSolutionMapsToFirstAvailable(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenProjectWithoutMatchingConfigurationsIsAddedSolutionMapsToFirstAvailable(string solutionCommand, string solutionExtension) { var slnDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(slnDirectory, "App.sln"); + var slnFullPath = Path.Combine(slnDirectory, $"App{solutionExtension}"); var result = new DotnetCommand(Log) .WithWorkingDirectory(slnDirectory) - .Execute(solutionCommand, "add", "ProjectWithoutMatchingConfigs"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "ProjectWithoutMatchingConfigs"); result.Should().Pass(); + var expectedResult = File.ReadAllText(Path.Combine(slnDirectory, "Results", $"ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs{solutionExtension}")); + File.ReadAllText(slnFullPath) - .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs); + .Should().BeVisuallyEquivalentTo(expectedResult); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectWithMatchingConfigurationsIsAddedSolutionMapsAll(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenProjectWithMatchingConfigurationsIsAddedSolutionMapsAll(string solutionCommand, string solutionExtension) { var slnDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(slnDirectory, "App.sln"); + var slnFullPath = Path.Combine(slnDirectory, $"App{solutionExtension}"); var result = new DotnetCommand(Log) .WithWorkingDirectory(slnDirectory) - .Execute(solutionCommand, "add", "ProjectWithMatchingConfigs"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "ProjectWithMatchingConfigs"); result.Should().Pass(); + var expectedResult = File.ReadAllText(Path.Combine(slnDirectory, "Results", $"ExpectedSlnFileAfterAddingProjectWithMatchingConfigs{solutionExtension}")); + File.ReadAllText(slnFullPath) - .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithMatchingConfigs); + .Should().BeVisuallyEquivalentTo(expectedResult); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectWithAdditionalConfigurationsIsAddedSolutionDoesNotMapThem(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenProjectWithAdditionalConfigurationsIsAddedSolutionDoesNotMapThem(string solutionCommand, string solutionExtension) { var slnDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndProjectConfigs", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFullPath = Path.Combine(slnDirectory, "App.sln"); + var slnFullPath = Path.Combine(slnDirectory, $"App{solutionExtension}"); var result = new DotnetCommand(Log) .WithWorkingDirectory(slnDirectory) - .Execute(solutionCommand, "add", "ProjectWithAdditionalConfigs"); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "ProjectWithAdditionalConfigs"); result.Should().Pass(); + var expectedResult = File.ReadAllText(Path.Combine(slnDirectory, "Results", $"ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs{solutionExtension}")); + File.ReadAllText(slnFullPath) - .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs); + .Should().BeVisuallyEquivalentTo(expectedResult); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void ItAddsACSharpProjectThatIsMultitargeted(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void ItAddsACSharpProjectThatIsMultitargeted(string solutionCommand, string solutionExtension) { var solutionDirectory = _testAssetsManager - .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; @@ -1224,7 +919,7 @@ public void ItAddsACSharpProjectThatIsMultitargeted(string solutionCommand) new DotnetCommand(Log) .WithWorkingDirectory(solutionDirectory) - .Execute(solutionCommand, "add", projectToAdd) + .Execute(solutionCommand, $"TestAppsWithSlnAndMultitargetedProjects{solutionExtension}", "add", projectToAdd) .Should() .Pass() .And @@ -1232,12 +927,14 @@ public void ItAddsACSharpProjectThatIsMultitargeted(string solutionCommand) } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void ItAddsAVisualBasicProjectThatIsMultitargeted(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void ItAddsAVisualBasicProjectThatIsMultitargeted(string solutionCommand, string solutionExtension) { var solutionDirectory = _testAssetsManager - .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; @@ -1245,7 +942,7 @@ public void ItAddsAVisualBasicProjectThatIsMultitargeted(string solutionCommand) new DotnetCommand(Log) .WithWorkingDirectory(solutionDirectory) - .Execute(solutionCommand, "add", projectToAdd) + .Execute(solutionCommand, $"TestAppsWithSlnAndMultitargetedProjects{solutionExtension}", "add", projectToAdd) .Should() .Pass() .And @@ -1253,12 +950,14 @@ public void ItAddsAVisualBasicProjectThatIsMultitargeted(string solutionCommand) } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void ItAddsAnFSharpProjectThatIsMultitargeted(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void ItAddsAnFSharpProjectThatIsMultitargeted(string solutionCommand, string solutionExtension) { var solutionDirectory = _testAssetsManager - .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppsWithSlnAndMultitargetedProjects", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; @@ -1267,7 +966,7 @@ public void ItAddsAnFSharpProjectThatIsMultitargeted(string solutionCommand) new DotnetCommand(Log) .WithWorkingDirectory(solutionDirectory) - .Execute(solutionCommand, "add", projectToAdd) + .Execute(solutionCommand, $"TestAppsWithSlnAndMultitargetedProjects{solutionExtension}", "add", projectToAdd) .Should() .Pass() .And @@ -1275,66 +974,79 @@ public void ItAddsAnFSharpProjectThatIsMultitargeted(string solutionCommand) } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenNestedProjectIsAddedAndInRootOptionIsPassedNoSolutionFoldersAreCreated(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenNestedProjectIsAddedAndInRootOptionIsPassedNoSolutionFoldersAreCreated(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", "--in-root", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "--in-root", projectToAdd); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); - var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingProjectWithInRootOption); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); + + var expectedSlnContents = GetExpectedSlnContents( + slnPath, + $"ExpectedSlnFileAfterAddingProjectWithInRootOption{solutionExtension}", + solutionExtension: solutionExtension); File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSolutionFolderIsPassedProjectsAreAddedThere(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenSolutionFolderIsPassedProjectsAreAddedThere(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", "--solution-folder", "TestFolder", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "--solution-folder", "TestFolder", projectToAdd); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); - var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); + + var expectedSlnContents = GetExpectedSlnContents( + slnPath, + $"ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption{solutionExtension}", + solutionExtension: solutionExtension); File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSolutionFolderAndInRootIsPassedItFails(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenSolutionFolderAndInRootIsPassedItFails(string solutionCommand, string solutionExtension) { var solutionDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"{solutionCommand}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var solutionPath = Path.Combine(solutionDirectory, "App.sln"); + var solutionPath = Path.Combine(solutionDirectory, $"App{solutionExtension}"); var contentBefore = File.ReadAllText(solutionPath); var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(solutionDirectory) - .Execute(solutionCommand, "App.sln", "add", "--solution-folder", "blah", "--in-root", projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "--solution-folder", "blah", "--in-root", projectToAdd); cmd.Should().Fail(); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(""); cmd.StdErr.Should().Be(Tools.Sln.LocalizableStrings.SolutionFolderAndInRootMutuallyExclusive); @@ -1346,108 +1058,150 @@ public void WhenSolutionFolderAndInRootIsPassedItFails(string solutionCommand) } [Theory] - [InlineData("sln", "/TestFolder//", "ForwardSlash")] - [InlineData("sln", "\\TestFolder\\\\", "BackwardSlash")] - [InlineData("solution", "/TestFolder//", "ForwardSlash")] - [InlineData("solution", "\\TestFolder\\\\", "BackwardSlash")] - public void WhenSolutionFolderIsPassedWithDirectorySeparatorFolderStructureIsCorrect(string solutionCommand, string solutionFolder, string testIdentifier) + [InlineData("sln", "/TestFolder//", "ForwardSlash", ".sln")] + [InlineData("sln", "\\TestFolder\\\\", "BackwardSlash", ".sln")] + [InlineData("solution", "/TestFolder//", "ForwardSlash", ".sln")] + [InlineData("solution", "\\TestFolder\\\\", "BackwardSlash", ".sln")] + + [InlineData("sln", "/TestFolder//", "ForwardSlash", ".slnx")] + [InlineData("solution", "\\TestFolder\\\\", "BackwardSlash", ".slnx")] + public void WhenSolutionFolderIsPassedWithDirectorySeparatorFolderStructureIsCorrect(string solutionCommand, string solutionFolder, string testIdentifier, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"{solutionCommand}{testIdentifier}") + .CopyTestAsset("TestAppWithSlnAndCsprojInSubDir", identifier: $"GivenDotnetSlnAdd-{solutionCommand}{testIdentifier}{solutionExtension}") .WithSource() .Path; var projectToAdd = Path.Combine("src", "Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "App.sln", "add", "--solution-folder", solutionFolder, projectToAdd); + .Execute(solutionCommand, $"App{solutionExtension}", "add", "--solution-folder", solutionFolder, projectToAdd); cmd.Should().Pass(); - var slnPath = Path.Combine(projectDirectory, "App.sln"); - var expectedSlnContents = GetExpectedSlnContents(slnPath, ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption); + var slnPath = Path.Combine(projectDirectory, $"App{solutionExtension}"); + + var expectedSlnContents = GetExpectedSlnContents( + slnPath, + $"ExpectedSlnFileAfterAddingProjectWithSolutionFolderOption{solutionExtension}", + solutionExtension: solutionExtension); File.ReadAllText(slnPath) .Should().BeVisuallyEquivalentTo(expectedSlnContents); } private string GetExpectedSlnContents( string slnPath, - string slnTemplate, - string expectedLibProjectGuid = null) + string slnTemplateName, + string expectedLibProjectGuid = null, + string solutionExtension = ".sln") { - var slnFile = SlnFile.Read(slnPath); + var slnTemplate = GetSolutionFileTemplateContents(slnTemplateName); + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(slnPath); + SolutionModel solution = serializer.OpenAsync(slnPath, CancellationToken.None).Result; if (string.IsNullOrEmpty(expectedLibProjectGuid)) { - var matchingProjects = slnFile.Projects - .Where((p) => p.FilePath.EndsWith("Lib.csproj")) + var matchingProjects = solution.SolutionProjects + .Where(p => p.FilePath.EndsWith("Lib.csproj")) .ToList(); matchingProjects.Count.Should().Be(1); var slnProject = matchingProjects[0]; - expectedLibProjectGuid = slnProject.Id; + expectedLibProjectGuid = slnProject.Id.ToString(); } - var slnContents = slnTemplate.Replace("__LIB_PROJECT_GUID__", expectedLibProjectGuid); - var matchingSrcFolder = slnFile.Projects - .Where((p) => p.FilePath == "src") - .ToList(); + var slnContents = slnTemplate.Replace( + "__LIB_PROJECT_GUID__", + solutionExtension == ".sln" + ? $"{{{expectedLibProjectGuid.ToUpper()}}}" + : expectedLibProjectGuid); + + var matchingSrcFolder = solution.SolutionFolders + .Where(p => p.Path.Contains("src")) + .ToList(); if (matchingSrcFolder.Count == 1) { - slnContents = slnContents.Replace("__SRC_FOLDER_GUID__", matchingSrcFolder[0].Id); + slnContents = slnContents.Replace( + "__SRC_FOLDER_GUID__", + solutionExtension == ".sln" + ? $"{{{matchingSrcFolder[0].Id.ToString().ToUpper()}}}" + : matchingSrcFolder[0].Id.ToString()); } - var matchingSolutionFolder = slnFile.Projects - .Where((p) => p.FilePath == "TestFolder") - .ToList(); + var matchingSolutionFolder = solution.SolutionFolders + .Where(p => p.Path.Contains("TestFolder")) + .ToList(); if (matchingSolutionFolder.Count == 1) { - slnContents = slnContents.Replace("__SOLUTION_FOLDER_GUID__", matchingSolutionFolder[0].Id); + slnContents = slnContents.Replace( + "_SOLUTION_FOLDER_GUID__", + solutionExtension == ".sln" + ? $"{{{matchingSolutionFolder[0].Id.ToString().ToUpper()}}}" + : matchingSolutionFolder[0].Id.ToString()); } return slnContents; } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSolutionIsPassedAsProjectItPrintsSuggestionAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + public void WhenSolutionIsPassedAsProjectItPrintsSuggestionAndUsage(string solutionCommand, string solutionExtension) { - VerifySuggestionAndUsage(solutionCommand, ""); + VerifySuggestionAndUsage(solutionCommand, "", solutionExtension); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSolutionIsPassedAsProjectWithInRootItPrintsSuggestionAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + public void WhenSolutionIsPassedAsProjectWithInRootItPrintsSuggestionAndUsage(string solutionCommand, string solutionExtension) { - VerifySuggestionAndUsage(solutionCommand, "--in-root"); + VerifySuggestionAndUsage(solutionCommand, "--in-root", solutionExtension); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenSolutionIsPassedAsProjectWithSolutionFolderItPrintsSuggestionAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + public void WhenSolutionIsPassedAsProjectWithSolutionFolderItPrintsSuggestionAndUsage(string solutionCommand, string solutionExtension) { - VerifySuggestionAndUsage(solutionCommand, "--solution-folder"); + VerifySuggestionAndUsage(solutionCommand, "--solution-folder", solutionExtension); } - private void VerifySuggestionAndUsage(string solutionCommand, string arguments) + private void VerifySuggestionAndUsage(string solutionCommand, string arguments, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}{arguments}") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"{solutionCommand}{arguments}{solutionExtension}") .WithSource() .Path; + // TODO: Move to different location + if (solutionExtension == ".sln") + { + File.Delete(Path.Join(projectDirectory, "App.slnx")); + } + else if (solutionExtension == ".slnx") + { + File.Delete(Path.Join(projectDirectory, "App.sln")); + } + var projectArg = Path.Combine("Lib", "Lib.csproj"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "add", arguments, "Lib", "App.sln", projectArg); + .Execute(solutionCommand, "add", arguments, "Lib", $"App{solutionExtension}", projectArg); cmd.Should().Fail(); cmd.StdErr.Should().BeVisuallyEquivalentTo( - string.Format(CommonLocalizableStrings.SolutionArgumentMisplaced, "App.sln") + Environment.NewLine + string.Format(CommonLocalizableStrings.SolutionArgumentMisplaced, $"App{solutionExtension}") + Environment.NewLine + CommonLocalizableStrings.DidYouMean + Environment.NewLine - + $" dotnet solution App.sln add {arguments} Lib {projectArg}" + + $" dotnet solution App{solutionExtension} add {arguments} Lib {projectArg}" ); cmd.StdOut.Should().BeVisuallyEquivalentToIfNotLocalized(""); } + + private string GetSolutionFileTemplateContents(string templateFileName) + { + var templateContentDirectory = _testAssetsManager + .CopyTestAsset("SolutionFilesTemplates", identifier: "SolutionFilesTemplates") + .WithSource() + .Path; + return File.ReadAllText(Path.Join(templateContentDirectory, templateFileName)); + } } } diff --git a/test/dotnet-sln.Tests/GivenDotnetSlnList.cs b/test/dotnet-sln.Tests/GivenDotnetSlnList.cs index f9487fc3155a..682a1e45c495 100644 --- a/test/dotnet-sln.Tests/GivenDotnetSlnList.cs +++ b/test/dotnet-sln.Tests/GivenDotnetSlnList.cs @@ -92,7 +92,7 @@ public void WhenNonExistingSolutionIsPassedItPrintsErrorAndUsage(string solution public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("InvalidSolution", identifier: "GivenDotnetSlnList") + .CopyTestAsset("InvalidSolution", identifier: $"GivenDotnetSlnList-InvalidSolutionPassed-{solutionCommand}") .WithSource() .Path; @@ -106,16 +106,22 @@ public void WhenInvalidSolutionIsPassedItPrintsErrorAndUsage(string solutionComm } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenInvalidSolutionIsFoundListPrintsErrorAndUsage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenInvalidSolutionIsFoundListPrintsErrorAndUsage(string solutionCommand, string solutionExtension) { - var projectDirectory = _testAssetsManager - .CopyTestAsset("InvalidSolution") + var projectRootDirectory = _testAssetsManager + .CopyTestAsset("InvalidSolution", identifier: $"GivenDotnetSlnList-InvalidSolutionFound-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var solutionFullPath = Path.Combine(projectDirectory, "InvalidSolution.sln"); + var projectDirectory = solutionExtension == ".sln" + ? Path.Join(projectRootDirectory, "Sln") + : Path.Join(projectRootDirectory, "Slnx"); + + var solutionFullPath = Path.Combine(projectDirectory, $"InvalidSolution{solutionExtension}"); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) .Execute(solutionCommand, "list"); @@ -131,7 +137,7 @@ public void WhenInvalidSolutionIsFoundListPrintsErrorAndUsage(string solutionCom public void WhenNoSolutionExistsInTheDirectoryListPrintsErrorAndUsage(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndCsprojFiles") + .CopyTestAsset("TestAppWithSlnAndCsprojFiles", identifier: $"GivenDotnetSlnList-{solutionCommand}") .WithSource() .Path; @@ -150,7 +156,7 @@ public void WhenNoSolutionExistsInTheDirectoryListPrintsErrorAndUsage(string sol public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage(string solutionCommand) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithMultipleSlnFiles", identifier: "GivenDotnetSlnList") + .CopyTestAsset("TestAppWithMultipleSlnFiles", identifier: $"GivenDotnetSlnList-{solutionCommand}") .WithSource() .Path; @@ -163,26 +169,30 @@ public void WhenMoreThanOneSolutionExistsInTheDirectoryItPrintsErrorAndUsage(str } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenNoProjectsArePresentInTheSolutionItPrintsANoProjectMessage(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenNoProjectsArePresentInTheSolutionItPrintsANoProjectMessage(string solutionCommand, string solutionExtension) { var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithEmptySln") + .CopyTestAsset("TestAppWithEmptySln", identifier: $"GivenDotnetSlnList-{solutionCommand}{solutionExtension}") .WithSource() .Path; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "list"); + .Execute(solutionCommand, $"App{solutionExtension}", "list"); cmd.Should().Pass(); cmd.StdOut.Should().Be(CommonLocalizableStrings.NoProjectsFound); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectsPresentInTheSolutionItListsThem(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenProjectsPresentInTheSolutionItListsThem(string solutionCommand, string solutionExtension) { var expectedOutput = $@"{CommandLocalizableStrings.ProjectsHeader} {new string('-', CommandLocalizableStrings.ProjectsHeader.Length)} @@ -190,21 +200,23 @@ public void WhenProjectsPresentInTheSolutionItListsThem(string solutionCommand) {Path.Combine("Lib", "Lib.csproj")}"; var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndExistingCsprojReferences") + .CopyTestAsset("TestAppWithSlnAndExistingCsprojReferences", identifier: $"GivenDotnetSlnList-{solutionCommand}{solutionExtension}") .WithSource() .Path; var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "list"); + .Execute(solutionCommand, $"App{solutionExtension}", "list"); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentTo(expectedOutput); } [Theory] - [InlineData("sln")] - [InlineData("solution")] - public void WhenProjectsPresentInTheReadonlySolutionItListsThem(string solutionCommand) + [InlineData("sln", ".sln")] + [InlineData("solution", ".sln")] + [InlineData("sln", ".slnx")] + [InlineData("solution", ".slnx")] + public void WhenProjectsPresentInTheReadonlySolutionItListsThem(string solutionCommand, string solutionExtension) { var expectedOutput = $@"{CommandLocalizableStrings.ProjectsHeader} {new string('-', CommandLocalizableStrings.ProjectsHeader.Length)} @@ -212,17 +224,17 @@ public void WhenProjectsPresentInTheReadonlySolutionItListsThem(string solutionC {Path.Combine("Lib", "Lib.csproj")}"; var projectDirectory = _testAssetsManager - .CopyTestAsset("TestAppWithSlnAndExistingCsprojReferences") + .CopyTestAsset("TestAppWithSlnAndExistingCsprojReferences", identifier: $"GivenDotnetSlnList-Readonly-{solutionCommand}{solutionExtension}") .WithSource() .Path; - var slnFileName = Path.Combine(projectDirectory, "App.sln"); + var slnFileName = Path.Combine(projectDirectory, $"App{solutionExtension}"); var attributes = File.GetAttributes(slnFileName); File.SetAttributes(slnFileName, attributes | FileAttributes.ReadOnly); var cmd = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "list"); + .Execute(solutionCommand, $"App{solutionExtension}", "list"); cmd.Should().Pass(); cmd.StdOut.Should().BeVisuallyEquivalentTo(expectedOutput); } @@ -237,7 +249,7 @@ public void WhenProjectsInSolutionFoldersPresentInTheSolutionItListsSolutionFold $"{Path.Combine("NestedSolution", "NestedFolder", "NestedFolder")}" }; var projectDirectory = _testAssetsManager - .CopyTestAsset("SlnFileWithSolutionItemsInNestedFolders") + .CopyTestAsset("SlnFileWithSolutionItemsInNestedFolders", identifier: $"GivenDotnetSlnList-{solutionCommand}") .WithSource() .Path; diff --git a/test/dotnet-sln.Tests/GivenDotnetSlnMigrate.cs b/test/dotnet-sln.Tests/GivenDotnetSlnMigrate.cs index b2a2ecee7272..7af7267a2997 100644 --- a/test/dotnet-sln.Tests/GivenDotnetSlnMigrate.cs +++ b/test/dotnet-sln.Tests/GivenDotnetSlnMigrate.cs @@ -6,7 +6,7 @@ using Microsoft.DotNet.Tools.Common; using CommandLocalizableStrings = Microsoft.DotNet.Tools.Sln.LocalizableStrings; -namespace Microsoft.DotNet.Cli.Sln.List.Tests +namespace Microsoft.DotNet.Cli.Sln.Migrate.Tests { public class GivenDotnetSlnMigrate : SdkTest { @@ -24,7 +24,7 @@ public void WhenSlnFileIsValidShouldGenerateValidSlnxFile(string solutionCommand var slnFileName = Path.Combine(projectDirectory, "App.sln"); var slnMigrateCommand = new DotnetCommand(Log) .WithWorkingDirectory(projectDirectory) - .Execute(solutionCommand, "migrate"); + .Execute(solutionCommand, "App.sln", "migrate"); slnMigrateCommand.Should().Pass(); var slnxFileName = Path.ChangeExtension(slnFileName, ".slnx"); diff --git a/test/dotnet-sln.Tests/dotnet-sln.Tests.csproj b/test/dotnet-sln.Tests/dotnet-sln.Tests.csproj index 2dce887f4cfb..ad45aa7b7e6c 100644 --- a/test/dotnet-sln.Tests/dotnet-sln.Tests.csproj +++ b/test/dotnet-sln.Tests/dotnet-sln.Tests.csproj @@ -24,5 +24,9 @@ + + + +