// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.IO; using System.Collections.Generic; using System.Configuration; using Microsoft.Win32; using System.Text; using NUnit.Framework; using Microsoft.Build.BuildEngine; using Microsoft.Build.BuildEngine.Shared; namespace Microsoft.Build.UnitTests { /// /// Unit tests for ToolsetReader class and its derived classes /// [TestFixture] public class ToolsetReaderTests { // The registry key that is passed as the baseKey parameter to the ToolsetRegistryReader class private RegistryKey testRegistryKey = null; // Subkey "4.0" private RegistryKey currentVersionRegistryKey = null; // Subkey "ToolsVersions" private RegistryKey toolsVersionsRegistryKey = null; // Path to the registry key under HKCU // Note that this is a test registry key created solely for unit testing. private const string testRegistryPath = @"msbuildUnitTests"; /// /// Reset the testRegistryKey /// [SetUp] public void Setup() { TearDown(); testRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath); currentVersionRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath + "\\" + Constants.AssemblyVersion); toolsVersionsRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath + "\\ToolsVersions"); } [TearDown] public void TearDown() { ToolsetConfigurationReaderTestHelper.CleanUp(); DeleteTestRegistryKey(); } /// /// Helper class to delete the testRegistryKey tree. /// private void DeleteTestRegistryKey() { if (Registry.CurrentUser.OpenSubKey(testRegistryPath) != null) { Registry.CurrentUser.DeleteSubKeyTree(testRegistryPath); } } /// /// Test to make sure machine.config file has the section registered /// and we are picking it up from there. /// [Test] public void GetToolsetDataFromConfiguration_SectionNotRegisteredInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@" "); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(null, defaultToolsVersion); Assertion.AssertEquals(0, values.Count); } #region "Reading from application configuration file tests" /// /// Tests that the data is correctly populated using function GetToolsetDataFromConfiguration /// [Test] public void GetToolsetDataFromConfiguration_Basic() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals("2.0", defaultToolsVersion); Assertion.AssertEquals(2, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath); Assertion.AssertEquals(0, values["3.5"].BuildProperties.Count); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["3.5"].ToolsPath); } /// /// Relative paths can be used in a config file value /// [Test] public void RelativePathInValue() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); BuildPropertyGroup pg = new BuildPropertyGroup(); pg.SetProperty("DotDotSlash", @"..\"); reader.ReadToolsets(values, new BuildPropertyGroup(), pg, true); string expected1 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\foo")); string expected2 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\bar")); Console.WriteLine(values["2.0"].ToolsPath); Assertion.AssertEquals(expected1, values["2.0"].ToolsPath); Assertion.AssertEquals(expected2, values["3.0"].ToolsPath); } /// /// Invalid relative path in msbuildbinpath value /// [Test] public void InvalidRelativePath() { string invalidRelativePath = @"..\|invalid|"; ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); // Don't crash (consistent with invalid absolute path) Assertion.AssertEquals(invalidRelativePath, values["2.0"].ToolsPath); } /// /// Tests the case where application configuration file is invalid /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_InvalidXmlFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@""); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case where application configuration file is invalid /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_InvalidConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case where application configuration file is empty /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_FileEmpty() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@""); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case when ReadConfiguration throws exception /// Make sure that we don't eat it and always throw ConfigurationErrorsException /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_ConfigurationExceptionThrown() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationException()); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // this should throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case when ReadConfiguration throws exception /// Make sure that we don't eat it and always throw ConfigurationErrorsException /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_ConfigurationErrorsExceptionThrown() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationErrorsException()); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // this should throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case where default attribute is not specified in the config file /// [Test] public void GetToolsetDataFromConfiguration_DefaultAttributeNotSpecified() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(null, defaultToolsVersion); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath); } /// /// Default toolset has no toolsVersion element definition /// [Test] public void GetToolsetDataFromConfiguration_DefaultToolsetUndefined() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // Does not throw reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case where msbuildToolsets is not specified in the config file /// Basically in the code we should be checking if config.GetSection("msbuildToolsets") returns a null /// [Test] public void GetToolsetDataFromConfiguration_MSBuildToolsetsNodeNotPresent() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(null, defaultToolsVersion); Assertion.AssertEquals(0, values.Count); } /// /// Tests that we handle empty MSBuildToolsets element correctly /// [Test] public void GetToolsetDataFromConfiguration_EmptyMSBuildToolsetsNode() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(null, defaultToolsVersion); Assertion.AssertEquals(0, values.Count); } /// /// Tests the case where only default ToolsVersion is specified in the application configuration file /// [Test] public void GetToolsetDataFromConfiguration_OnlyDefaultSpecified() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case where only one ToolsVersion data is specified in the application configuration file /// [Test] public void GetToolsetDataFromConfiguration_OneToolsVersionNode() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals("2.0", defaultToolsVersion); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath); Assertion.AssertEquals(1, values.Count); } /// /// Tests the case when an invalid value of ToolsVersion is specified /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_ToolsVersionIsEmptyString() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); //this should throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// If both MSBuildToolsPath and MSBuildBinPath are present, they must match /// [Test] public void GetToolsetDataFromConfiguration_ToolsPathAndBinPathDiffer() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); //this should throw ... bool caught = false; try { reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } catch (InvalidToolsetDefinitionException) { caught = true; } Assertion.Assert(caught); } /// /// Tests the case when a blank value of PropertyName is specified in the config file /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void BlankPropertyNameInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); //this should throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case when a blank property name is specified in the registry /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void BlankPropertyNameInRegistry() { RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0"); rk.SetValue("MSBuildBinPath", "someBinPath"); rk.SetValue("", "foo"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // Should throw ... string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } /// /// Tests the case when a blank property value is specified in the config file /// [Test] public void BlankPropertyValueInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); //this should not throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case when a blank property value is specified in the registry /// [Test] public void BlankPropertyValueInRegistry() { RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0"); rk.SetValue("MSBuildBinPath", "someBinPath"); rk.SetValue("foo", ""); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // Should not throw ... string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } /// /// Tests the case when an invalid value of PropertyName is specified in the config file /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void InvalidPropertyNameInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); //this should throw ... reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); } /// /// Tests the case when an invalid value of PropertyName is specified in the registry /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void InvalidPropertyNameInRegistry() { RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0"); rk.SetValue("MSBuildBinPath", "someBinPath"); rk.SetValue("foo|bar", "x"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // Should throw ... string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } /// /// Tests that empty string is an invalid value for MSBuildBinPath /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetDataFromConfiguration_PropertyValueIsEmptyString1() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(String.Empty, values["2.0"].ToolsPath); } /// /// Tests that empty string is a valid property value for an arbitrary property /// [Test] public void GetToolsetDataFromConfiguration_PropertyValueIsEmptyString2() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(1, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(String.Empty, values["2.0"].BuildProperties["foo"].Value); } /// /// Tests that any escaped xml in config file, is treated well /// Note that this comes for free with the current implementation using the /// framework api to access section in the config file /// [Test] public void GetToolsetDataFromConfiguration_XmlEscapedCharacters() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration( ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true); Assertion.AssertEquals("2>.0", defaultToolsVersion); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(@"some>value", values["2>.0"].BuildProperties["foo"].Value); } #endregion #region "GetToolsetData tests" /// /// Tests the case where registry and config file contains different toolsVersion /// [Test] public void GetToolsetData_NoConflict() { // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); // Verifications Assertion.AssertEquals(4, values.Count); Assertion.AssertEquals("4.5", defaultToolsVersion); Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath); Assertion.AssertEquals(@"D:\somepath2", values["3.5"].ToolsPath); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["4.5"].ToolsPath); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["5.0"].ToolsPath); } /// /// Tests that ToolsetInitialization are respected. /// [Test] public void ToolsetInitializationFlagsSetToNone() { // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); RegistryKey key2 = testRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.None ); // Verifications Assertion.AssertEquals(1, values.Count); string expectedDefault = "2.0"; if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { expectedDefault = "4.0"; } Assertion.AssertEquals(expectedDefault, defaultToolsVersion); } /// /// Tests that ToolsetInitialization are respected. /// [Test] public void ToolsetInitializationFlagsSetToRegistry() { // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); // Verifications Assertion.AssertEquals(2, values.Count); Assertion.AssertEquals("2.0", defaultToolsVersion); Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath); Assertion.AssertEquals(@"D:\somepath2", values["3.5"].ToolsPath); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void ThrowOnNonStringRegistryValueTypes() { RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0"); rk.SetValue("MSBuildBinPath", "someBinPath"); // Non-string rk.SetValue("QuadWordValue", 42, RegistryValueKind.QWord); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // Should throw ... string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } [Test] public void PropertiesInRegistryCannotReferToOtherPropertiesInRegistry() { RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0"); rk.SetValue("MSBuildBinPath", "c:\\x$(p1)"); rk.SetValue("p0", "$(p1)"); rk.SetValue("p1", "v"); rk.SetValue("p2", "$(p1)"); rk.SetValue("MSBuildToolsPath", "c:\\x$(p1)"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("", values["2.0"].BuildProperties["p0"].Value); Assertion.AssertEquals("v", values["2.0"].BuildProperties["p1"].Value); Assertion.AssertEquals("", values["2.0"].BuildProperties["p2"].Value); Assertion.AssertEquals("c:\\x", values["2.0"].ToolsPath); } /// /// Tests that ToolsetInitialization are respected. /// [Test] public void ToolsetInitializationFlagsSetToConfigurationFile() { // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); // Verifications Assertion.AssertEquals(2, values.Count); Assertion.AssertEquals("4.5", defaultToolsVersion); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["4.5"].ToolsPath); Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["5.0"].ToolsPath); } /// /// Properties in the configuration file may refer to a registry location by using the syntax for example /// "$(Registry:HKEY_LOCAL_MACHINE\Software\Vendor\Tools@TaskLocation)", where "HKEY_LOCAL_MACHINE\Software\Vendor\Tools" is the key and /// "TaskLocation" is the name of the value. The name of the value and the preceding "@" may be omitted if /// the default value is desired. /// [Test] public void PropertyInConfigurationFileReferencesRegistryLocation() { // Registry Read RegistryKey key1 = Registry.CurrentUser.CreateSubKey(@"Software\Vendor\Tools"); key1.SetValue("TaskLocation", @"somePathToTasks"); key1.SetValue("TargetsLocation", @"D:\somePathToTargets"); key1.SetValue("SchemaLocation", @"Schemas"); key1.SetValue(null, @"D:\somePathToDefault"); //this sets the default value for this key ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(@"D:\somePathToTasks", values["2.0"].ToolsPath); Assertion.AssertEquals(2, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\somePathToDefault", values["2.0"].BuildProperties["p1"].Value); Assertion.AssertEquals(@"D:\somePathToDefault\somePathToTasks\Schemas\2.0", values["2.0"].BuildProperties["p2"].Value); Registry.CurrentUser.DeleteSubKeyTree(@"Software\Vendor"); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void ToolsPathInRegistryHasInvalidPathChars() { currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\some\foo|bar\path\"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); // should throw... string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), null, new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void SamePropertyDefinedMultipleTimesForSingleToolsVersionInConfigurationFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void SamePropertyDifferentCaseDefinedMultipleTimesForSingleToolsVersionInConfigurationFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void SameToolsVersionDefinedMultipleTimesInConfigurationFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void SameToolsVersionDifferentCaseDefinedMultipleTimesInConfigurationFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void CannotSetReservedPropertyInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); } [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void CannotSetReservedPropertyInRegistry() { // Registry Read RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); key1.SetValue("MSBuildProjectFile", @"SomeRegistryValue"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), null, new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); } /// /// Properties defined in previously processed toolset definitions should /// not affect the evaluation of subsequent toolset definitions. /// [Test] public void NoInterferenceBetweenToolsetDefinitions() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, null, new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); Assertion.AssertEquals(2, values.Count); Assertion.AssertEquals(@"D:\20\some\folder\on\disk", values["2.0"].ToolsPath); Assertion.AssertEquals(2, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"another", values["2.0"].BuildProperties["p1"].Value); Assertion.AssertEquals(@"fourthValue", values["2.0"].BuildProperties["p4"].Value); Assertion.AssertEquals(@"D:\35\some\folder\on\disk", values["3.5"].ToolsPath); Assertion.AssertEquals(2, values["3.5"].BuildProperties.Count); Assertion.AssertEquals(@"somevalue", values["3.5"].BuildProperties["p2"].Value); Assertion.AssertEquals(@"propertyValue", values["3.5"].BuildProperties["p3"].Value); } /// /// Properties in the configuration file may refer to a registry location by using the syntax for example /// "$(Registry:HKEY_LOCAL_MACHINE\Software\Vendor\Tools@TaskLocation)", where "HKEY_LOCAL_MACHINE\Software\Vendor\Tools" is the key and /// "TaskLocation" is the name of the value. The name of the value and the preceding "@" may be omitted if /// the default value is desired. /// [Test] public void ConfigFileInvalidRegistryExpression1() { // No location ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression2() { // Bogus key expression ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression3() { // No registry location just @ ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression4() { // Double @ ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression5() { // Trailing @ ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression6() { // Leading @ ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileInvalidRegistryExpression7() { // Bogus hive ConfigFileInvalidRegistryExpressionHelper(@""); } [Test] public void ConfigFileStringEmptyRegistryExpression1() { // Regular undefined property beginning with "Registry" ConfigFileValidRegistryExpressionHelper(@"", String.Empty); } [Test] public void ConfigFileStringEmptyRegistryExpression2() { // Nonexistent key ConfigFileValidRegistryExpressionHelper(@"", String.Empty); } [Test] public void ConfigFileNonPropertyRegistryExpression1() { // Property not terminated with paren, does not look like property ConfigFileValidRegistryExpressionHelper(@"", @"$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation"); } [Test] public void ConfigFileNonPropertyRegistryExpression2() { // Missing colon, looks like regular property (admittedly with invalid property name chars, but we don't // error for that today) ConfigFileValidRegistryExpressionHelper(@"", String.Empty); } [Test] public void ConfigFileItemExpressionsDoNotExpandInConfigurationProperties() { // Expect that item expressions such as '@(SomeItem)' are not evaluated in any way, e.g., they are treated literally ConfigFileValidRegistryExpressionHelper(@"", @"@(SomeItem)"); } [Test] public void RegistryInvalidRegistryExpression1() { // Bogus key expression RegistryInvalidRegistryExpressionHelper("$(Registry:__bogus__)"); } [Test] public void RegistryValidRegistryExpression1() { // Regular undefined property beginning with "Registry" RegistryValidRegistryExpressionHelper("$(Registry)", String.Empty); } [Test] public void RegistryValidRegistryExpressionRecursive() { // Property pointing to itself - should not hang :-) RegistryValidRegistryExpressionHelper (@"$(Registry:HKEY_CURRENT_USER\" + testRegistryPath + @"\ToolsVersions\2.0@p)", @"$(Registry:HKEY_CURRENT_USER\" + testRegistryPath + @"\ToolsVersions\2.0@p)"); } private void RegistryInvalidRegistryExpressionHelper(string propertyExpression) { bool caught = false; try { // this should throw... RegistryValidRegistryExpressionHelper(propertyExpression, String.Empty); } catch (InvalidToolsetDefinitionException ex) { Console.WriteLine(ex.Message); caught = true; } Assertion.AssertEquals(true, caught); } private void RegistryValidRegistryExpressionHelper(string propertyExpression, string expectedValue) { // Registry Read currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", "xxxx"); key1.SetValue("p", propertyExpression); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(expectedValue, values["2.0"].BuildProperties["p"].Value); } /// /// Tests that an invalid registry property expression causes an exception (resulting in a project load error) /// /// private void ConfigFileInvalidRegistryExpressionHelper(string propertyExpression) { bool caught = false; try { // this should throw... ConfigFileValidRegistryExpressionHelper(propertyExpression, String.Empty); } catch (InvalidToolsetDefinitionException ex) { Console.WriteLine(ex.Message); caught = true; } Assertion.AssertEquals(true, caught); } /// /// Tests that a specified registry property expression evaluates to specified value /// /// private void ConfigFileValidRegistryExpressionHelper(string propertyExpression, string expectedValue) { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
" + propertyExpression + @" "); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(expectedValue, values["2.0"].BuildProperties["p"].Value); } /// /// Tests the case where application configuration file overrides a value already specified in the registry /// [Test] public void GetToolsetData_ConflictingPropertyValuesSameCase() { // Registry Read RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\somedifferentpath", values["2.0"].ToolsPath); } /// /// Tests when properties are defined in the registry as /// well as in the config file for the same tools version. /// We should not merge them; we should take the config file ones only /// [Test] public void GetToolsetData_NoMerging() { // Registry Read RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); key1.SetValue("SomeRegistryProperty", @"SomeRegistryValue"); // Set the config file contents as needed ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(1, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\someotherpath", values["2.0"].ToolsPath); Assertion.AssertEquals(null, values["2.0"].BuildProperties["SomeRegistryProperty"]); // Was zapped Assertion.AssertEquals(@"SomeConfigValue", values["2.0"].BuildProperties["SomeConfigProperty"].Value); } /// /// The absence of the ToolsVersion attribute on the main Project element in a project file means /// that the engine's default tools version should be used. /// [Test] public void ToolsVersionAttributeNotSpecifiedOnProjectElementAndDefaultVersionSpecifiedInRegistry() { Engine e = new Engine(); e.AddToolset(new Toolset("2.0", "20toolsPath")); e.AddToolset(new Toolset("4.0", "40toolsPath")); string projectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("x.proj", @""); Project project = e.CreateNewProject(); project.Load(projectPath); Assertion.AssertEquals("2.0", project.ToolsVersion); Assertion.AssertEquals("2.0", project.DefaultToolsVersion); } /// /// Tests the case when no values are specified in the registry /// [Test] public void GetToolsetData_RegistryNotPresent() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\somedifferentpath", values["2.0"].ToolsPath); } /// /// Test the case where nothing is specified in the config file /// Note that config file not present is same as config file /// with no MSBuildToolsets Section /// [Test] public void GetToolsetData_ConfigFileNotPresent() { // Registry Read RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1, values.Count); Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count); Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath); } /// /// Tests the case where nothing is specified in registry and config file /// [Test] public void GetToolsetData_RegistryAndConfigNotPresent() { ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals(1 /* fallback */, values.Count); } /// /// Tests the case when reading config file throws an exception /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetData_ReadConfigThrowsException() { // Registry Read RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); // Set the config helper to throw exception ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationException()); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); } /// /// Tests the case where reading from registry throws exception /// [Test] [ExpectedException(typeof(InvalidToolsetDefinitionException))] public void GetToolsetData_ReadRegistryOpenSubKeyThrowsException() { RegistryKeyWrapper mockRegistryKey = new MockRegistryKey(testRegistryPath, MockRegistryKey.WhereToThrow.OpenSubKey); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(mockRegistryKey), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); } #endregion #region "SetDefaultToolsetVersion tests" /// /// Tests that the default ToolsVersion is correctly resolved when specified /// in registry and config file /// [Test] public void SetDefaultToolsetVersion_SpecifiedInRegistryAndConfigFile() { // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0"); RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0"); key1.SetValue("MSBuildBinPath", @"D:\somepath"); RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("5.0", defaultToolsVersion); } /// /// Tests that the default ToolsVersion is correctly resolved when specified in registry only /// [Test] public void SetDefaultToolsetVersion_SpecifiedOnlyInRegistry() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); // Set up registry with two tools versions and one property each currentVersionRegistryKey.SetValue("DefaultToolsVersion", "3.5"); RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5"); key2.SetValue("MSBuildBinPath", @"D:\somepath2"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("3.5", defaultToolsVersion); } /// /// Tests that the default ToolsVersion is correctly resolved /// when specified in config file only /// [Test] public void SetDefaultToolsetVersion_SpecifiedOnlyInConfigFile() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("5.0", defaultToolsVersion); } /// /// Tests that the default ToolsVersion is correctly resolved when specified nowhere /// [Test] public void SetDefaultToolsetVersion_SpecifiedNowhere() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), new BuildPropertyGroup(), ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); string expectedDefault = "2.0"; if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null) { expectedDefault = "4.0"; } Assertion.AssertEquals(expectedDefault, defaultToolsVersion); // built-in default } /// /// Tests that properties are properly expanded when reading them from the config file /// [Test] public void PropertiesInToolsetsFromConfigFileAreExpanded() { // $(COMPUTERNAME) is just a convenient env var. $(NUMBER_OF_PROCESSORS) isn't defined on Longhorn ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); Engine e = new Engine(); BuildPropertyGroup initialProperties = new BuildPropertyGroup(); initialProperties.ImportProperties(e.EnvironmentProperties); initialProperties.ImportProperties(e.GlobalProperties); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), initialProperties, ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("v1", values["3.5"].BuildProperties["p1"].Value); // Properties can refer to other properties also defined in the config file Assertion.AssertEquals("__v1__", values["3.5"].BuildProperties["p2"].Value); Assertion.AssertEquals(Environment.MachineName, values["3.5"].BuildProperties["p3"].Value); } /// /// Tests that properties in MSBuildToolsPath are properly expanded when reading them from the config file /// [Test] public void PropertiesInToolsetsFromConfigFileAreExpandedInToolsPath() { // $(COMPUTERNAME) is just a convenient env var. $(NUMBER_OF_PROCESSORS) isn't defined on Longhorn ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None)); Engine e = new Engine(); BuildPropertyGroup initialProperties = new BuildPropertyGroup(); initialProperties.ImportProperties(e.EnvironmentProperties); initialProperties.ImportProperties(e.GlobalProperties); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), new BuildPropertyGroup(), initialProperties, ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("Microsoft.NET", values["3.5"].BuildProperties["p1"].Value); Assertion.AssertEquals("windows", values["3.5"].BuildProperties["p2"].Value); string expectedToolsPath = @"D:\windows\Microsoft.NET\Framework\v2.0.x86ret\" + Environment.MachineName; Assertion.AssertEquals(expectedToolsPath, values["3.5"].ToolsPath); Assertion.AssertEquals("v3" + expectedToolsPath, values["3.5"].BuildProperties["p3"].Value); } /// /// Global properties are available, but they cannot be overwritten by other toolset properties, just as they cannot /// be overwritten by project file properties. /// [Test] public void GlobalPropertiesInToolsetsAreExpandedButAreNotOverwritten() { ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
"); Engine e = new Engine(ToolsetDefinitionLocations.None); ToolsetCollection values = new ToolsetCollection(e); BuildPropertyGroup globalProperties = e.GlobalProperties; globalProperties.SetProperty("gp1", "gv1"); BuildPropertyGroup initialProperties = new BuildPropertyGroup(); initialProperties.ImportProperties(e.EnvironmentProperties); initialProperties.ImportProperties(globalProperties); string defaultToolsVersion = ToolsetReader.ReadAllToolsets ( values, new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)), new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)), globalProperties, initialProperties, ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry ); Assertion.AssertEquals("gv1", values["3.5"].BuildProperties["p1"].Value); Assertion.AssertEquals("gv1", values["3.5"].BuildProperties["p2"].Value); } #endregion } internal class MockRegistryKey : RegistryKeyWrapper { public enum WhereToThrow { None, Name, GetValue, GetValueNames, GetSubKeyNames, OpenSubKey } private WhereToThrow whereToThrow = WhereToThrow.None; private string subKeyThatDoesNotExist = null; /// /// Construct the mock key with a specified key /// /// protected MockRegistryKey(RegistryKey wrappedKey, RegistryKey registryHive) : base(wrappedKey, registryHive) { } /// /// Construct the mock key with a wrapper /// /// public MockRegistryKey(string path) : base(path, Registry.CurrentUser) { } /// /// Construct the mock key with a wrapper and a designated method /// to throw from /// /// /// public MockRegistryKey(string path, WhereToThrow whereToThrow) : base(path, Registry.CurrentUser) { this.whereToThrow = whereToThrow; } /// /// Construct the mock key with a wrapper and a designated subkey /// to refuse to open /// /// /// public MockRegistryKey(string path, string subKeyThatDoesNotExist) : base(path, Registry.CurrentUser) { this.subKeyThatDoesNotExist = subKeyThatDoesNotExist; } /// /// Name of the registry key /// public override string Name { get { if (whereToThrow == WhereToThrow.Name) { throw new RegistryException("registryException", "registry"); } return base.Name; } } /// /// Gets the value with name "name" stored under this registry key /// public override object GetValue(string name) { if (whereToThrow == WhereToThrow.GetValue) { throw new RegistryException("registryException", "registry"); } return base.GetValue(name); } /// /// Gets the names of all values underneath this registry key /// public override string[] GetValueNames() { if (whereToThrow == WhereToThrow.GetValueNames) { throw new RegistryException("registryException", "registry"); } return base.GetValueNames(); } /// /// Gets the names of all sub keys immediately below this registry key /// /// public override string[] GetSubKeyNames() { if (whereToThrow == WhereToThrow.GetSubKeyNames) { throw new RegistryException("registryException", "registry"); } return base.GetSubKeyNames(); } /// /// Returns the sub key with name "name" as a read only key /// public override RegistryKeyWrapper OpenSubKey(string name) { if (whereToThrow == WhereToThrow.OpenSubKey) { throw new RegistryException("registryException", "registry"); } if (subKeyThatDoesNotExist == name) { // Return wrapper around null key return new MockRegistryKey((RegistryKey)null, Registry.LocalMachine); } return base.OpenSubKey(name); } } }