1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 using System;
5 using System.IO;
6 using System.Collections.Generic;
7 using System.Configuration;
8 using Microsoft.Win32;
9 using System.Text;
10 using NUnit.Framework;
11 using Microsoft.Build.BuildEngine;
12 using Microsoft.Build.BuildEngine.Shared;
13 
14 namespace Microsoft.Build.UnitTests
15 {
16     /// <summary>
17     /// Unit tests for ToolsetReader class and its derived classes
18     /// </summary>
19     [TestFixture]
20     public class ToolsetReaderTests
21     {
22         // The registry key that is passed as the baseKey parameter to the ToolsetRegistryReader class
23         private RegistryKey testRegistryKey = null;
24         // Subkey "4.0"
25         private RegistryKey currentVersionRegistryKey = null;
26         // Subkey "ToolsVersions"
27         private RegistryKey toolsVersionsRegistryKey = null;
28 
29         // Path to the registry key under HKCU
30         // Note that this is a test registry key created solely for unit testing.
31         private const string testRegistryPath = @"msbuildUnitTests";
32 
33         /// <summary>
34         /// Reset the testRegistryKey
35         /// </summary>
36         [SetUp]
Setup()37         public void Setup()
38         {
39             TearDown();
40             testRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath);
41             currentVersionRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath + "\\" + Constants.AssemblyVersion);
42             toolsVersionsRegistryKey = Registry.CurrentUser.CreateSubKey(testRegistryPath + "\\ToolsVersions");
43         }
44 
45         [TearDown]
TearDown()46         public void TearDown()
47         {
48             ToolsetConfigurationReaderTestHelper.CleanUp();
49 
50             DeleteTestRegistryKey();
51         }
52 
53         /// <summary>
54         /// Helper class to delete the testRegistryKey tree.
55         /// </summary>
DeleteTestRegistryKey()56         private void DeleteTestRegistryKey()
57         {
58             if (Registry.CurrentUser.OpenSubKey(testRegistryPath) != null)
59             {
60                 Registry.CurrentUser.DeleteSubKeyTree(testRegistryPath);
61             }
62         }
63 
64         /// <summary>
65         /// Test to make sure machine.config file has the section registered
66         /// and we are picking it up from there.
67         /// </summary>
68         [Test]
GetToolsetDataFromConfiguration_SectionNotRegisteredInConfigFile()69         public void GetToolsetDataFromConfiguration_SectionNotRegisteredInConfigFile()
70         {
71             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
72                  <configuration>
73                    <configSections>
74                    </configSections>
75                    <msbuildToolsets>
76                      <toolset toolsVersion=""2.0"">
77                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
78                      </toolset>
79                    </msbuildToolsets>
80                  </configuration>");
81 
82             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
83                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
84 
85             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
86             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
87 
88             Assertion.AssertEquals(null, defaultToolsVersion);
89             Assertion.AssertEquals(0, values.Count);
90         }
91 
92         #region "Reading from application configuration file tests"
93 
94         /// <summary>
95         /// Tests that the data is correctly populated using function GetToolsetDataFromConfiguration
96         /// </summary>
97         [Test]
98         public void GetToolsetDataFromConfiguration_Basic()
99         {
100             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
101                  <configuration>
102                    <configSections>
103                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
104                    </configSections>
105                    <msbuildToolsets default=""2.0"">
106                      <toolset toolsVersion=""2.0"">
107                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
108                      </toolset>
109                      <toolset toolsVersion=""3.5"">
110                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
111                      </toolset>
112                    </msbuildToolsets>
113                  </configuration>");
114 
115             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
116                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
117 
118             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
119             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
120 
121             Assertion.AssertEquals("2.0", defaultToolsVersion);
122             Assertion.AssertEquals(2, values.Count);
123             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
124             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath);
125             Assertion.AssertEquals(0, values["3.5"].BuildProperties.Count);
126             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["3.5"].ToolsPath);
127         }
128 
129         /// <summary>
130         /// Relative paths can be used in a config file value
131         /// </summary>
132         [Test]
133         public void RelativePathInValue()
134         {
135             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
136                  <configuration>
137                    <configSections>
138                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
139                    </configSections>
140                    <msbuildToolsets default=""2.0"">
141                      <toolset toolsVersion=""2.0"">
142                        <property name=""MSBuildToolsPath"" value=""..\foo""/>
143                        <!-- derelativization occurs before comparing toolspath and binpath -->
144                        <property name=""MSBuildBinPath"" value=""..\.\foo""/>
145                      </toolset>
146                      <toolset toolsVersion=""3.0"">
147                        <!-- properties are expanded before derelativization-->
148                        <property name=""MSBuildBinPath"" value=""$(DotDotSlash)bar""/>
149                      </toolset>
150                    </msbuildToolsets>
151                  </configuration>");
152 
153             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
154                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
155 
156             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
157             BuildPropertyGroup pg = new BuildPropertyGroup();
158             pg.SetProperty("DotDotSlash", @"..\");
159             reader.ReadToolsets(values, new BuildPropertyGroup(), pg, true);
160 
161             string expected1 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\foo"));
162             string expected2 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\bar"));
163             Console.WriteLine(values["2.0"].ToolsPath);
164             Assertion.AssertEquals(expected1, values["2.0"].ToolsPath);
165             Assertion.AssertEquals(expected2, values["3.0"].ToolsPath);
166         }
167 
168         /// <summary>
169         /// Invalid relative path in msbuildbinpath value
170         /// </summary>
171         [Test]
172         public void InvalidRelativePath()
173         {
174             string invalidRelativePath = @"..\|invalid|";
175             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
176                  <configuration>
177                    <configSections>
178                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
179                    </configSections>
180                    <msbuildToolsets default=""2.0"">
181                      <toolset toolsVersion=""2.0"">
182                        <property name=""MSBuildBinPath"" value=""" + invalidRelativePath + @"""/>
183                      </toolset>
184                    </msbuildToolsets>
185                  </configuration>");
186 
187             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
188                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
189 
190             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
191             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
192 
193             // Don't crash (consistent with invalid absolute path)
194             Assertion.AssertEquals(invalidRelativePath, values["2.0"].ToolsPath);
195         }
196 
197         /// <summary>
198         /// Tests the case where application configuration file is invalid
199         /// </summary>
200         [Test]
201         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
202         public void GetToolsetDataFromConfiguration_InvalidXmlFile()
203         {
204             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"<INVALIDXML>");
205 
206             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
207                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
208 
209             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
210 
211             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
212         }
213 
214         /// <summary>
215         /// Tests the case where application configuration file is invalid
216         /// </summary>
217         [Test]
218         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
219         public void GetToolsetDataFromConfiguration_InvalidConfigFile()
220         {
221             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
222                  <configuration>
223                    <configSections>
224                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
225                    </configSections>
226                    <msbuildToolsets>
227                      <toolset toolsVersion=""2.0"">
228                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
229                      </toolsVersion>
230                      <SOMEINVALIDTAG/>
231                    </msbuildToolsets>
232                  </configuration>");
233 
234             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
235                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
236 
237             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
238 
239             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
240         }
241 
242         /// <summary>
243         /// Tests the case where application configuration file is empty
244         /// </summary>
245         [Test]
246         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
247         public void GetToolsetDataFromConfiguration_FileEmpty()
248         {
249             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"");
250 
251             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
252                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
253 
254             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
255 
256             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
257         }
258 
259         /// <summary>
260         /// Tests the case when ReadConfiguration throws exception
261         /// Make sure that we don't eat it and always throw ConfigurationErrorsException
262         /// </summary>
263         [Test]
264         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
265         public void GetToolsetDataFromConfiguration_ConfigurationExceptionThrown()
266         {
267             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationException());
268 
269             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
270                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
271 
272             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
273 
274             // this should throw ...
275             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
276         }
277 
278         /// <summary>
279         /// Tests the case when ReadConfiguration throws exception
280         /// Make sure that we don't eat it and always throw ConfigurationErrorsException
281         /// </summary>
282         [Test]
283         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
284         public void GetToolsetDataFromConfiguration_ConfigurationErrorsExceptionThrown()
285         {
286             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationErrorsException());
287 
288             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
289                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
290 
291             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
292 
293             // this should throw ...
294             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
295         }
296 
297         /// <summary>
298         /// Tests the case where default attribute is not specified in the config file
299         /// </summary>
300         [Test]
301         public void GetToolsetDataFromConfiguration_DefaultAttributeNotSpecified()
302         {
303             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
304                  <configuration>
305                    <configSections>
306                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
307                    </configSections>
308                    <msbuildToolsets>
309                      <toolset toolsVersion=""2.0"">
310                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
311                      </toolset>
312                    </msbuildToolsets>
313                  </configuration>");
314 
315             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
316                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
317 
318             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
319 
320             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
321 
322             Assertion.AssertEquals(null, defaultToolsVersion);
323             Assertion.AssertEquals(1, values.Count);
324             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
325             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath);
326         }
327 
328         /// <summary>
329         /// Default toolset has no toolsVersion element definition
330         /// </summary>
331         [Test]
332         public void GetToolsetDataFromConfiguration_DefaultToolsetUndefined()
333         {
334             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
335                  <configuration>
336                    <configSections>
337                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
338                    </configSections>
339                    <msbuildToolsets default=""nonexistent"">
340                      <toolset toolsVersion=""2.0"">
341                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
342                      </toolset>
343                    </msbuildToolsets>
344                  </configuration>");
345 
346             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
347                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
348 
349             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
350 
351             // Does not throw
352             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
353         }
354 
355         /// <summary>
356         /// Tests the case where msbuildToolsets is not specified in the config file
357         /// Basically in the code we should be checking if config.GetSection("msbuildToolsets") returns a null
358         /// </summary>
359         [Test]
360         public void GetToolsetDataFromConfiguration_MSBuildToolsetsNodeNotPresent()
361         {
362             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
363                  <configuration>
364                    <configSections>
365                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
366                    </configSections>
367                  </configuration>");
368 
369             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
370                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
371 
372             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
373 
374             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
375 
376             Assertion.AssertEquals(null, defaultToolsVersion);
377             Assertion.AssertEquals(0, values.Count);
378         }
379 
380         /// <summary>
381         /// Tests that we handle empty MSBuildToolsets element correctly
382         /// </summary>
383         [Test]
384         public void GetToolsetDataFromConfiguration_EmptyMSBuildToolsetsNode()
385         {
386             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
387                  <configuration>
388                    <configSections>
389                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
390                    </configSections>
391                    <msbuildToolsets/>
392                  </configuration>");
393 
394             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
395                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
396 
397             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
398 
399             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
400 
401             Assertion.AssertEquals(null, defaultToolsVersion);
402             Assertion.AssertEquals(0, values.Count);
403         }
404 
405         /// <summary>
406         /// Tests the case where only default ToolsVersion is specified in the application configuration file
407         /// </summary>
408         [Test]
409         public void GetToolsetDataFromConfiguration_OnlyDefaultSpecified()
410         {
411             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
412                  <configuration>
413                    <configSections>
414                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
415                    </configSections>
416                    <msbuildToolsets default=""2.0""/>
417                  </configuration>");
418 
419             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
420                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
421 
422             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
423 
424             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
425         }
426 
427         /// <summary>
428         /// Tests the case where only one ToolsVersion data is specified in the application configuration file
429         /// </summary>
430         [Test]
431         public void GetToolsetDataFromConfiguration_OneToolsVersionNode()
432         {
433             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
434                  <configuration>
435                    <configSections>
436                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
437                    </configSections>
438                    <msbuildToolsets default=""2.0"">
439                      <toolset toolsVersion=""2.0"">
440                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
441                      </toolset>
442                    </msbuildToolsets>
443                  </configuration>");
444 
445             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
446                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
447 
448             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
449 
450             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
451 
452             Assertion.AssertEquals("2.0", defaultToolsVersion);
453             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath);
454             Assertion.AssertEquals(1, values.Count);
455         }
456 
457         /// <summary>
458         /// Tests the case when an invalid value of ToolsVersion is specified
459         /// </summary>
460         [Test]
461         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
462         public void GetToolsetDataFromConfiguration_ToolsVersionIsEmptyString()
463         {
464             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
465                  <configuration>
466                    <configSections>
467                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
468                    </configSections>
469                    <msbuildToolsets default=""2.0"">
470                      <toolset toolsVersion="""">
471                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
472                      </toolset>
473                      <toolset toolsVersion=""3.5"">
474                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
475                      </toolset>
476                    </msbuildToolsets>
477                  </configuration>");
478 
479             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
480                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
481 
482             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
483 
484             //this should throw ...
485             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
486         }
487 
488         /// <summary>
489         /// If both MSBuildToolsPath and MSBuildBinPath are present, they must match
490         /// </summary>
491         [Test]
492         public void GetToolsetDataFromConfiguration_ToolsPathAndBinPathDiffer()
493         {
494             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
495                  <configuration>
496                    <configSections>
497                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
498                    </configSections>
499                    <msbuildToolsets default=""2.0"">
500                      <toolset toolsVersion=""2.0"">
501                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
502                        <property name=""MSBuildToolsPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
503                      </toolset>
504                    </msbuildToolsets>
505                  </configuration>");
506 
507             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
508                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
509 
510             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
511 
512             //this should throw ...
513             bool caught = false;
514             try
515             {
516                 reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
517             }
518             catch (InvalidToolsetDefinitionException)
519             {
520                 caught = true;
521             }
522             Assertion.Assert(caught);
523         }
524 
525         /// <summary>
526         /// Tests the case when a blank value of PropertyName is specified in the config file
527         /// </summary>
528         [Test]
529         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
530         public void BlankPropertyNameInConfigFile()
531         {
532             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
533                  <configuration>
534                    <configSections>
535                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
536                    </configSections>
537                    <msbuildToolsets default=""2.0"">
538                      <toolset toolsVersion=""2.0"">
539                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
540                        <property name="""" value=""foo""/>
541                      </toolset>
542                    </msbuildToolsets>
543                  </configuration>");
544 
545             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
546                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
547 
548             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
549 
550             //this should throw ...
551             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
552         }
553 
554         /// <summary>
555         /// Tests the case when a blank property name is specified in the registry
556         /// </summary>
557         [Test]
558         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
559         public void BlankPropertyNameInRegistry()
560         {
561             RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0");
562             rk.SetValue("MSBuildBinPath", "someBinPath");
563             rk.SetValue("", "foo");
564 
565             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
566 
567             // Should throw ...
568             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
569                                                        (
570                                                            values,
571                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
572                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
573                                                            new BuildPropertyGroup(),
574                                                            new BuildPropertyGroup(),
575                                                            ToolsetDefinitionLocations.Registry
576                                                        );
577         }
578 
579         /// <summary>
580         /// Tests the case when a blank property value is specified in the config file
581         /// </summary>
582         [Test]
583         public void BlankPropertyValueInConfigFile()
584         {
585             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
586                  <configuration>
587                    <configSections>
588                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
589                    </configSections>
590                    <msbuildToolsets default=""2.0"">
591                      <toolset toolsVersion=""2.0"">
592                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
593                        <property name=""foo"" value=""""/>
594                      </toolset>
595                    </msbuildToolsets>
596                  </configuration>");
597 
598             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
599                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
600 
601             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
602 
603             //this should not throw ...
604             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
605         }
606 
607         /// <summary>
608         /// Tests the case when a blank property value is specified in the registry
609         /// </summary>
610         [Test]
611         public void BlankPropertyValueInRegistry()
612         {
613             RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0");
614             rk.SetValue("MSBuildBinPath", "someBinPath");
615             rk.SetValue("foo", "");
616 
617             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
618 
619             // Should not throw ...
620             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
621                                                        (
622                                                            values,
623                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
624                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
625                                                            new BuildPropertyGroup(),
626                                                            new BuildPropertyGroup(),
627                                                            ToolsetDefinitionLocations.Registry
628                                                        );
629         }
630 
631         /// <summary>
632         /// Tests the case when an invalid value of PropertyName is specified in the config file
633         /// </summary>
634         [Test]
635         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
636         public void InvalidPropertyNameInConfigFile()
637         {
638             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
639                  <configuration>
640                    <configSections>
641                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
642                    </configSections>
643                    <msbuildToolsets default=""2.0"">
644                      <toolset toolsVersion=""2.0"">
645                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
646                        <property name=""&amp;"" value=""foo""/>
647                      </toolset>
648                    </msbuildToolsets>
649                  </configuration>");
650 
651             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
652                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
653 
654             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
655 
656             //this should throw ...
657             reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
658         }
659 
660         /// <summary>
661         /// Tests the case when an invalid value of PropertyName is specified in the registry
662         /// </summary>
663         [Test]
664         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
665         public void InvalidPropertyNameInRegistry()
666         {
667             RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0");
668             rk.SetValue("MSBuildBinPath", "someBinPath");
669             rk.SetValue("foo|bar", "x");
670 
671             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
672 
673             // Should throw ...
674             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
675                                                        (
676                                                            values,
677                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
678                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
679                                                            new BuildPropertyGroup(),
680                                                            new BuildPropertyGroup(),
681                                                            ToolsetDefinitionLocations.Registry
682                                                        );
683         }
684 
685         /// <summary>
686         /// Tests that empty string is an invalid value for MSBuildBinPath
687         /// </summary>
688         [Test]
689         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
690         public void GetToolsetDataFromConfiguration_PropertyValueIsEmptyString1()
691         {
692             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
693                  <configuration>
694                    <configSections>
695                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
696                    </configSections>
697                    <msbuildToolsets default=""2.0"">
698                      <toolset toolsVersion=""2.0"">
699                        <property name=""MSBuildBinPath"" value=""""/>
700                      </toolset>
701                    </msbuildToolsets>
702                  </configuration>");
703 
704             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
705                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
706 
707             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
708 
709             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
710 
711             Assertion.AssertEquals(1, values.Count);
712             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
713             Assertion.AssertEquals(String.Empty, values["2.0"].ToolsPath);
714         }
715 
716         /// <summary>
717         /// Tests that empty string is a valid property value for an arbitrary property
718         /// </summary>
719         [Test]
720         public void GetToolsetDataFromConfiguration_PropertyValueIsEmptyString2()
721         {
722             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
723                  <configuration>
724                    <configSections>
725                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
726                    </configSections>
727                    <msbuildToolsets default=""2.0"">
728                      <toolset toolsVersion=""2.0"">
729                        <property name=""MSBuildToolsPath"" value=""xxx""/>
730                        <property name=""foo"" value=""""/>
731                      </toolset>
732                    </msbuildToolsets>
733                  </configuration>");
734 
735             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
736                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
737 
738             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
739 
740             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
741 
742             Assertion.AssertEquals(1, values.Count);
743             Assertion.AssertEquals(1, values["2.0"].BuildProperties.Count);
744             Assertion.AssertEquals(String.Empty, values["2.0"].BuildProperties["foo"].Value);
745         }
746 
747         /// <summary>
748         /// Tests that any escaped xml in config file, is treated well
749         /// Note that this comes for free with the current implementation using the
750         /// framework api to access section in the config file
751         /// </summary>
752         [Test]
753         public void GetToolsetDataFromConfiguration_XmlEscapedCharacters()
754         {
755             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
756                  <configuration>
757                    <configSections>
758                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
759                    </configSections>
760                    <msbuildToolsets default=""2&gt;.0"">
761                      <toolset toolsVersion=""2&gt;.0"">
762                        <property name=""MSBuildBinPath"" value=""x""/>
763                        <property name=""foo"" value=""some&gt;value""/>
764                      </toolset>
765                    </msbuildToolsets>
766                  </configuration>");
767 
768             ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
769                 ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));
770 
771             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
772 
773             string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
774 
775             Assertion.AssertEquals("2>.0", defaultToolsVersion);
776             Assertion.AssertEquals(1, values.Count);
777             Assertion.AssertEquals(@"some>value", values["2>.0"].BuildProperties["foo"].Value);
778         }
779         #endregion
780 
781         #region "GetToolsetData tests"
782 
783         /// <summary>
784         /// Tests the case where registry and config file contains different toolsVersion
785         /// </summary>
786         [Test]
787         public void GetToolsetData_NoConflict()
788         {
789             // Set up registry with two tools versions and one property each
790             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
791             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
792             key1.SetValue("MSBuildBinPath", @"D:\somepath");
793             RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5");
794             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
795 
796             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
797                  <configuration>
798                    <configSections>
799                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
800                    </configSections>
801                    <msbuildToolsets default=""4.5"">
802                      <toolset toolsVersion=""4.5"">
803                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
804                      </toolset>
805                      <toolset toolsVersion=""5.0"">
806                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
807                      </toolset>
808                    </msbuildToolsets>
809                  </configuration>");
810 
811             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
812 
813             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
814                                                        (
815                                                            values,
816                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
817                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
818                                                            new BuildPropertyGroup(),
819                                                            new BuildPropertyGroup(),
820                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
821                                                        );
822 
823             // Verifications
824             Assertion.AssertEquals(4, values.Count);
825             Assertion.AssertEquals("4.5", defaultToolsVersion);
826             Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath);
827             Assertion.AssertEquals(@"D:\somepath2", values["3.5"].ToolsPath);
828             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["4.5"].ToolsPath);
829             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["5.0"].ToolsPath);
830         }
831 
832         /// <summary>
833         /// Tests that ToolsetInitialization are respected.
834         /// </summary>
835         [Test]
836         public void ToolsetInitializationFlagsSetToNone()
837         {
838             // Set up registry with two tools versions and one property each
839             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
840             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
841             key1.SetValue("MSBuildBinPath", @"D:\somepath");
842             RegistryKey key2 = testRegistryKey.CreateSubKey("3.5");
843             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
844 
845             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
846                  <configuration>
847                    <configSections>
848                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
849                    </configSections>
850                    <msbuildToolsets default=""4.5"">
851                      <toolset toolsVersion=""4.5"">
852                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
853                      </toolset>
854                      <toolset toolsVersion=""5.0"">
855                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
856                      </toolset>
857                    </msbuildToolsets>
858                  </configuration>");
859 
860             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
861 
862             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
863                                                        (
864                                                            values,
865                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
866                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
867                                                            new BuildPropertyGroup(),
868                                                            new BuildPropertyGroup(),
869                                                            ToolsetDefinitionLocations.None
870                                                        );
871 
872             // Verifications
873             Assertion.AssertEquals(1, values.Count);
874 
875             string expectedDefault = "2.0";
876             if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null)
877             {
878                 expectedDefault = "4.0";
879             }
880 
881             Assertion.AssertEquals(expectedDefault, defaultToolsVersion);
882         }
883 
884         /// <summary>
885         /// Tests that ToolsetInitialization are respected.
886         /// </summary>
887         [Test]
888         public void ToolsetInitializationFlagsSetToRegistry()
889         {
890             // Set up registry with two tools versions and one property each
891             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
892             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
893             key1.SetValue("MSBuildBinPath", @"D:\somepath");
894             RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5");
895             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
896 
897             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
898                  <configuration>
899                    <configSections>
900                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
901                    </configSections>
902                    <msbuildToolsets default=""4.5"">
903                      <toolset toolsVersion=""4.5"">
904                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
905                      </toolset>
906                      <toolset toolsVersion=""5.0"">
907                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
908                      </toolset>
909                    </msbuildToolsets>
910                  </configuration>");
911 
912             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
913 
914             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
915                                                        (
916                                                            values,
917                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
918                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
919                                                            new BuildPropertyGroup(),
920                                                            new BuildPropertyGroup(),
921                                                            ToolsetDefinitionLocations.Registry
922                                                        );
923 
924             // Verifications
925             Assertion.AssertEquals(2, values.Count);
926             Assertion.AssertEquals("2.0", defaultToolsVersion);
927             Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath);
928             Assertion.AssertEquals(@"D:\somepath2", values["3.5"].ToolsPath);
929         }
930 
931         [Test]
932         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
933         public void ThrowOnNonStringRegistryValueTypes()
934         {
935             RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0");
936             rk.SetValue("MSBuildBinPath", "someBinPath");
937 
938             // Non-string
939             rk.SetValue("QuadWordValue", 42, RegistryValueKind.QWord);
940 
941             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
942 
943             // Should throw ...
944             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
945                                                        (
946                                                            values,
947                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
948                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
949                                                            new BuildPropertyGroup(),
950                                                            new BuildPropertyGroup(),
951                                                            ToolsetDefinitionLocations.Registry
952                                                        );
953         }
954 
955         [Test]
956         public void PropertiesInRegistryCannotReferToOtherPropertiesInRegistry()
957         {
958             RegistryKey rk = toolsVersionsRegistryKey.CreateSubKey("2.0");
959             rk.SetValue("MSBuildBinPath", "c:\\x$(p1)");
960             rk.SetValue("p0", "$(p1)");
961             rk.SetValue("p1", "v");
962             rk.SetValue("p2", "$(p1)");
963             rk.SetValue("MSBuildToolsPath", "c:\\x$(p1)");
964 
965             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
966 
967             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
968                                                        (
969                                                            values,
970                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
971                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
972                                                            new BuildPropertyGroup(),
973                                                            new BuildPropertyGroup(),
974                                                            ToolsetDefinitionLocations.Registry
975                                                        );
976 
977             Assertion.AssertEquals("", values["2.0"].BuildProperties["p0"].Value);
978             Assertion.AssertEquals("v", values["2.0"].BuildProperties["p1"].Value);
979             Assertion.AssertEquals("", values["2.0"].BuildProperties["p2"].Value);
980             Assertion.AssertEquals("c:\\x", values["2.0"].ToolsPath);
981         }
982 
983         /// <summary>
984         /// Tests that ToolsetInitialization are respected.
985         /// </summary>
986         [Test]
987         public void ToolsetInitializationFlagsSetToConfigurationFile()
988         {
989             // Set up registry with two tools versions and one property each
990             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
991             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
992             key1.SetValue("MSBuildBinPath", @"D:\somepath");
993             RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5");
994             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
995 
996             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
997                  <configuration>
998                    <configSections>
999                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1000                    </configSections>
1001                    <msbuildToolsets default=""4.5"">
1002                      <toolset toolsVersion=""4.5"">
1003                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
1004                      </toolset>
1005                      <toolset toolsVersion=""5.0"">
1006                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
1007                      </toolset>
1008                    </msbuildToolsets>
1009                  </configuration>");
1010 
1011             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1012 
1013             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1014                                                        (
1015                                                            values,
1016                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1017                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1018                                                            new BuildPropertyGroup(),
1019                                                            new BuildPropertyGroup(),
1020                                                            ToolsetDefinitionLocations.ConfigurationFile
1021                                                        );
1022 
1023             // Verifications
1024             Assertion.AssertEquals(2, values.Count);
1025             Assertion.AssertEquals("4.5", defaultToolsVersion);
1026             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["4.5"].ToolsPath);
1027             Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["5.0"].ToolsPath);
1028         }
1029 
1030         /// <summary>
1031         /// Properties in the configuration file may refer to a registry location by using the syntax for example
1032         /// "$(Registry:HKEY_LOCAL_MACHINE\Software\Vendor\Tools@TaskLocation)", where "HKEY_LOCAL_MACHINE\Software\Vendor\Tools" is the key and
1033         /// "TaskLocation" is the name of the value.  The name of the value and the preceding "@" may be omitted if
1034         /// the default value is desired.
1035         /// </summary>
1036         [Test]
1037         public void PropertyInConfigurationFileReferencesRegistryLocation()
1038         {
1039             // Registry Read
1040             RegistryKey key1 = Registry.CurrentUser.CreateSubKey(@"Software\Vendor\Tools");
1041             key1.SetValue("TaskLocation", @"somePathToTasks");
1042             key1.SetValue("TargetsLocation", @"D:\somePathToTargets");
1043             key1.SetValue("SchemaLocation", @"Schemas");
1044             key1.SetValue(null, @"D:\somePathToDefault");  //this sets the default value for this key
1045 
1046             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1047                  <configuration>
1048                    <configSections>
1049                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1050                    </configSections>
1051                    <msbuildToolsets default=""2.0"">
1052                      <toolset toolsVersion=""2.0"">
1053                        <property name=""MSBuildBinPath"" value=""D:\$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation)""/>
1054                        <property name=""p1"" value=""$(p2)$(REGISTRY:HKEY_CURRENT_USER\Software\Vendor\Tools)""/>
1055                        <property name=""p2"" value=""$(p1)\$(Registry:hkey_current_user\Software\Vendor\Tools@TaskLocation)\$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@SchemaLocation)\2.0""/>
1056                      </toolset>
1057                    </msbuildToolsets>
1058                  </configuration>");
1059 
1060             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1061 
1062             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1063                                                        (
1064                                                            values,
1065                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1066                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1067                                                            new BuildPropertyGroup(),
1068                                                            new BuildPropertyGroup(),
1069                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1070                                                        );
1071 
1072             Assertion.AssertEquals(1, values.Count);
1073             Assertion.AssertEquals(@"D:\somePathToTasks", values["2.0"].ToolsPath);
1074             Assertion.AssertEquals(2, values["2.0"].BuildProperties.Count);
1075             Assertion.AssertEquals(@"D:\somePathToDefault", values["2.0"].BuildProperties["p1"].Value);
1076             Assertion.AssertEquals(@"D:\somePathToDefault\somePathToTasks\Schemas\2.0", values["2.0"].BuildProperties["p2"].Value);
1077 
1078             Registry.CurrentUser.DeleteSubKeyTree(@"Software\Vendor");
1079         }
1080 
1081         [Test]
1082         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1083         public void ToolsPathInRegistryHasInvalidPathChars()
1084         {
1085             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
1086             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1087             key1.SetValue("MSBuildBinPath", @"D:\some\foo|bar\path\");
1088 
1089             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1090 
1091             // should throw...
1092             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1093                                                        (
1094                                                            values,
1095                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1096                                                            null,
1097                                                            new BuildPropertyGroup(),
1098                                                            new BuildPropertyGroup(),
1099                                                            ToolsetDefinitionLocations.Registry
1100                                                        );
1101         }
1102 
1103         [Test]
1104         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1105         public void SamePropertyDefinedMultipleTimesForSingleToolsVersionInConfigurationFile()
1106         {
1107             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1108                  <configuration>
1109                    <configSections>
1110                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1111                    </configSections>
1112                    <msbuildToolsets default=""2.0"">
1113                      <toolset toolsVersion=""2.0"">
1114                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1115                        <property name=""p1"" value=""another""/>
1116                        <property name=""MSBuildBinPath"" value=""C:\$(p1)\folder""/>
1117                        <property name=""p1"" value=""newValue""/>
1118                      </toolset>
1119                    </msbuildToolsets>
1120                  </configuration>");
1121 
1122             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1123 
1124             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1125                                                        (
1126                                                            values,
1127                                                            null,
1128                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1129                                                            new BuildPropertyGroup(),
1130                                                            new BuildPropertyGroup(),
1131                                                            ToolsetDefinitionLocations.ConfigurationFile
1132                                                        );
1133         }
1134 
1135         [Test]
1136         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1137         public void SamePropertyDifferentCaseDefinedMultipleTimesForSingleToolsVersionInConfigurationFile()
1138         {
1139             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1140                  <configuration>
1141                    <configSections>
1142                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1143                    </configSections>
1144                    <msbuildToolsets default=""2.0"">
1145                      <toolset toolsVersion=""2.0"">
1146                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1147                        <property name=""p1"" value=""another""/>
1148                        <property name=""mSbUiLdBiNpAtH"" value=""C:\$(p1)\folder""/>
1149                        <property name=""P1"" value=""newValue""/>
1150                      </toolset>
1151                    </msbuildToolsets>
1152                  </configuration>");
1153 
1154             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1155 
1156             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1157                                                        (
1158                                                            values,
1159                                                            null,
1160                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1161                                                            new BuildPropertyGroup(),
1162                                                            new BuildPropertyGroup(),
1163                                                            ToolsetDefinitionLocations.ConfigurationFile
1164                                                        );
1165         }
1166 
1167         [Test]
1168         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1169         public void SameToolsVersionDefinedMultipleTimesInConfigurationFile()
1170         {
1171             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1172                  <configuration>
1173                    <configSections>
1174                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1175                    </configSections>
1176                    <msbuildToolsets default=""2.0"">
1177                      <toolset toolsVersion=""2.0"">
1178                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1179                        <property name=""p1"" value=""another""/>
1180                      </toolset>
1181                      <toolset toolsVersion=""3.5"">
1182                        <property name=""MSBuildBinPath"" value=""D:\folder""/>
1183                        <property name=""p2"" value=""anotherValue""/>
1184                      </toolset>
1185                      <toolset toolsVersion=""2.0"">
1186                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1187                        <property name=""p1"" value=""another""/>
1188                      </toolset>
1189                    </msbuildToolsets>
1190                  </configuration>");
1191 
1192             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1193 
1194             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1195                                                        (
1196                                                            values,
1197                                                            null,
1198                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1199                                                            new BuildPropertyGroup(),
1200                                                            new BuildPropertyGroup(),
1201                                                            ToolsetDefinitionLocations.ConfigurationFile
1202                                                        );
1203         }
1204 
1205         [Test]
1206         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1207         public void SameToolsVersionDifferentCaseDefinedMultipleTimesInConfigurationFile()
1208         {
1209             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1210                  <configuration>
1211                    <configSections>
1212                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1213                    </configSections>
1214                    <msbuildToolsets default=""2.0"">
1215                      <toolset toolsVersion=""DevDiv"">
1216                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1217                        <property name=""p1"" value=""another""/>
1218                      </toolset>
1219                      <toolset toolsVersion=""3.5"">
1220                        <property name=""MSBuildBinPath"" value=""D:\folder""/>
1221                        <property name=""p2"" value=""anotherValue""/>
1222                      </toolset>
1223                      <toolset toolsVersion=""DEVDIV"">
1224                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1225                        <property name=""p1"" value=""another""/>
1226                      </toolset>
1227                    </msbuildToolsets>
1228                  </configuration>");
1229 
1230             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1231 
1232             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1233                                                        (
1234                                                            values,
1235                                                            null,
1236                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1237                                                            new BuildPropertyGroup(),
1238                                                            new BuildPropertyGroup(),
1239                                                            ToolsetDefinitionLocations.ConfigurationFile
1240                                                        );
1241         }
1242 
1243         [Test]
1244         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1245         public void CannotSetReservedPropertyInConfigFile()
1246         {
1247             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1248                  <configuration>
1249                    <configSections>
1250                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1251                    </configSections>
1252                    <msbuildToolsets default=""2.0"">
1253                      <toolset toolsVersion=""2.0"">
1254                        <property name=""MSBuildBinPath"" value=""D:\some\folder\on\disk""/>
1255                        <property name=""MSBuildProjectFile"" value=""newValue""/>
1256                      </toolset>
1257                    </msbuildToolsets>
1258                  </configuration>");
1259 
1260             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1261 
1262             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1263                                                        (
1264                                                            values,
1265                                                            null,
1266                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1267                                                            new BuildPropertyGroup(),
1268                                                            new BuildPropertyGroup(),
1269                                                            ToolsetDefinitionLocations.ConfigurationFile
1270                                                        );
1271         }
1272 
1273         [Test]
1274         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
1275         public void CannotSetReservedPropertyInRegistry()
1276         {
1277             // Registry Read
1278             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1279             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1280             key1.SetValue("MSBuildProjectFile", @"SomeRegistryValue");
1281 
1282             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1283 
1284             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1285                                                        (
1286                                                            values,
1287                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1288                                                            null,
1289                                                            new BuildPropertyGroup(),
1290                                                            new BuildPropertyGroup(),
1291                                                            ToolsetDefinitionLocations.Registry
1292                                                        );
1293         }
1294 
1295         /// <summary>
1296         /// Properties defined in previously processed toolset definitions should
1297         /// not affect the evaluation of subsequent toolset definitions.
1298         /// </summary>
1299         [Test]
1300         public void NoInterferenceBetweenToolsetDefinitions()
1301         {
1302             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1303                  <configuration>
1304                    <configSections>
1305                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1306                    </configSections>
1307                    <msbuildToolsets default=""2.0"">
1308                      <toolset toolsVersion=""2.0"">
1309                        <property name=""MSBuildBinPath"" value=""D:\20\some\folder\on\disk""/>
1310                        <property name=""p1"" value=""another""/>
1311                        <property name=""p4"" value=""fourth$(p3)Value"" />
1312                      </toolset>
1313                      <toolset toolsVersion=""3.5"">
1314                        <property name=""MSBuildBinPath"" value=""D:\35\some\folder\on\disk""/>
1315                        <property name=""p2"" value=""some$(p1)value""/>
1316                        <property name=""p3"" value=""propertyValue""/>
1317                      </toolset>
1318                    </msbuildToolsets>
1319                  </configuration>");
1320 
1321             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1322 
1323             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1324                                                        (
1325                                                            values,
1326                                                            null,
1327                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1328                                                            new BuildPropertyGroup(),
1329                                                            new BuildPropertyGroup(),
1330                                                            ToolsetDefinitionLocations.ConfigurationFile
1331                                                        );
1332 
1333             Assertion.AssertEquals(2, values.Count);
1334 
1335             Assertion.AssertEquals(@"D:\20\some\folder\on\disk", values["2.0"].ToolsPath);
1336             Assertion.AssertEquals(2, values["2.0"].BuildProperties.Count);
1337             Assertion.AssertEquals(@"another", values["2.0"].BuildProperties["p1"].Value);
1338             Assertion.AssertEquals(@"fourthValue", values["2.0"].BuildProperties["p4"].Value);
1339 
1340             Assertion.AssertEquals(@"D:\35\some\folder\on\disk", values["3.5"].ToolsPath);
1341             Assertion.AssertEquals(2, values["3.5"].BuildProperties.Count);
1342             Assertion.AssertEquals(@"somevalue", values["3.5"].BuildProperties["p2"].Value);
1343             Assertion.AssertEquals(@"propertyValue", values["3.5"].BuildProperties["p3"].Value);
1344         }
1345 
1346         /// <summary>
1347         /// Properties in the configuration file may refer to a registry location by using the syntax for example
1348         /// "$(Registry:HKEY_LOCAL_MACHINE\Software\Vendor\Tools@TaskLocation)", where "HKEY_LOCAL_MACHINE\Software\Vendor\Tools" is the key and
1349         /// "TaskLocation" is the name of the value.  The name of the value and the preceding "@" may be omitted if
1350         /// the default value is desired.
1351         /// </summary>
1352 
1353         [Test]
1354         public void ConfigFileInvalidRegistryExpression1()
1355         {
1356             // No location
1357             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:)""/>");
1358         }
1359 
1360         [Test]
1361         public void ConfigFileInvalidRegistryExpression2()
1362         {
1363             // Bogus key expression
1364             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:__bogus__)""/>");
1365         }
1366 
1367         [Test]
1368         public void ConfigFileInvalidRegistryExpression3()
1369         {
1370             // No registry location just @
1371             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:@)""/>");
1372         }
1373 
1374         [Test]
1375         public void ConfigFileInvalidRegistryExpression4()
1376         {
1377             // Double @
1378             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@@TaskLocation)""/>");
1379         }
1380 
1381         [Test]
1382         public void ConfigFileInvalidRegistryExpression5()
1383         {
1384             // Trailing @
1385             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation@)""/>");
1386         }
1387 
1388         [Test]
1389         public void ConfigFileInvalidRegistryExpression6()
1390         {
1391             // Leading @
1392             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:@HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation)""/>");
1393         }
1394 
1395         [Test]
1396         public void ConfigFileInvalidRegistryExpression7()
1397         {
1398             // Bogus hive
1399             ConfigFileInvalidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:BOGUS_HIVE\Software\Vendor\Tools@TaskLocation)""/>");
1400         }
1401 
1402         [Test]
1403         public void ConfigFileStringEmptyRegistryExpression1()
1404         {
1405             // Regular undefined property beginning with "Registry"
1406             ConfigFileValidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry)""/>",
1407                                           String.Empty);
1408         }
1409 
1410         [Test]
1411         public void ConfigFileStringEmptyRegistryExpression2()
1412         {
1413             // Nonexistent key
1414             ConfigFileValidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:HKEY_CURRENT_USER\Nonexistent_Key\Software\Vendor\Tools@TaskLocation)""/>",
1415                                           String.Empty);
1416         }
1417 
1418         [Test]
1419         public void ConfigFileNonPropertyRegistryExpression1()
1420         {
1421             // Property not terminated with paren, does not look like property
1422             ConfigFileValidRegistryExpressionHelper(@"<property name=""p"" value=""$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation""/>",
1423                                           @"$(Registry:HKEY_CURRENT_USER\Software\Vendor\Tools@TaskLocation");
1424         }
1425 
1426         [Test]
1427         public void ConfigFileNonPropertyRegistryExpression2()
1428         {
1429             // Missing colon, looks like regular property (admittedly with invalid property name chars, but we don't
1430             // error for that today)
1431             ConfigFileValidRegistryExpressionHelper(@"<property name=""p"" value=""$(RegistryHKEY_CURRENT_USER\Software\Vendor\Tools@@TaskLocation)""/>",
1432                                           String.Empty);
1433         }
1434 
1435         [Test]
1436         public void ConfigFileItemExpressionsDoNotExpandInConfigurationProperties()
1437         {
1438             // Expect that item expressions such as '@(SomeItem)' are not evaluated in any way, e.g., they are treated literally
1439             ConfigFileValidRegistryExpressionHelper(@"<property name=""p"" value=""@(SomeItem)""/>",
1440                                           @"@(SomeItem)");
1441         }
1442 
1443         [Test]
1444         public void RegistryInvalidRegistryExpression1()
1445         {
1446             // Bogus key expression
1447             RegistryInvalidRegistryExpressionHelper("$(Registry:__bogus__)");
1448         }
1449 
1450         [Test]
1451         public void RegistryValidRegistryExpression1()
1452         {
1453             // Regular undefined property beginning with "Registry"
1454             RegistryValidRegistryExpressionHelper("$(Registry)", String.Empty);
1455         }
1456 
1457         [Test]
1458         public void RegistryValidRegistryExpressionRecursive()
1459         {
1460             // Property pointing to itself - should not hang :-)
1461             RegistryValidRegistryExpressionHelper
1462                 (@"$(Registry:HKEY_CURRENT_USER\" + testRegistryPath + @"\ToolsVersions\2.0@p)",
1463                  @"$(Registry:HKEY_CURRENT_USER\" + testRegistryPath + @"\ToolsVersions\2.0@p)");
1464         }
1465 
1466         private void RegistryInvalidRegistryExpressionHelper(string propertyExpression)
1467         {
1468             bool caught = false;
1469             try
1470             {
1471                 // this should throw...
1472                 RegistryValidRegistryExpressionHelper(propertyExpression, String.Empty);
1473             }
1474             catch (InvalidToolsetDefinitionException ex)
1475             {
1476                 Console.WriteLine(ex.Message);
1477                 caught = true;
1478             }
1479 
1480             Assertion.AssertEquals(true, caught);
1481         }
1482 
1483         private void RegistryValidRegistryExpressionHelper(string propertyExpression, string expectedValue)
1484         {
1485             // Registry Read
1486             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
1487             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1488             key1.SetValue("MSBuildBinPath", "xxxx");
1489             key1.SetValue("p", propertyExpression);
1490 
1491             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1492 
1493             ToolsetReader.ReadAllToolsets
1494                                        (
1495                                            values,
1496                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1497                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1498                                            new BuildPropertyGroup(),
1499                                            new BuildPropertyGroup(),
1500                                            ToolsetDefinitionLocations.Registry
1501                                        );
1502 
1503             Assertion.AssertEquals(1, values.Count);
1504             Assertion.AssertEquals(expectedValue, values["2.0"].BuildProperties["p"].Value);
1505         }
1506 
1507         /// <summary>
1508         /// Tests that an invalid registry property expression causes an exception (resulting in a project load error)
1509         /// </summary>
1510         /// <param name="propertyExpression"></param>
1511         private void ConfigFileInvalidRegistryExpressionHelper(string propertyExpression)
1512         {
1513             bool caught = false;
1514             try
1515             {
1516                 // this should throw...
1517                 ConfigFileValidRegistryExpressionHelper(propertyExpression, String.Empty);
1518             }
1519             catch (InvalidToolsetDefinitionException ex)
1520             {
1521                 Console.WriteLine(ex.Message);
1522                 caught = true;
1523             }
1524 
1525             Assertion.AssertEquals(true, caught);
1526         }
1527 
1528         /// <summary>
1529         /// Tests that a specified registry property expression evaluates to specified value
1530         /// </summary>
1531         /// <param name="propertyExpression"></param>
1532         private void ConfigFileValidRegistryExpressionHelper(string propertyExpression, string expectedValue)
1533         {
1534             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1535                  <configuration>
1536                    <configSections>
1537                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1538                    </configSections>
1539                    <msbuildToolsets default=""2.0"">
1540                      <toolset toolsVersion=""2.0"">
1541                        <property name=""MSBuildBinPath"" value=""xxxx""/>
1542                        " + propertyExpression + @"
1543                      </toolset>
1544                    </msbuildToolsets>
1545                  </configuration>");
1546 
1547             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1548 
1549 
1550             ToolsetReader.ReadAllToolsets
1551                                        (
1552                                            values,
1553                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1554                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1555                                            new BuildPropertyGroup(),
1556                                            new BuildPropertyGroup(),
1557                                            ToolsetDefinitionLocations.ConfigurationFile
1558                                        );
1559 
1560             Assertion.AssertEquals(1, values.Count);
1561             Assertion.AssertEquals(expectedValue, values["2.0"].BuildProperties["p"].Value);
1562         }
1563 
1564         /// <summary>
1565         /// Tests the case where application configuration file overrides a value already specified in the registry
1566         /// </summary>
1567         [Test]
1568         public void GetToolsetData_ConflictingPropertyValuesSameCase()
1569         {
1570             // Registry Read
1571             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1572             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1573 
1574             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1575                  <configuration>
1576                    <configSections>
1577                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1578                    </configSections>
1579                    <msbuildToolsets default=""2.0"">
1580                      <toolset toolsVersion=""2.0"">
1581                        <property name=""MSBuildBinPath"" value=""D:\somedifferentpath""/>
1582                      </toolset>
1583                    </msbuildToolsets>
1584                  </configuration>");
1585 
1586             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1587 
1588             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1589                                                        (
1590                                                            values,
1591                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1592                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1593                                                            new BuildPropertyGroup(),
1594                                                            new BuildPropertyGroup(),
1595                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1596                                                        );
1597 
1598             Assertion.AssertEquals(1, values.Count);
1599             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
1600             Assertion.AssertEquals(@"D:\somedifferentpath", values["2.0"].ToolsPath);
1601         }
1602 
1603         /// <summary>
1604         /// Tests when properties are defined in the registry as
1605         /// well as in the config file for the same tools version.
1606         /// We should not merge them; we should take the config file ones only
1607         /// </summary>
1608         [Test]
1609         public void GetToolsetData_NoMerging()
1610         {
1611             // Registry Read
1612             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1613             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1614             key1.SetValue("SomeRegistryProperty", @"SomeRegistryValue");
1615 
1616             // Set the config file contents as needed
1617             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1618                  <configuration>
1619                    <configSections>
1620                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1621                    </configSections>
1622                    <msbuildToolsets default=""2.0"">
1623                      <toolset toolsVersion=""2.0"">
1624                        <property name=""MSBuildBinPath"" value=""D:\someotherpath""/>
1625                        <property name=""SomeConfigProperty"" value=""SomeConfigValue""/>
1626                      </toolset>
1627                    </msbuildToolsets>
1628                  </configuration>");
1629 
1630             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1631 
1632             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1633                                                        (
1634                                                            values,
1635                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1636                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1637                                                            new BuildPropertyGroup(),
1638                                                            new BuildPropertyGroup(),
1639                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1640                                                        );
1641 
1642             Assertion.AssertEquals(1, values.Count);
1643             Assertion.AssertEquals(1, values["2.0"].BuildProperties.Count);
1644             Assertion.AssertEquals(@"D:\someotherpath", values["2.0"].ToolsPath);
1645             Assertion.AssertEquals(null, values["2.0"].BuildProperties["SomeRegistryProperty"]); // Was zapped
1646             Assertion.AssertEquals(@"SomeConfigValue", values["2.0"].BuildProperties["SomeConfigProperty"].Value);
1647         }
1648 
1649         /// <summary>
1650         /// The absence of the ToolsVersion attribute on the main Project element in a project file means
1651         /// that the engine's default tools version should be used.
1652         /// </summary>
1653         [Test]
1654         public void ToolsVersionAttributeNotSpecifiedOnProjectElementAndDefaultVersionSpecifiedInRegistry()
1655         {
1656             Engine e = new Engine();
1657             e.AddToolset(new Toolset("2.0", "20toolsPath"));
1658             e.AddToolset(new Toolset("4.0", "40toolsPath"));
1659 
1660             string projectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("x.proj", @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" />");
1661 
1662             Project project = e.CreateNewProject();
1663             project.Load(projectPath);
1664 
1665             Assertion.AssertEquals("2.0", project.ToolsVersion);
1666             Assertion.AssertEquals("2.0", project.DefaultToolsVersion);
1667         }
1668 
1669         /// <summary>
1670         /// Tests the case when no values are specified in the registry
1671         /// </summary>
1672         [Test]
GetToolsetData_RegistryNotPresent()1673         public void GetToolsetData_RegistryNotPresent()
1674         {
1675             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1676                  <configuration>
1677                    <configSections>
1678                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1679                    </configSections>
1680                    <msbuildToolsets default=""2.0"">
1681                      <toolset toolsVersion=""2.0"">
1682                        <property name=""MSBUILDBINPATH"" value=""D:\somedifferentpath""/>
1683                      </toolset>
1684                    </msbuildToolsets>
1685                  </configuration>");
1686 
1687             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1688 
1689             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1690                                                        (
1691                                                            values,
1692                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1693                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1694                                                            new BuildPropertyGroup(),
1695                                                            new BuildPropertyGroup(),
1696                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1697                                                        );
1698 
1699             Assertion.AssertEquals(1, values.Count);
1700             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
1701             Assertion.AssertEquals(@"D:\somedifferentpath", values["2.0"].ToolsPath);
1702         }
1703 
1704         /// <summary>
1705         /// Test the case where nothing is specified in the config file
1706         /// Note that config file not present is same as config file
1707         /// with no MSBuildToolsets Section
1708         /// </summary>
1709         [Test]
GetToolsetData_ConfigFileNotPresent()1710         public void GetToolsetData_ConfigFileNotPresent()
1711         {
1712             // Registry Read
1713             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1714             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1715 
1716             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1717 
1718             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1719                                                        (
1720                                                            values,
1721                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1722                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1723                                                            new BuildPropertyGroup(),
1724                                                            new BuildPropertyGroup(),
1725                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1726                                                        );
1727 
1728             Assertion.AssertEquals(1, values.Count);
1729             Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
1730             Assertion.AssertEquals(@"D:\somepath", values["2.0"].ToolsPath);
1731         }
1732 
1733         /// <summary>
1734         /// Tests the case where nothing is specified in registry and config file
1735         /// </summary>
1736         [Test]
GetToolsetData_RegistryAndConfigNotPresent()1737         public void GetToolsetData_RegistryAndConfigNotPresent()
1738         {
1739             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1740 
1741             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1742                                                        (
1743                                                            values,
1744                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1745                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1746                                                            new BuildPropertyGroup(),
1747                                                            new BuildPropertyGroup(),
1748                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1749                                                        );
1750 
1751             Assertion.AssertEquals(1 /* fallback */, values.Count);
1752         }
1753 
1754         /// <summary>
1755         /// Tests the case when reading config file throws an exception
1756         /// </summary>
1757         [Test]
1758         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
GetToolsetData_ReadConfigThrowsException()1759         public void GetToolsetData_ReadConfigThrowsException()
1760         {
1761             // Registry Read
1762             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1763             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1764 
1765             // Set the config helper to throw exception
1766             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationException());
1767 
1768             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1769 
1770             ToolsetReader.ReadAllToolsets
1771                        (
1772                            values,
1773                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1774                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1775                            new BuildPropertyGroup(),
1776                            new BuildPropertyGroup(),
1777                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1778                        );
1779         }
1780 
1781         /// <summary>
1782         /// Tests the case where reading from registry throws exception
1783         /// </summary>
1784         [Test]
1785         [ExpectedException(typeof(InvalidToolsetDefinitionException))]
GetToolsetData_ReadRegistryOpenSubKeyThrowsException()1786         public void GetToolsetData_ReadRegistryOpenSubKeyThrowsException()
1787         {
1788             RegistryKeyWrapper mockRegistryKey =
1789                 new MockRegistryKey(testRegistryPath, MockRegistryKey.WhereToThrow.OpenSubKey);
1790 
1791             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1792                  <configuration>
1793                    <configSections>
1794                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1795                    </configSections>
1796                    <msbuildToolsets default=""2.0"">
1797                      <toolset toolsVersion=""2.0"">
1798                        <property name=""MSBuildBinPath"" value=""D:\somedifferentpath""/>
1799                      </toolset>
1800                    </msbuildToolsets>
1801                  </configuration>");
1802 
1803             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1804 
1805             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1806                                                        (
1807                                                            values,
1808                                                            new ToolsetRegistryReader(mockRegistryKey),
1809                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1810                                                            new BuildPropertyGroup(),
1811                                                            new BuildPropertyGroup(),
1812                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1813                                                        );
1814         }
1815 
1816         #endregion
1817 
1818         #region "SetDefaultToolsetVersion tests"
1819 
1820         /// <summary>
1821         /// Tests that the default ToolsVersion is correctly resolved when specified
1822         /// in registry and config file
1823         /// </summary>
1824         [Test]
SetDefaultToolsetVersion_SpecifiedInRegistryAndConfigFile()1825         public void SetDefaultToolsetVersion_SpecifiedInRegistryAndConfigFile()
1826         {
1827             // Set up registry with two tools versions and one property each
1828             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "2.0");
1829             RegistryKey key1 = toolsVersionsRegistryKey.CreateSubKey("2.0");
1830             key1.SetValue("MSBuildBinPath", @"D:\somepath");
1831             RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5");
1832             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
1833 
1834             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1835                  <configuration>
1836                    <configSections>
1837                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1838                    </configSections>
1839                    <msbuildToolsets default=""5.0"">
1840                      <toolset toolsVersion=""4.0"">
1841                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
1842                      </toolset>
1843                      <toolset toolsVersion=""5.0"">
1844                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
1845                      </toolset>
1846                    </msbuildToolsets>
1847                  </configuration>");
1848 
1849             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1850 
1851             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1852                                                        (
1853                                                            values,
1854                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1855                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1856                                                            new BuildPropertyGroup(),
1857                                                            new BuildPropertyGroup(),
1858                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1859                                                        );
1860 
1861             Assertion.AssertEquals("5.0", defaultToolsVersion);
1862         }
1863 
1864         /// <summary>
1865         /// Tests that the default ToolsVersion is correctly resolved when specified in registry only
1866         /// </summary>
1867         [Test]
1868         public void SetDefaultToolsetVersion_SpecifiedOnlyInRegistry()
1869         {
1870             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1871                  <configuration>
1872                    <configSections>
1873                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1874                    </configSections>
1875                    <msbuildToolsets>
1876                      <toolset toolsVersion=""3.0"">
1877                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
1878                      </toolset>
1879                      <toolset toolsVersion=""5.0"">
1880                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
1881                      </toolset>
1882                    </msbuildToolsets>
1883                  </configuration>");
1884 
1885             // Set up registry with two tools versions and one property each
1886             currentVersionRegistryKey.SetValue("DefaultToolsVersion", "3.5");
1887             RegistryKey key2 = toolsVersionsRegistryKey.CreateSubKey("3.5");
1888             key2.SetValue("MSBuildBinPath", @"D:\somepath2");
1889 
1890             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1891 
1892             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1893                                                        (
1894                                                            values,
1895                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1896                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1897                                                            new BuildPropertyGroup(),
1898                                                            new BuildPropertyGroup(),
1899                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1900                                                        );
1901 
1902             Assertion.AssertEquals("3.5", defaultToolsVersion);
1903         }
1904 
1905         /// <summary>
1906         /// Tests that the default ToolsVersion is correctly resolved
1907         /// when specified in config file only
1908         /// </summary>
1909         [Test]
1910         public void SetDefaultToolsetVersion_SpecifiedOnlyInConfigFile()
1911         {
1912             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1913                  <configuration>
1914                    <configSections>
1915                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1916                    </configSections>
1917                    <msbuildToolsets default=""5.0"">
1918                      <toolset toolsVersion=""3.5"">
1919                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
1920                      </toolset>
1921                      <toolset toolsVersion=""5.0"">
1922                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
1923                      </toolset>
1924                    </msbuildToolsets>
1925                  </configuration>");
1926 
1927             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1928 
1929             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1930                                                        (
1931                                                            values,
1932                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1933                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1934                                                            new BuildPropertyGroup(),
1935                                                            new BuildPropertyGroup(),
1936                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1937                                                        );
1938 
1939 
1940             Assertion.AssertEquals("5.0", defaultToolsVersion);
1941         }
1942 
1943         /// <summary>
1944         /// Tests that the default ToolsVersion is correctly resolved when specified nowhere
1945         /// </summary>
1946         [Test]
1947         public void SetDefaultToolsetVersion_SpecifiedNowhere()
1948         {
1949             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1950                  <configuration>
1951                    <configSections>
1952                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1953                    </configSections>
1954                    <msbuildToolsets>
1955                      <toolset toolsVersion=""3.5"">
1956                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
1957                      </toolset>
1958                      <toolset toolsVersion=""5.0"">
1959                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
1960                      </toolset>
1961                    </msbuildToolsets>
1962                  </configuration>");
1963 
1964             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
1965 
1966             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
1967                                                        (
1968                                                            values,
1969                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
1970                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
1971                                                            new BuildPropertyGroup(),
1972                                                            new BuildPropertyGroup(),
1973                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
1974                                                        );
1975 
1976             string expectedDefault = "2.0";
1977             if (FrameworkLocationHelper.PathToDotNetFrameworkV20 == null)
1978             {
1979                 expectedDefault = "4.0";
1980             }
1981 
1982             Assertion.AssertEquals(expectedDefault, defaultToolsVersion); // built-in default
1983         }
1984 
1985         /// <summary>
1986         /// Tests that properties are properly expanded when reading them from the config file
1987         /// </summary>
1988         [Test]
1989         public void PropertiesInToolsetsFromConfigFileAreExpanded()
1990         {
1991             // $(COMPUTERNAME) is just a convenient env var. $(NUMBER_OF_PROCESSORS) isn't defined on Longhorn
1992             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
1993                  <configuration>
1994                    <configSections>
1995                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
1996                    </configSections>
1997                    <msbuildToolsets>
1998                      <toolset toolsVersion=""3.5"">
1999                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
2000                        <property name=""p1"" value=""v1$(p2)""/>
2001                        <property name=""p2"" value=""__$(p1)__""/>
2002                        <property name=""p3"" value=""$(COMPUTERNAME)""/>
2003                      </toolset>
2004                    </msbuildToolsets>
2005                  </configuration>");
2006 
2007             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
2008 
2009             Engine e = new Engine();
2010             BuildPropertyGroup initialProperties = new BuildPropertyGroup();
2011             initialProperties.ImportProperties(e.EnvironmentProperties);
2012             initialProperties.ImportProperties(e.GlobalProperties);
2013 
2014             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
2015                                                        (
2016                                                            values,
2017                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
2018                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
2019                                                            new BuildPropertyGroup(),
2020                                                            initialProperties,
2021                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
2022                                                        );
2023 
2024             Assertion.AssertEquals("v1", values["3.5"].BuildProperties["p1"].Value);
2025             // Properties can refer to other properties also defined in the config file
2026             Assertion.AssertEquals("__v1__", values["3.5"].BuildProperties["p2"].Value);
2027             Assertion.AssertEquals(Environment.MachineName, values["3.5"].BuildProperties["p3"].Value);
2028         }
2029 
2030         /// <summary>
2031         /// Tests that properties in MSBuildToolsPath are properly expanded when reading them from the config file
2032         /// </summary>
2033         [Test]
2034         public void PropertiesInToolsetsFromConfigFileAreExpandedInToolsPath()
2035         {
2036             // $(COMPUTERNAME) is just a convenient env var. $(NUMBER_OF_PROCESSORS) isn't defined on Longhorn
2037             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
2038                  <configuration>
2039                    <configSections>
2040                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
2041                    </configSections>
2042                    <msbuildToolsets>
2043                      <toolset toolsVersion=""3.5"">
2044                        <property name=""p1"" value=""Microsoft.NET""/>
2045                        <property name=""p2"" value=""windows""/>
2046                        <property name=""MSBuildBinPath"" value=""D:\windows\$(p1)\Framework\v2.0.x86ret\$(COMPUTERNAME)""/>
2047                        <property name=""MSBuildToolsPath"" value=""D:\$(p2)\$(p1)\Framework\v2.0.x86ret\$(COMPUTERNAME)""/>
2048                        <property name=""p3"" value=""v3$(MSBuildToolsPath)""/>
2049                      </toolset>
2050                    </msbuildToolsets>
2051                  </configuration>");
2052 
2053             ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
2054 
2055             Engine e = new Engine();
2056             BuildPropertyGroup initialProperties = new BuildPropertyGroup();
2057             initialProperties.ImportProperties(e.EnvironmentProperties);
2058             initialProperties.ImportProperties(e.GlobalProperties);
2059 
2060             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
2061                                                        (
2062                                                            values,
2063                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
2064                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
2065                                                            new BuildPropertyGroup(),
2066                                                            initialProperties,
2067                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
2068                                                        );
2069 
2070             Assertion.AssertEquals("Microsoft.NET", values["3.5"].BuildProperties["p1"].Value);
2071             Assertion.AssertEquals("windows", values["3.5"].BuildProperties["p2"].Value);
2072             string expectedToolsPath = @"D:\windows\Microsoft.NET\Framework\v2.0.x86ret\" + Environment.MachineName;
2073             Assertion.AssertEquals(expectedToolsPath, values["3.5"].ToolsPath);
2074             Assertion.AssertEquals("v3" + expectedToolsPath, values["3.5"].BuildProperties["p3"].Value);
2075         }
2076 
2077         /// <summary>
2078         /// Global properties are available, but they cannot be overwritten by other toolset properties, just as they cannot
2079         /// be overwritten by project file properties.
2080         /// </summary>
2081         [Test]
2082         public void GlobalPropertiesInToolsetsAreExpandedButAreNotOverwritten()
2083         {
2084             ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
2085                  <configuration>
2086                    <configSections>
2087                      <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
2088                    </configSections>
2089                    <msbuildToolsets>
2090                      <toolset toolsVersion=""3.5"">
2091                        <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
2092                        <property name=""p1"" value=""$(gp1)""/>
2093                        <property name=""gp1"" value=""v2""/>
2094                        <property name=""p2"" value=""$(gp1)""/>
2095                      </toolset>
2096                    </msbuildToolsets>
2097                  </configuration>");
2098 
2099             Engine e = new Engine(ToolsetDefinitionLocations.None);
2100             ToolsetCollection values = new ToolsetCollection(e);
2101 
2102             BuildPropertyGroup globalProperties = e.GlobalProperties;
2103             globalProperties.SetProperty("gp1", "gv1");
2104 
2105             BuildPropertyGroup initialProperties = new BuildPropertyGroup();
2106             initialProperties.ImportProperties(e.EnvironmentProperties);
2107             initialProperties.ImportProperties(globalProperties);
2108 
2109             string defaultToolsVersion = ToolsetReader.ReadAllToolsets
2110                                                        (
2111                                                            values,
2112                                                            new ToolsetRegistryReader(new MockRegistryKey(testRegistryPath)),
2113                                                            new ToolsetConfigurationReader(new ReadApplicationConfiguration(ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest)),
2114                                                            globalProperties,
2115                                                            initialProperties,
2116                                                            ToolsetDefinitionLocations.ConfigurationFile | ToolsetDefinitionLocations.Registry
2117                                                        );
2118 
2119             Assertion.AssertEquals("gv1", values["3.5"].BuildProperties["p1"].Value);
2120             Assertion.AssertEquals("gv1", values["3.5"].BuildProperties["p2"].Value);
2121         }
2122 
2123 
2124         #endregion
2125     }
2126 
2127     internal class MockRegistryKey : RegistryKeyWrapper
2128     {
2129         public enum WhereToThrow
2130         {
2131             None,
2132             Name,
2133             GetValue,
2134             GetValueNames,
2135             GetSubKeyNames,
2136             OpenSubKey
2137         }
2138 
2139         private WhereToThrow whereToThrow = WhereToThrow.None;
2140         private string subKeyThatDoesNotExist = null;
2141 
2142         /// <summary>
2143         /// Construct the mock key with a specified key
2144         /// </summary>
2145         /// <param name="path"></param>
2146         protected MockRegistryKey(RegistryKey wrappedKey, RegistryKey registryHive)
2147             : base(wrappedKey, registryHive)
2148         { }
2149 
2150         /// <summary>
2151         /// Construct the mock key with a wrapper
2152         /// </summary>
2153         /// <param name="path"></param>
2154         public MockRegistryKey(string path)
2155             : base(path, Registry.CurrentUser)
2156         { }
2157 
2158         /// <summary>
2159         /// Construct the mock key with a wrapper and a designated method
2160         /// to throw from
2161         /// </summary>
2162         /// <param name="path"></param>
2163         /// <param name="whereToThrow"></param>
2164         public MockRegistryKey(string path, WhereToThrow whereToThrow)
2165             : base(path, Registry.CurrentUser)
2166         {
2167             this.whereToThrow = whereToThrow;
2168         }
2169 
2170         /// <summary>
2171         /// Construct the mock key with a wrapper and a designated subkey
2172         /// to refuse to open
2173         /// </summary>
2174         /// <param name="path"></param>
2175         /// <param name="whereToThrow"></param>
2176         public MockRegistryKey(string path, string subKeyThatDoesNotExist)
2177             : base(path, Registry.CurrentUser)
2178         {
2179             this.subKeyThatDoesNotExist = subKeyThatDoesNotExist;
2180         }
2181 
2182         /// <summary>
2183         /// Name of the registry key
2184         /// </summary>
2185         public override string Name
2186         {
2187             get
2188             {
2189                 if (whereToThrow == WhereToThrow.Name)
2190                 {
2191                     throw new RegistryException("registryException", "registry");
2192                 }
2193                 return base.Name;
2194             }
2195         }
2196 
2197         /// <summary>
2198         /// Gets the value with name "name" stored under this registry key
2199         /// </summary>
2200         public override object GetValue(string name)
2201         {
2202             if (whereToThrow == WhereToThrow.GetValue)
2203             {
2204                 throw new RegistryException("registryException", "registry");
2205             }
2206             return base.GetValue(name);
2207         }
2208 
2209         /// <summary>
2210         /// Gets the names of all values underneath this registry key
2211         /// </summary>
2212         public override string[] GetValueNames()
2213         {
2214             if (whereToThrow == WhereToThrow.GetValueNames)
2215             {
2216                 throw new RegistryException("registryException", "registry");
2217             }
2218             return base.GetValueNames();
2219         }
2220 
2221         /// <summary>
2222         /// Gets the names of all sub keys immediately below this registry key
2223         /// </summary>
2224         /// <returns></returns>
2225         public override string[] GetSubKeyNames()
2226         {
2227             if (whereToThrow == WhereToThrow.GetSubKeyNames)
2228             {
2229                 throw new RegistryException("registryException", "registry");
2230             }
2231             return base.GetSubKeyNames();
2232         }
2233 
2234         /// <summary>
2235         /// Returns the sub key with name "name" as a read only key
2236         /// </summary>
2237         public override RegistryKeyWrapper OpenSubKey(string name)
2238         {
2239             if (whereToThrow == WhereToThrow.OpenSubKey)
2240             {
2241                 throw new RegistryException("registryException", "registry");
2242             }
2243 
2244             if (subKeyThatDoesNotExist == name)
2245             {
2246                 // Return wrapper around null key
2247                 return new MockRegistryKey((RegistryKey)null, Registry.LocalMachine);
2248             }
2249 
2250             return base.OpenSubKey(name);
2251         }
2252 
2253     }
2254 }
2255 
2256