diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.sln b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.sln
new file mode 100644
index 000000000..acf657a65
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/App.sln
@@ -0,0 +1,21 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26006.2
+MinimumVisualStudioVersion = 10.0.40219.1
+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
+EndGlobal
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/Library.cs b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/Library.cs
new file mode 100644
index 000000000..786c0221c
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/Library.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+namespace ProjectWithAdditionalConfigs
+{
+ public static class Library
+ {
+ public static string GetMessage()
+ {
+ return "Hello World!";
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/ProjectWithAdditionalConfigs.csproj b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/ProjectWithAdditionalConfigs.csproj
new file mode 100644
index 000000000..9b87758e9
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithAdditionalConfigs/ProjectWithAdditionalConfigs.csproj
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0
+ {A302325B-D680-4C0E-8680-7AE283981624}
+ AnyCPU;x64;x86;AdditionalPlatform
+ Debug;Release;FooBar;AdditionalConfiguration
+
+
+
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/Library.cs b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/Library.cs
new file mode 100644
index 000000000..c0d7436b3
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/Library.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+namespace ProjectWithMatchingConfigs
+{
+ public static class Library
+ {
+ public static string GetMessage()
+ {
+ return "Hello World!";
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/ProjectWithMatchingConfigs.csproj b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/ProjectWithMatchingConfigs.csproj
new file mode 100644
index 000000000..7c789108f
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithMatchingConfigs/ProjectWithMatchingConfigs.csproj
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0
+ {C9601CA2-DB64-4FB6-B463-368C7764BF0D}
+ AnyCPU;x64;x86
+ Debug;Release;FooBar
+
+
+
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/Library.cs b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/Library.cs
new file mode 100644
index 000000000..fb9a17c27
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/Library.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+namespace ProjectWithoutMatchingConfigs
+{
+ public static class Library
+ {
+ public static string GetMessage()
+ {
+ return "Hello World!";
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/ProjectWithoutMatchingConfigs.csproj b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/ProjectWithoutMatchingConfigs.csproj
new file mode 100644
index 000000000..4bc811fa1
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithSlnAndProjectConfigs/ProjectWithoutMatchingConfigs/ProjectWithoutMatchingConfigs.csproj
@@ -0,0 +1,8 @@
+
+
+
+ netstandard2.0
+ {C49B64DE-4401-4825-8A88-10DCB5950E57}
+
+
+
diff --git a/src/dotnet/ProjectInstanceExtensions.cs b/src/dotnet/ProjectInstanceExtensions.cs
index f437572c5..fdfd41b38 100644
--- a/src/dotnet/ProjectInstanceExtensions.cs
+++ b/src/dotnet/ProjectInstanceExtensions.cs
@@ -4,6 +4,7 @@
using Microsoft.Build.Execution;
using Microsoft.DotNet.Cli.Sln.Internal;
using System;
+using System.Collections.Generic;
using System.Linq;
namespace Microsoft.DotNet.Tools.Common
@@ -45,5 +46,25 @@ namespace Microsoft.DotNet.Tools.Common
return projectTypeGuid;
}
+
+ public static IEnumerable GetPlatforms(this ProjectInstance projectInstance)
+ {
+ return (projectInstance.GetPropertyValue("Platforms") ?? "")
+ .Split(
+ new char[] { ';' },
+ StringSplitOptions.RemoveEmptyEntries)
+ .Where(p => !string.IsNullOrWhiteSpace(p))
+ .DefaultIfEmpty("AnyCPU");
+ }
+
+ public static IEnumerable GetConfigurations(this ProjectInstance projectInstance)
+ {
+ return (projectInstance.GetPropertyValue("Configurations") ?? "Debug;Release")
+ .Split(
+ new char[] { ';' },
+ StringSplitOptions.RemoveEmptyEntries)
+ .Where(c => !string.IsNullOrWhiteSpace(c))
+ .DefaultIfEmpty("Debug");
+ }
}
}
diff --git a/src/dotnet/SlnFileExtensions.cs b/src/dotnet/SlnFileExtensions.cs
index 84ce82b0d..e1d91c224 100644
--- a/src/dotnet/SlnFileExtensions.cs
+++ b/src/dotnet/SlnFileExtensions.cs
@@ -59,7 +59,16 @@ namespace Microsoft.DotNet.Tools.Common
FilePath = relativeProjectPath
};
- slnFile.AddDefaultBuildConfigurations(slnProject);
+ // NOTE: The order you create the sections determines the order they are written to the sln
+ // file. In the case of an empty sln file, in order to make sure the solution configurations
+ // section comes first we need to add it first. This doesn't affect correctness but does
+ // stop VS from re-ordering things later on. Since we are keeping the SlnFile class low-level
+ // it shouldn't care about the VS implementation details. That's why we handle this here.
+ slnFile.AddDefaultBuildConfigurations();
+
+ slnFile.MapSolutionConfigurationsToProject(
+ projectInstance,
+ slnFile.ProjectConfigurationsSection.GetOrCreatePropertySet(slnProject.Id));
slnFile.AddSolutionFolders(slnProject);
@@ -70,11 +79,13 @@ namespace Microsoft.DotNet.Tools.Common
}
}
- public static void AddDefaultBuildConfigurations(this SlnFile slnFile, SlnProject slnProject)
+ private static void AddDefaultBuildConfigurations(this SlnFile slnFile)
{
- if (slnProject == null)
+ var configurationsSection = slnFile.SolutionConfigurationsSection;
+
+ if (!configurationsSection.IsEmpty)
{
- throw new ArgumentException();
+ return;
}
var defaultConfigurations = new List()
@@ -87,57 +98,108 @@ namespace Microsoft.DotNet.Tools.Common
"Release|x86",
};
- // NOTE: The order you create the sections determines the order they are written to the sln
- // file. In the case of an empty sln file, in order to make sure the solution configurations
- // section comes first we need to add it first. This doesn't affect correctness but does
- // stop VS from re-ordering things later on. Since we are keeping the SlnFile class low-level
- // it shouldn't care about the VS implementation details. That's why we handle this here.
- AddDefaultSolutionConfigurations(defaultConfigurations, slnFile.SolutionConfigurationsSection);
- AddDefaultProjectConfigurations(
- defaultConfigurations,
- slnFile.ProjectConfigurationsSection.GetOrCreatePropertySet(slnProject.Id));
- }
-
- private static void AddDefaultSolutionConfigurations(
- List defaultConfigurations,
- SlnPropertySet solutionConfigs)
- {
foreach (var config in defaultConfigurations)
{
- if (!solutionConfigs.ContainsKey(config))
+ configurationsSection[config] = config;
+ }
+ }
+
+ private static void MapSolutionConfigurationsToProject(
+ this SlnFile slnFile,
+ ProjectInstance projectInstance,
+ SlnPropertySet solutionProjectConfigs)
+ {
+ var (projectConfigurations, defaultProjectConfiguration) = GetKeysDictionary(projectInstance.GetConfigurations());
+ var (projectPlatforms, defaultProjectPlatform) = GetKeysDictionary(projectInstance.GetPlatforms());
+
+ foreach (var solutionConfigKey in slnFile.SolutionConfigurationsSection.Keys)
+ {
+ var projectConfigKey = MapSolutionConfigKeyToProjectConfigKey(
+ solutionConfigKey,
+ projectConfigurations,
+ defaultProjectConfiguration,
+ projectPlatforms,
+ defaultProjectPlatform);
+ if (projectConfigKey == null)
{
- solutionConfigs[config] = config;
+ continue;
+ }
+
+ var activeConfigKey = $"{solutionConfigKey}.ActiveCfg";
+ if (!solutionProjectConfigs.ContainsKey(activeConfigKey))
+ {
+ solutionProjectConfigs[activeConfigKey] = projectConfigKey;
+ }
+
+ var buildKey = $"{solutionConfigKey}.Build.0";
+ if (!solutionProjectConfigs.ContainsKey(buildKey))
+ {
+ solutionProjectConfigs[buildKey] = projectConfigKey;
}
}
}
- private static void AddDefaultProjectConfigurations(
- List defaultConfigurations,
- SlnPropertySet projectConfigs)
+ private static (Dictionary Keys, string DefaultKey) GetKeysDictionary(IEnumerable keys)
{
- foreach (var config in defaultConfigurations)
- {
- var activeCfgKey = $"{config}.ActiveCfg";
- if (!projectConfigs.ContainsKey(activeCfgKey))
- {
- projectConfigs[activeCfgKey] = config;
- }
+ // A dictionary mapping key -> key is used instead of a HashSet so the original case of the key can be retrieved from the set
+ var dictionary = new Dictionary(StringComparer.CurrentCultureIgnoreCase);
- var build0Key = $"{config}.Build.0";
- if (!projectConfigs.ContainsKey(build0Key))
- {
- projectConfigs[build0Key] = config;
- }
+ foreach (var key in keys)
+ {
+ dictionary[key] = key;
}
+
+ return (dictionary, keys.FirstOrDefault());
}
- public static void AddSolutionFolders(this SlnFile slnFile, SlnProject slnProject)
+ private static string GetMatchingProjectKey(IDictionary projectKeys, string solutionKey)
{
- if (slnProject == null)
+ string projectKey;
+ if (projectKeys.TryGetValue(solutionKey, out projectKey))
{
- throw new ArgumentException();
+ return projectKey;
}
+ var keyWithoutWhitespace = String.Concat(solutionKey.Where(c => !Char.IsWhiteSpace(c)));
+ if (projectKeys.TryGetValue(keyWithoutWhitespace, out projectKey))
+ {
+ return projectKey;
+ }
+
+ return null;
+ }
+
+ private static string MapSolutionConfigKeyToProjectConfigKey(
+ string solutionConfigKey,
+ Dictionary projectConfigurations,
+ string defaultProjectConfiguration,
+ Dictionary projectPlatforms,
+ string defaultProjectPlatform)
+ {
+ var pair = solutionConfigKey.Split(new char[] {'|'}, 2);
+ if (pair.Length != 2)
+ {
+ return null;
+ }
+
+ var projectConfiguration = GetMatchingProjectKey(projectConfigurations, pair[0]) ?? defaultProjectConfiguration;
+ if (projectConfiguration == null)
+ {
+ return null;
+ }
+
+ var projectPlatform = GetMatchingProjectKey(projectPlatforms, pair[1]) ?? defaultProjectPlatform;
+ if (projectPlatform == null)
+ {
+ return null;
+ }
+
+ // VS stores "Any CPU" platform in the solution regardless of how it is named at the project level
+ return $"{projectConfiguration}|{(projectPlatform == "AnyCPU" ? "Any CPU" : projectPlatform)}";
+ }
+
+ private static void AddSolutionFolders(this SlnFile slnFile, SlnProject slnProject)
+ {
var solutionFolders = slnProject.GetSolutionFoldersFromProject();
if (solutionFolders.Any())
diff --git a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs
index 346fd6638..bb50d5f5d 100644
--- a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs
+++ b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs
@@ -81,16 +81,16 @@ Global
{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|x64
- __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|x64
- __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|x86
- __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|x86
+ __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|x64
- __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|x64
- __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|x86
- __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|x86
+ __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
@@ -117,16 +117,16 @@ Global
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|x64
- __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|x64
- __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|x86
- __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|x86
+ __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|x64
- __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|x64
- __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|x86
- __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|x86
+ __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
";
@@ -166,16 +166,16 @@ Global
{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|x64
- __LIB_PROJECT_GUID__.Debug|x64.Build.0 = Debug|x64
- __LIB_PROJECT_GUID__.Debug|x86.ActiveCfg = Debug|x86
- __LIB_PROJECT_GUID__.Debug|x86.Build.0 = Debug|x86
+ __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|x64
- __LIB_PROJECT_GUID__.Release|x64.Build.0 = Release|x64
- __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|x86
- __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|x86
+ __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
@@ -184,6 +184,141 @@ Global
__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
";
[Theory]
@@ -788,6 +923,69 @@ EndGlobal
solutionFolderProjects.Count().Should().Be(1);
}
+ [Fact]
+ public void WhenProjectWithoutMatchingConfigurationsIsAddedSolutionMapsToFirstAvailable()
+ {
+ var slnDirectory = TestAssets
+ .Get("TestAppWithSlnAndProjectConfigs")
+ .CreateInstance()
+ .WithSourceFiles()
+ .Root
+ .FullName;
+
+ var slnFullPath = Path.Combine(slnDirectory, "App.sln");
+
+ var result = new DotnetCommand()
+ .WithWorkingDirectory(slnDirectory)
+ .ExecuteWithCapturedOutput($"sln add ProjectWithoutMatchingConfigs");
+ result.Should().Pass();
+
+ File.ReadAllText(slnFullPath)
+ .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithoutMatchingConfigs);
+ }
+
+ [Fact]
+ public void WhenProjectWithMatchingConfigurationsIsAddedSolutionMapsAll()
+ {
+ var slnDirectory = TestAssets
+ .Get("TestAppWithSlnAndProjectConfigs")
+ .CreateInstance()
+ .WithSourceFiles()
+ .Root
+ .FullName;
+
+ var slnFullPath = Path.Combine(slnDirectory, "App.sln");
+
+ var result = new DotnetCommand()
+ .WithWorkingDirectory(slnDirectory)
+ .ExecuteWithCapturedOutput($"sln add ProjectWithMatchingConfigs");
+ result.Should().Pass();
+
+ File.ReadAllText(slnFullPath)
+ .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithMatchingConfigs);
+ }
+
+ [Fact]
+ public void WhenProjectWithAdditionalConfigurationsIsAddedSolutionDoesNotMapThem()
+ {
+ var slnDirectory = TestAssets
+ .Get("TestAppWithSlnAndProjectConfigs")
+ .CreateInstance()
+ .WithSourceFiles()
+ .Root
+ .FullName;
+
+ var slnFullPath = Path.Combine(slnDirectory, "App.sln");
+
+ var result = new DotnetCommand()
+ .WithWorkingDirectory(slnDirectory)
+ .ExecuteWithCapturedOutput($"sln add ProjectWithAdditionalConfigs");
+ result.Should().Pass();
+
+ File.ReadAllText(slnFullPath)
+ .Should().BeVisuallyEquivalentTo(ExpectedSlnFileAfterAddingProjectWithAdditionalConfigs);
+ }
+
private string GetExpectedSlnContents(
string slnPath,
string slnTemplate,