diff --git a/documentation/wiki/ChangeWaves.md b/documentation/wiki/ChangeWaves.md index 09e7ca1394c..5df8c06508f 100644 --- a/documentation/wiki/ChangeWaves.md +++ b/documentation/wiki/ChangeWaves.md @@ -23,6 +23,9 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t ## Current Rotation of Change Waves +### 17.14 +- [.SLNX support - use the new parser for .sln and .slnx](https://github.com/dotnet/msbuild/pull/10836) + ### 17.12 - [Log TaskParameterEvent for scalar parameters](https://github.com/dotnet/msbuild/pull/9908) - [Convert.ToString during a property evaluation uses the InvariantCulture for all types](https://github.com/dotnet/msbuild/pull/9874) diff --git a/eng/BootStrapMsBuild.targets b/eng/BootStrapMsBuild.targets index dcff8617638..d4330ba658d 100644 --- a/eng/BootStrapMsBuild.targets +++ b/eng/BootStrapMsBuild.targets @@ -35,7 +35,8 @@ <_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Newtonsoft.Json'))' == 'true'" /> <_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('NuGetSdkResolver'))' == 'true'" /> <_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Microsoft.Extensions.'))' == 'true'" /> - + <_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Microsoft.VisualStudio.SolutionPersistence'))' == 'true'" /> + <_NuGetRuntimeDependencies Include="%(RuntimeTargetsCopyLocalItems.Identity)" Condition="'@(RuntimeTargetsCopyLocalItems->Contains('NuGet.'))' == 'true'" /> @@ -48,7 +49,7 @@ - - - - - - - - - - - - - - - - - @(BravoProjectOutputs) - @(CharlieProjectOutputs) - @(DeltaProjectOutputs) - - - - - - - - - - - - - - - Count())' != '3' ` Text='Overall sln outputs must include outputs of each referenced project (there should be 3).' /> - AnyHaveMetadataValue('Identity', '$(StringifiedBravoProjectOutputs)'))' != 'true'` Text='Overall sln outputs must include outputs of normal project build of project B.' /> - AnyHaveMetadataValue('Identity', '$(StringifiedCharlieProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project C.' /> - AnyHaveMetadataValue('Identity', '$(StringifiedDeltaProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project D.' /> - -"; + """; + const string automaticProjectFileContents = + """ + + + + + + + + + + + + + + + + + + + + @(BravoProjectOutputs) + @(CharlieProjectOutputs) + @(DeltaProjectOutputs) + + + + + + + + + + + + + + + Count())' != '3' ` Text='Overall sln outputs must include outputs of each referenced project (there should be 3).' /> + AnyHaveMetadataValue('Identity', '$(StringifiedBravoProjectOutputs)'))' != 'true'` Text='Overall sln outputs must include outputs of normal project build of project B.' /> + AnyHaveMetadataValue('Identity', '$(StringifiedCharlieProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project C.' /> + AnyHaveMetadataValue('Identity', '$(StringifiedDeltaProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project D.' /> + + + """; #endregion var logger = new MockLogger(output); @@ -1039,11 +1065,13 @@ public void SolutionConfigurationWithDependenciesRelaysItsOutputs() /// /// Test the SolutionProjectGenerator.AddPropertyGroupForSolutionConfiguration method /// - [Fact] - public void TestAddPropertyGroupForSolutionConfiguration() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestAddPropertyGroupForSolutionConfiguration(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1063,9 +1091,9 @@ public void TestAddPropertyGroupForSolutionConfiguration() {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = VCConfig1|Win32 EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectRootElement projectXml = ProjectRootElement.Create(); @@ -1112,11 +1140,13 @@ public void TestAddPropertyGroupForSolutionConfiguration() /// /// Make sure that BuildProjectInSolution is set to true of the Build.0 entry is in the solution configuration. /// - [Fact] - public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionSet() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionSet(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1131,9 +1161,9 @@ public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionSe {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.Build.0 = CSConfig1|Any CPU EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectRootElement projectXml = ProjectRootElement.Create(); @@ -1156,11 +1186,13 @@ public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionSe /// /// Make sure that BuildProjectInSolution is set to false of the Build.0 entry is in the solution configuration. /// - [Fact] - public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionNotSet() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionNotSet(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1174,9 +1206,9 @@ public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionNo {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.ActiveCfg = CSConfig1|Any CPU EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectRootElement projectXml = ProjectRootElement.Create(); @@ -1200,10 +1232,12 @@ public void TestAddPropertyGroupForSolutionConfigurationBuildProjectInSolutionNo /// In this bug, SkipNonexistentProjects was always set to 'Build'. It should be 'Build' for metaprojects and 'True' for everything else. /// The repro below has one of each case. WebProjects can't build so they are set as SkipNonexistentProjects='Build' /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void Regress751742_SkipNonexistentProjects() + public void Regress751742_SkipNonexistentProjects(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { @@ -1212,7 +1246,7 @@ public void Regress751742_SkipNonexistentProjects() } var solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1232,10 +1266,10 @@ public void Regress751742_SkipNonexistentProjects() {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = VCConfig1|Win32 EndGlobalSection EndGlobal - "; + """; // We're not passing in a /tv:xx switch, so the solution project will have tools version 2.0 - var solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); var instance = SolutionProjectGenerator.Generate(solution, null, ObjectModelHelpers.MSBuildDefaultToolsVersion, _buildEventContext, CreateMockLoggingService())[0]; @@ -1274,11 +1308,13 @@ public void Regress751742_SkipNonexistentProjects() /// if set when building a solution, will be specified as the ToolsVersion on the MSBuild task when /// building the projects contained within the solution. /// - [Fact] - public void ToolsVersionOverrideShouldBeSpecifiedOnMSBuildTaskInvocations() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ToolsVersionOverrideShouldBeSpecifiedOnMSBuildTaskInvocations(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1298,10 +1334,10 @@ public void ToolsVersionOverrideShouldBeSpecifiedOnMSBuildTaskInvocations() {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = VCConfig1|Win32 EndGlobalSection EndGlobal - "; + """; // We're not passing in a /tv:xx switch, so the solution project will have tools version 2.0 - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, null, ObjectModelHelpers.MSBuildDefaultToolsVersion, _buildEventContext, CreateMockLoggingService()); @@ -1340,42 +1376,44 @@ public void ToolsVersionOverrideShouldBeSpecifiedOnMSBuildTaskInvocations() /// /// Make sure that whatever the solution ToolsVersion is, it gets mapped to all its metaprojs, too. /// - [Fact] - public void SolutionWithDependenciesHasCorrectToolsVersionInMetaprojs() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SolutionWithDependenciesHasCorrectToolsVersionInMetaprojs(bool useNewParser) { string solutionFileContents = - @" -Microsoft Visual Studio Solution File, Format Version 12.00 -Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ConsoleApplication2', 'ConsoleApplication2\ConsoleApplication2.csproj', '{5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}' - ProjectSection(ProjectDependencies) = postProject - {E0D295A1-CAFA-4E68-9929-468657DAAC6C} = {E0D295A1-CAFA-4E68-9929-468657DAAC6C} - EndProjectSection -EndProject -Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ConsoleApplication1', 'ConsoleApplication1\ConsoleApplication1.vbproj', '{E0D295A1-CAFA-4E68-9929-468657DAAC6C}' -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Release|Any CPU.Build.0 = Release|Any CPU - {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal - "; + """ + Microsoft Visual Studio Solution File, Format Version 12.00 + Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ConsoleApplication2', 'ConsoleApplication2\ConsoleApplication2.csproj', '{5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}' + ProjectSection(ProjectDependencies) = postProject + {E0D295A1-CAFA-4E68-9929-468657DAAC6C} = {E0D295A1-CAFA-4E68-9929-468657DAAC6C} + EndProjectSection + EndProject + Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ConsoleApplication1', 'ConsoleApplication1\ConsoleApplication1.vbproj', '{E0D295A1-CAFA-4E68-9929-468657DAAC6C}' + EndProject + Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B97A3C7-3DEE-47A4-870F-5CB6384FE6A4}.Release|Any CPU.Build.0 = Release|Any CPU + {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0D295A1-CAFA-4E68-9929-468657DAAC6C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + EndGlobal + """; // We're not passing in a /tv:xx switch, so the solution project will have tools version 2.0 - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); string[] solutionToolsVersions = { "4.0", ObjectModelHelpers.MSBuildDefaultToolsVersion }; @@ -1409,11 +1447,13 @@ public void SolutionWithDependenciesHasCorrectToolsVersionInMetaprojs() /// /// Test the SolutionProjectGenerator.Generate method has its toolset redirected correctly. /// - [Fact] - public void ToolsVersionOverrideCausesToolsetRedirect() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ToolsVersionOverrideCausesToolsetRedirect(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}' @@ -1433,8 +1473,8 @@ public void ToolsVersionOverrideCausesToolsetRedirect() {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = VCConfig1|Win32 EndGlobalSection EndGlobal - "; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + """; + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); bool caughtException = false; try @@ -1454,11 +1494,13 @@ public void ToolsVersionOverrideCausesToolsetRedirect() /// /// Test the SolutionProjectGenerator.AddPropertyGroupForSolutionConfiguration method /// - [Fact] - public void TestDisambiguateProjectTargetName() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestDisambiguateProjectTargetName(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'Build', 'Build\Build.csproj', '{21397922-C38F-4A0E-B950-77B3FBD51881}' @@ -1478,9 +1520,9 @@ public void TestDisambiguateProjectTargetName() HideSolutionNode = FALSE EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, null, null, BuildEventContext.Invalid, CreateMockLoggingService()); @@ -1534,11 +1576,13 @@ public void TestDisambiguateProjectTargetName() /// /// Tests the algorithm for choosing default configuration/platform values for solutions /// + /// This test would only work for the old parser. In the new parser SolutionConfigurations are not available, + /// and constructed from projects configurations. [Fact] public void TestConfigurationPlatformDefaults1() { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1550,9 +1594,9 @@ public void TestConfigurationPlatformDefaults1() Release|Win32 = Release|Win32 EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = SolutionFile_OldParser_Tests.ParseSolutionHelper(solutionFileContents); // These used to exist on the engine, but now need to be passed in explicitly IDictionary globalProperties = new Dictionary(); @@ -1572,11 +1616,13 @@ public void TestConfigurationPlatformDefaults1() /// /// Tests the algorithm for choosing default configuration/platform values for solutions /// + /// This test would only work for the old parser. In the new parser SolutionConfigurations are not available, + /// and constructed from projects configurations. [Fact] public void TestConfigurationPlatformDefaults2() { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1586,9 +1632,9 @@ public void TestConfigurationPlatformDefaults2() Other|Win32 = Other|Win32 EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = SolutionFile_OldParser_Tests.ParseSolutionHelper(solutionFileContents); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, null, null, BuildEventContext.Invalid, CreateMockLoggingService()); @@ -1602,10 +1648,12 @@ public void TestConfigurationPlatformDefaults2() /// /// Tests the algorithm for choosing default Venus configuration values for solutions /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void TestVenusConfigurationDefaults() + public void TestVenusConfigurationDefaults(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { @@ -1615,13 +1663,13 @@ public void TestVenusConfigurationDefaults() Dictionary globalProperties = new Dictionary(); globalProperties["Configuration"] = "Debug"; - ProjectInstance msbuildProject = CreateVenusSolutionProject(globalProperties); + ProjectInstance msbuildProject = CreateVenusSolutionProject(globalProperties, useNewParser); // ASP.NET configuration should match the selected solution configuration Assert.Equal("Debug", msbuildProject.GetPropertyValue("AspNetConfiguration")); globalProperties["Configuration"] = "Release"; - msbuildProject = CreateVenusSolutionProject(globalProperties); + msbuildProject = CreateVenusSolutionProject(globalProperties, useNewParser); Assert.Equal("Release", msbuildProject.GetPropertyValue("AspNetConfiguration")); // Check that the two standard Asp.net configurations are represented on the targets @@ -1632,10 +1680,12 @@ public void TestVenusConfigurationDefaults() /// /// Tests that the correct value for TargetFrameworkVersion gets set when creating Venus solutions /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void VenusSolutionDefaultTargetFrameworkVersion() + public void VenusSolutionDefaultTargetFrameworkVersion(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { @@ -1644,7 +1694,7 @@ public void VenusSolutionDefaultTargetFrameworkVersion() } // v4.0 by default - ProjectInstance msbuildProject = CreateVenusSolutionProject(); + ProjectInstance msbuildProject = CreateVenusSolutionProject(useNewParser); Assert.Equal("v4.0", msbuildProject.GetPropertyValue("TargetFrameworkVersion")); if (FrameworkLocationHelper.PathToDotNetFrameworkV35 == null) @@ -1654,34 +1704,36 @@ public void VenusSolutionDefaultTargetFrameworkVersion() } // v3.5 if MSBuildToolsVersion is 3.5 - msbuildProject = CreateVenusSolutionProject("3.5"); + msbuildProject = CreateVenusSolutionProject("3.5", useNewParser); Assert.Equal("v3.5", msbuildProject.GetPropertyValue("TargetFrameworkVersion")); // v2.0 if MSBuildToolsVersion is 2.0 - msbuildProject = CreateVenusSolutionProject("2.0"); + msbuildProject = CreateVenusSolutionProject("2.0", useNewParser); Assert.Equal("v2.0", msbuildProject.GetPropertyValue("TargetFrameworkVersion")); // may be user defined IDictionary globalProperties = new Dictionary(); globalProperties.Add("TargetFrameworkVersion", "userdefined"); - msbuildProject = CreateVenusSolutionProject(globalProperties); + msbuildProject = CreateVenusSolutionProject(globalProperties, useNewParser); Assert.Equal("userdefined", msbuildProject.GetPropertyValue("TargetFrameworkVersion")); } /// /// Tests the algorithm for choosing target framework paths for ResolveAssemblyReferences for Venus /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void TestTargetFrameworkPaths0() + public void TestTargetFrameworkPaths0(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkSdkV20 != null) { IDictionary globalProperties = new Dictionary(); globalProperties.Add("TargetFrameworkVersion", "v2.0"); - ProjectInstance msbuildProject = CreateVenusSolutionProject("2.0"); + ProjectInstance msbuildProject = CreateVenusSolutionProject("2.0", useNewParser); // ToolsVersion is 2.0, TargetFrameworkVersion is v2.0 --> one item pointing to v2.0 Assert.Equal("2.0", msbuildProject.ToolsVersion); @@ -1696,10 +1748,12 @@ public void TestTargetFrameworkPaths0() /// /// Tests the algorithm for choosing target framework paths for ResolveAssemblyReferences for Venus /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void TestTargetFrameworkPaths1() + public void TestTargetFrameworkPaths1(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { @@ -1707,7 +1761,7 @@ public void TestTargetFrameworkPaths1() return; } - ProjectInstance msbuildProject = CreateVenusSolutionProject(); + ProjectInstance msbuildProject = CreateVenusSolutionProject(useNewParser); // ToolsVersion is 4.0, TargetFrameworkVersion is v2.0 --> one item pointing to v2.0 msbuildProject.SetProperty("TargetFrameworkVersion", "v2.0"); @@ -1722,10 +1776,12 @@ public void TestTargetFrameworkPaths1() /// /// Tests the algorithm for choosing target framework paths for ResolveAssemblyReferences for Venus /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void TestTargetFrameworkPaths2() + public void TestTargetFrameworkPaths2(bool useNewParser) { if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { @@ -1733,7 +1789,7 @@ public void TestTargetFrameworkPaths2() return; } - ProjectInstance msbuildProject = CreateVenusSolutionProject(); + ProjectInstance msbuildProject = CreateVenusSolutionProject(useNewParser); // ToolsVersion is 4.0, TargetFrameworkVersion is v4.0 --> items for v2.0 and v4.0 msbuildProject.SetProperty("TargetFrameworkVersion", "v4.0"); @@ -1771,11 +1827,13 @@ public void TestTargetFrameworkPaths2() /// /// Test the PredictActiveSolutionConfigurationName method /// + /// This test would only work for the old parser. + /// In the new parser SolutionConfigurations are not available, and constructed from projects configurations. [Fact] public void TestPredictSolutionConfigurationName() { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1785,9 +1843,9 @@ public void TestPredictSolutionConfigurationName() Debug|Win32 = Debug|Win32 EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = SolutionFile_OldParser_Tests.ParseSolutionHelper(solutionFileContents); IDictionary globalProperties = new Dictionary(); @@ -1806,11 +1864,13 @@ public void TestPredictSolutionConfigurationName() /// /// Verifies that the SolutionProjectGenerator will correctly escape project file paths /// - [Fact] - public void SolutionGeneratorEscapingProjectFilePaths() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SolutionGeneratorEscapingProjectFilePaths(bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ConsoleApplication1', '%abtest\ConsoleApplication1.vbproj', '{AB3413A6-D689-486D-B7F0-A095371B3F13}' @@ -1830,9 +1890,9 @@ public void SolutionGeneratorEscapingProjectFilePaths() HideSolutionNode = FALSE EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); // Creating a ProjectRootElement shouldn't affect the ProjectCollection at all Assert.Empty(ProjectCollection.GlobalProjectCollection.LoadedProjects); @@ -1849,8 +1909,10 @@ public void SolutionGeneratorEscapingProjectFilePaths() /// /// Verifies that the SolutionProjectGenerator will emit a solution file. /// - [Fact] - public void SolutionGeneratorCanEmitSolutions() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SolutionGeneratorCanEmitSolutions(bool useNewParser) { string oldValueForMSBuildEmitSolution = Environment.GetEnvironmentVariable("MSBuildEmitSolution"); @@ -1858,7 +1920,7 @@ public void SolutionGeneratorCanEmitSolutions() ProjectCollection.GlobalProjectCollection.UnloadAllProjects(); string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ConsoleApplication1', 'ConsoleApplication1\ConsoleApplication1.vbproj', '{AB3413A6-D689-486D-B7F0-A095371B3F13}' @@ -1878,7 +1940,7 @@ public void SolutionGeneratorCanEmitSolutions() HideSolutionNode = FALSE EndGlobalSection EndGlobal - "; + """; SolutionFile solution = null; using ProjectCollection collection = new ProjectCollection(); @@ -1887,7 +1949,7 @@ public void SolutionGeneratorCanEmitSolutions() { Environment.SetEnvironmentVariable("MSBuildEmitSolution", "1"); - solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + solution = ParseSolutionHelper(solutionFileContents, useNewParser); // Creating a ProjectRootElement shouldn't affect the ProjectCollection at all Assert.Empty(ProjectCollection.GlobalProjectCollection.LoadedProjects); @@ -1919,16 +1981,18 @@ public void SolutionGeneratorCanEmitSolutions() /// Make sure that we output a warning and don't build anything when we're given an invalid /// solution configuration and SkipInvalidConfigurations is set to true. /// - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [Trait("Category", "netcore-osx-failing")] [Trait("Category", "netcore-linux-failing")] - public void TestSkipInvalidConfigurationsCase() + public void TestSkipInvalidConfigurationsCase(bool useNewParser) { string tmpFileName = FileUtilities.GetTemporaryFileName(); string projectFilePath = tmpFileName + ".sln"; - string solutionContents = - @" + string solutionFileContents = + """ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2005 Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'C:\solutions\WebSite2\', '..\..\solutions\WebSite2\', '{F90528C4-6989-4D33-AFE8-F53173597CC2}' @@ -1959,7 +2023,8 @@ public void TestSkipInvalidConfigurationsCase() {F90528C4-6989-4D33-AFE8-F53173597CC2}.Debug|Any CPU.ActiveCfg = Debug|.NET {F90528C4-6989-4D33-AFE8-F53173597CC2}.Debug|Any CPU.Build.0 = Debug|.NET EndGlobalSection - EndGlobal"; + EndGlobal + """; try { @@ -1969,7 +2034,7 @@ public void TestSkipInvalidConfigurationsCase() globalProperties["Configuration"] = "Nonexistent"; globalProperties["SkipInvalidConfigurations"] = "true"; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionContents.Replace('\'', '"')); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, globalProperties, null, BuildEventContext.Invalid, CreateMockLoggingService()); ProjectInstance msbuildProject = instances[0]; @@ -2173,50 +2238,52 @@ public void BadFrameworkMonkierExpectBuildToFail2() /// Bug indicated that when a target framework version greater than 4.0 was used then the solution project generator would crash. /// this test is to make sure the fix is not regressed. /// - [Fact] - public void TestTargetFrameworkVersionGreaterThan4() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void TestTargetFrameworkVersionGreaterThan4(bool useNewParser) { string tmpFileName = FileUtilities.GetTemporaryFileName(); string projectFilePath = tmpFileName + ".sln"; string solutionFileContents = - @" -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'WebSite1', '..\WebSite1\', '{6B8F98F2-C976-4029-9321-5CCD73A174DA}' - ProjectSection(WebsiteProperties) = preProject - TargetFrameworkMoniker = '.NETFramework,Version=v4.34' - Debug.AspNetCompiler.VirtualPath = '/WebSite1' - Debug.AspNetCompiler.PhysicalPath = '..\WebSite1\' - Debug.AspNetCompiler.TargetPath = 'PrecompiledWeb\WebSite1\' - Debug.AspNetCompiler.Updateable = 'true' - Debug.AspNetCompiler.ForceOverwrite = 'true' - Debug.AspNetCompiler.FixedNames = 'false' - Debug.AspNetCompiler.Debug = 'True' - Release.AspNetCompiler.VirtualPath = '/WebSite1' - Release.AspNetCompiler.PhysicalPath = '..\WebSite1\' - Release.AspNetCompiler.TargetPath = 'PrecompiledWeb\WebSite1\' - Release.AspNetCompiler.Updateable = 'true' - Release.AspNetCompiler.ForceOverwrite = 'true' - Release.AspNetCompiler.FixedNames = 'false' - Release.AspNetCompiler.Debug = 'False' - VWDPort = '45602' - DefaultWebSiteLanguage = 'Visual Basic' - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6B8F98F2-C976-4029-9321-5CCD73A174DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B8F98F2-C976-4029-9321-5CCD73A174DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal - "; + """ + Microsoft Visual Studio Solution File, Format Version 11.00 + # Visual Studio 2010 + Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'WebSite1', '..\WebSite1\', '{6B8F98F2-C976-4029-9321-5CCD73A174DA}' + ProjectSection(WebsiteProperties) = preProject + TargetFrameworkMoniker = '.NETFramework,Version=v4.34' + Debug.AspNetCompiler.VirtualPath = '/WebSite1' + Debug.AspNetCompiler.PhysicalPath = '..\WebSite1\' + Debug.AspNetCompiler.TargetPath = 'PrecompiledWeb\WebSite1\' + Debug.AspNetCompiler.Updateable = 'true' + Debug.AspNetCompiler.ForceOverwrite = 'true' + Debug.AspNetCompiler.FixedNames = 'false' + Debug.AspNetCompiler.Debug = 'True' + Release.AspNetCompiler.VirtualPath = '/WebSite1' + Release.AspNetCompiler.PhysicalPath = '..\WebSite1\' + Release.AspNetCompiler.TargetPath = 'PrecompiledWeb\WebSite1\' + Release.AspNetCompiler.Updateable = 'true' + Release.AspNetCompiler.ForceOverwrite = 'true' + Release.AspNetCompiler.FixedNames = 'false' + Release.AspNetCompiler.Debug = 'False' + VWDPort = '45602' + DefaultWebSiteLanguage = 'Visual Basic' + EndProjectSection + EndProject + Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6B8F98F2-C976-4029-9321-5CCD73A174DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B8F98F2-C976-4029-9321-5CCD73A174DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + EndGlobal + """; try { @@ -2226,7 +2293,9 @@ public void TestTargetFrameworkVersionGreaterThan4() globalProperties["Configuration"] = "Release"; globalProperties["SkipInvalidConfigurations"] = "true"; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents.Replace('\'', '"')); + + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); + using ProjectCollection collection = new ProjectCollection(); collection.RegisterLogger(logger); @@ -2256,14 +2325,16 @@ public void TestTargetFrameworkVersionGreaterThan4() /// /// Verifies that when target names are specified they end up in the metaproj. /// - [Fact] - public void CustomTargetNamesAreInInMetaproj() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void CustomTargetNamesAreInInMetaproj(bool useNewParser) { - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper( - @" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFileContents = + """ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 - Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ClassLibrary1"", ""ClassLibrary1.csproj"", ""{6185CC21-BE89-448A-B3C0-D1C27112E595}"" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -2275,7 +2346,9 @@ public void CustomTargetNamesAreInInMetaproj() {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = CSConfig2|Any CPU EndGlobalSection EndGlobal - "); + """; + + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, null, null, BuildEventContext.Invalid, CreateMockLoggingService(), new List { "One" }); @@ -2304,14 +2377,16 @@ public void CustomTargetNamesAreInInMetaproj() /// /// Verifies that disambiguated target names are used when a project name matches a standard solution entry point. /// - [Fact] - public void DisambiguatedTargetNamesAreInInMetaproj() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void DisambiguatedTargetNamesAreInMetaproj(bool useNewParser) { - foreach(string projectName in ProjectInSolution.projectNamesToDisambiguate) + foreach (string projectName in ProjectInSolution.projectNamesToDisambiguate) { - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper( - $$""" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFileContents = + $$""" + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{projectName}}", "{{projectName}}.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject @@ -2326,7 +2401,9 @@ public void DisambiguatedTargetNamesAreInInMetaproj() {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal - """); + """; + + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, null, null, BuildEventContext.Invalid, CreateMockLoggingService(), null); @@ -2349,29 +2426,33 @@ public void DisambiguatedTargetNamesAreInInMetaproj() /// Verifies that illegal user target names (the ones already used internally) don't crash the SolutionProjectGenerator /// [Theory] - [InlineData(false)] - [InlineData(true)] - public void IllegalUserTargetNamesDoNotThrow(bool forceCaseDifference) + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(true, true)] + public void IllegalUserTargetNamesDoNotThrow(bool forceCaseDifference, bool useNewParser) { - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper( - @" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFileContents = + """ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 - Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ClassLibrary1"", ""ClassLibrary1.csproj"", ""{6185CC21-BE89-448A-B3C0-D1C27112E595}"" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal - "); + """; + + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances; @@ -2426,31 +2507,34 @@ public void AfterTargetsComeFromImport() { string baseDirectory = Guid.NewGuid().ToString("N"); - string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), @" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), + """ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 - Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ClassLibrary1"", ""ClassLibrary1.csproj"", ""{6185CC21-BE89-448A-B3C0-D1C27112E595}"" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal - "); + """); - ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"after.{Path.GetFileName(solutionFilePath)}.targets"), @" - - + ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"after.{Path.GetFileName(solutionFilePath)}.targets"), + """ + + - "); + + """); try { @@ -2482,31 +2566,34 @@ public void BeforeTargetsFromImportCanHookDynamicTarget() { string baseDirectory = Guid.NewGuid().ToString("N"); - string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), @" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), + """ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 - Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ClassLibrary1"", ""ClassLibrary1.csproj"", ""{6185CC21-BE89-448A-B3C0-D1C27112E595}"" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal - "); + """); - ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"after.{Path.GetFileName(solutionFilePath)}.targets"), @" - - - + ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"after.{Path.GetFileName(solutionFilePath)}.targets"), + """ + + + - "); + + """); try { @@ -2557,48 +2644,55 @@ public void DirectorySolutionPropsTest(string projectName, bool enable) string baseDirectory = Guid.NewGuid().ToString("N"); - string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), @" - Microsoft Visual Studio Solution File, Format Version 14.00 + string solutionFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, $"{Guid.NewGuid():N}.sln"), + """ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2015 - Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""ClassLibrary1"", ""ClassLibrary1.csproj"", ""{6185CC21-BE89-448A-B3C0-D1C27112E595}"" + Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1.csproj", "{6185CC21-BE89-448A-B3C0-D1C27112E595}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal - "); + """); - string projectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, projectName), $@" - + string projectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, projectName), + $$""" + - {expectedPropertyValue} + {{expectedPropertyValue}} - "); + + """); if (projectPath.StartsWith("Custom", StringComparison.OrdinalIgnoreCase)) { // If a custom file name was given, create a Directory.Solution.props and Directory.Build.targets to ensure that they aren't imported - ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, "Directory.Solution.props"), $@" - - - This file should not be imported - - "); - - ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, "Directory.Solution.targets"), $@" - - - This file should not be imported - - "); + ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, "Directory.Solution.props"), + """ + + + This file should not be imported + + + """); + + ObjectModelHelpers.CreateFileInTempProjectDirectory(Path.Combine(baseDirectory, "Directory.Solution.targets"), + """ + + + This file should not be imported + + + """); } try @@ -2640,20 +2734,23 @@ public void DirectorySolutionPropsTest(string projectName, bool enable) /// Regression test for https://github.com/dotnet/msbuild/issues/6236 /// [Theory] - [InlineData("http://localhost:8080")] - [InlineData("a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-")] - public void AbsolutePathWorksForUnsupportedPaths(string relativePath) + [InlineData("http://localhost:8080", false)] + [InlineData("http://localhost:8080", true)] + [InlineData(_longLineString, false)] + [InlineData(_longLineString, true)] + public void AbsolutePathWorksForUnsupportedPaths(string relativePath, bool useNewParser) { string solutionFileContents = - $@" -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31025.194 -MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{{E24C65DC-7377-472B-9ABA-BC803B73C61A}}"") = ""WebSite1"", ""{relativePath}"", ""{{{{96E0707C-2E9C-4704-946F-FA583147737F}}}}"" -EndProject"; + $$""" + Microsoft Visual Studio Solution File, Format Version 12.00 + # Visual Studio Version 16 + VisualStudioVersion = 16.0.31025.194 + MinimumVisualStudioVersion = 10.0.40219.1 + Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "WebSite1", "{{relativePath}}", "{96E0707C-2E9C-4704-946F-FA583147737F}" + EndProject + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInSolution projectInSolution = solution.ProjectsInOrder.ShouldHaveSingleItem(); @@ -2665,25 +2762,25 @@ public void AbsolutePathWorksForUnsupportedPaths(string relativePath) /// /// Create a Project derived from a Venus solution /// - private ProjectInstance CreateVenusSolutionProject() + private ProjectInstance CreateVenusSolutionProject(bool useNewParser) { - return CreateVenusSolutionProject(null, null); + return CreateVenusSolutionProject(null, null, useNewParser); } /// /// Create a Project derived from a Venus solution /// - private ProjectInstance CreateVenusSolutionProject(IDictionary globalProperties) + private ProjectInstance CreateVenusSolutionProject(IDictionary globalProperties, bool useNewParser) { - return CreateVenusSolutionProject(globalProperties, null); + return CreateVenusSolutionProject(globalProperties, null, useNewParser); } /// /// Create a Project derived from a Venus solution /// - private ProjectInstance CreateVenusSolutionProject(string toolsVersion) + private ProjectInstance CreateVenusSolutionProject(string toolsVersion, bool useNewParser) { - return CreateVenusSolutionProject(null, toolsVersion); + return CreateVenusSolutionProject(null, toolsVersion, useNewParser); } /// @@ -2692,10 +2789,10 @@ private ProjectInstance CreateVenusSolutionProject(string toolsVersion) /// /// The dictionary of global properties. May be null. /// The ToolsVersion override value. May be null. - private ProjectInstance CreateVenusSolutionProject(IDictionary globalProperties, string toolsVersion) + private ProjectInstance CreateVenusSolutionProject(IDictionary globalProperties, string toolsVersion, bool useNewParser) { string solutionFileContents = - @" + """ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'C:\solutions\WebSite2\', '..\..\solutions\WebSite2\', '{F90528C4-6989-4D33-AFE8-F53173597CC2}' @@ -2727,9 +2824,9 @@ private ProjectInstance CreateVenusSolutionProject(IDictionary g {F90528C4-6989-4D33-AFE8-F53173597CC2}.Debug|Any CPU.Build.0 = Debug|.NET EndGlobalSection EndGlobal - "; + """; - SolutionFile solution = SolutionFile_Tests.ParseSolutionHelper(solutionFileContents); + SolutionFile solution = ParseSolutionHelper(solutionFileContents, useNewParser); ProjectInstance[] instances = SolutionProjectGenerator.Generate(solution, globalProperties, toolsVersion, BuildEventContext.Invalid, CreateMockLoggingService()); @@ -2776,6 +2873,12 @@ private void AssertProjectItemNameCount(ProjectInstance msbuildProject, string i Assert.Equal(count, itemGroup.Count()); } + private SolutionFile ParseSolutionHelper(string solutionFileContents, bool useNewParser) + { + return useNewParser ? SolutionFile_NewParser_Tests.ParseSolutionHelper(solutionFileContents) : + SolutionFile_OldParser_Tests.ParseSolutionHelper(solutionFileContents); + } + #endregion // Helper Functions } } diff --git a/src/Build.UnitTests/Graph/GetCompatiblePlatformGraph_Tests.cs b/src/Build.UnitTests/Graph/GetCompatiblePlatformGraph_Tests.cs index b941649ad74..d6344240f1a 100644 --- a/src/Build.UnitTests/Graph/GetCompatiblePlatformGraph_Tests.cs +++ b/src/Build.UnitTests/Graph/GetCompatiblePlatformGraph_Tests.cs @@ -402,14 +402,14 @@ public void SolutionWithoutAllConfigurations() // Slashes here (and in the .slnf) are hardcoded as backslashes intentionally to support the common case. TransientTestFile solutionFile = testEnvironment.CreateFile(folder, "SimpleProject.sln", - @" + """ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29326.124 MinimumVisualStudioVersion = 10.0.40219.1 - Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""Project1"", ""1\1\1.csproj"", ""{79B5EBA6-5D27-4976-BC31-14422245A59A}"" + Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project1", "1\1\1.csproj", "{79B5EBA6-5D27-4976-BC31-14422245A59A}" EndProject - Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""2"", ""2\2\2.proj"", ""{8EFCCA22-9D51-4268-90F7-A595E11FCB2D}"" + Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "2", "2\2\2.proj", "{8EFCCA22-9D51-4268-90F7-A595E11FCB2D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -434,7 +434,7 @@ public void SolutionWithoutAllConfigurations() SolutionGuid = {DE7234EC-0C4D-4070-B66A-DCF1B4F0CFEF} EndGlobalSection EndGlobal - "); + """); ProjectCollection projectCollection = testEnvironment.CreateProjectCollection().Collection; MockLogger logger = new(); diff --git a/src/Build.UnitTests/Graph/GraphLoadedFromSolution_tests.cs b/src/Build.UnitTests/Graph/GraphLoadedFromSolution_tests.cs index 431ea412875..6d535479b1e 100644 --- a/src/Build.UnitTests/Graph/GraphLoadedFromSolution_tests.cs +++ b/src/Build.UnitTests/Graph/GraphLoadedFromSolution_tests.cs @@ -59,7 +59,8 @@ public void GraphConstructionFailsOnNonExistentSolution() new ProjectGraph("nonExistent.sln"); }); - exception.Message.ShouldContain("The project file could not be loaded. Could not find file"); + exception.Message.ShouldContain("The project file could not be loaded."); + exception.Message.ShouldContain("Could not find file"); } [Fact] @@ -646,28 +647,6 @@ IEnumerable GetIncomingEdgeItemsToNode(ProjectGraphNode nod } } - [Fact] - public void GraphConstructionShouldThrowOnMissingSolutionDependencies() - { - var solutionContents = SolutionFileBuilder.FromGraphEdges( - _env, - new Dictionary { { 1, null }, { 2, null } }, - new[] { ("1", new[] { Guid.NewGuid().ToString("B") }) }).BuildSolution(); - - var solutionFile = _env.CreateFile( - "solution.sln", - solutionContents) - .Path; - - var exception = Should.Throw( - () => - { - new ProjectGraph(solutionFile); - }); - - exception.Message.ShouldContain("but a project with this GUID was not found in the .SLN file"); - } - private static bool IsSolutionItemReference(ProjectItemInstance edgeItem) { return edgeItem.ItemType == GraphBuilder.SolutionItemReference; diff --git a/src/Build/Construction/Solution/SolutionFile.cs b/src/Build/Construction/Solution/SolutionFile.cs index 983cd691d0d..909feaf74a6 100644 --- a/src/Build/Construction/Solution/SolutionFile.cs +++ b/src/Build/Construction/Solution/SolutionFile.cs @@ -193,7 +193,7 @@ internal int VisualStudioVersion internal bool UseNewParser => ShouldUseNewParser(_solutionFile); - internal static bool ShouldUseNewParser(string solutionFile) => FileUtilities.IsSolutionXFilename(solutionFile); + internal static bool ShouldUseNewParser(string solutionFile) => ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14) || FileUtilities.IsSolutionXFilename(solutionFile); /// /// All projects in this solution, in the order they appeared in the solution file @@ -221,6 +221,10 @@ internal string FullPath set { + if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_14) && string.IsNullOrEmpty(value)) + { + throw new ArgumentNullException(nameof(FullPath)); + } // Should already be canonicalized to a full path ErrorUtilities.VerifyThrowInternalRooted(value); // To reduce code duplication, this should be diff --git a/src/Framework/ChangeWaves.cs b/src/Framework/ChangeWaves.cs index 1d682c4fc75..8e58f93835c 100644 --- a/src/Framework/ChangeWaves.cs +++ b/src/Framework/ChangeWaves.cs @@ -27,7 +27,8 @@ internal static class ChangeWaves { internal static readonly Version Wave17_10 = new Version(17, 10); internal static readonly Version Wave17_12 = new Version(17, 12); - internal static readonly Version[] AllWaves = { Wave17_10, Wave17_12 }; + internal static readonly Version Wave17_14 = new Version(17, 14); + internal static readonly Version[] AllWaves = { Wave17_10, Wave17_12, Wave17_14 }; /// /// Special value indicating that all features behind all Change Waves should be enabled.