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.Text;
8 using System.Reflection;
9 
10 using NUnit.Framework;
11 
12 using Microsoft.Build.UnitTests;
13 
14 using Microsoft.Build.Utilities;
15 using Microsoft.Build.Framework;
16 using Microsoft.Build.BuildEngine;
17 using Microsoft.Build.UnitTests.Project_Tests;
18 
19 namespace Microsoft.Build.UnitTests.EscapingInProjects_Tests
20 {
21     /// <summary>
22     /// Test task that just logs the parameters it receives.
23     /// </summary>
24     /// <owner>RGoel</owner>
25     public class MyTestTask : Task
26     {
27         private ITaskItem taskItemParam;
28         public ITaskItem TaskItemParam
29         {
30             get
31             {
32                 return taskItemParam;
33             }
34 
35             set
36             {
37                 taskItemParam = value;
38             }
39         }
40 
Execute()41         override public bool Execute()
42         {
43             if (TaskItemParam != null)
44             {
45                 Log.LogMessageFromText("Received TaskItemParam: " + TaskItemParam.ItemSpec, MessageImportance.High);
46             }
47 
48             return true;
49         }
50     }
51 
52     [TestFixture]
53     public class SimpleScenarios
54     {
55         /// <summary>
56         /// Make sure I can define a property with escaped characters and pass it into
57         /// a string parameter of a task, in this case the Message task.
58         /// </summary>
59         /// <owner>RGoel</owner>
60         [Test]
SemicolonInPropertyPassedIntoStringParam()61         public void SemicolonInPropertyPassedIntoStringParam()
62         {
63             MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(@"
64                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
65                     <PropertyGroup>
66                         <MyPropertyWithSemicolons>abc %3b def %3b ghi</MyPropertyWithSemicolons>
67                     </PropertyGroup>
68                     <Target Name=`Build`>
69                         <Message Text=`Property value is '$(MyPropertyWithSemicolons)'` />
70                     </Target>
71                 </Project>
72                 ");
73 
74             logger.AssertLogContains("Property value is 'abc ; def ; ghi'");
75         }
76 
77         /// <summary>
78         /// Make sure I can define a property with escaped characters and pass it into
79         /// an ITaskItem[] task parameter.
80         /// </summary>
81         [Test]
SemicolonInPropertyPassedIntoITaskItemParam()82         public void SemicolonInPropertyPassedIntoITaskItemParam()
83         {
84             MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(String.Format(@"
85 
86                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
87 
88                     <UsingTask TaskName=`Microsoft.Build.UnitTests.EscapingInProjects_Tests.MyTestTask` AssemblyFile=`{0}` />
89 
90                     <PropertyGroup>
91                         <MyPropertyWithSemicolons>abc %3b def %3b ghi</MyPropertyWithSemicolons>
92                     </PropertyGroup>
93 
94                     <Target Name=`Build`>
95                         <MyTestTask TaskItemParam=`123 $(MyPropertyWithSemicolons) 789` />
96                     </Target>
97 
98                 </Project>
99 
100                 ", new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath));
101 
102             logger.AssertLogContains("Received TaskItemParam: 123 abc ; def ; ghi 789");
103         }
104 
105         /// <summary>
106         /// If I try to add a new item to a project, and my new item's Include has an unescaped semicolon
107         /// in it, then we shouldn't try to match it up against any existing wildcards.  This is a really
108         /// bizarre scenario ... the caller probably meant to escape the semicolon.
109         /// </summary>
110         /// <owner>RGoel</owner>
111         [Test]
AddNewItemWithSemicolon()112         public void AddNewItemWithSemicolon()
113         {
114             // ************************************
115             //               BEFORE
116             // ************************************
117             string projectOriginalContents = @"
118                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
119                     <ItemGroup>
120                         <MyWildCard Include=`*.weirdo`/>
121                     </ItemGroup>
122                 </Project>
123                 ";
124 
125 
126             // ************************************
127             //               AFTER
128             // ************************************
129             string projectNewExpectedContents = @"
130                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
131                     <ItemGroup>
132                         <MyWildCard Include=`*.weirdo`/>
133                         <MyWildCard Include=`foo;bar.weirdo`/>
134                     </ItemGroup>
135                 </Project>
136                 ";
137 
138             BuildItem newItem = AddItem.AddNewItemHelper(projectOriginalContents,
139                 projectNewExpectedContents, "MyWildCard", "foo;bar.weirdo");
140 
141             Assertion.AssertEquals("Newly added item should have correct ItemName", "MyWildCard", newItem.Name);
142             Assertion.AssertEquals("Newly added item should have correct Include", "foo;bar.weirdo", newItem.Include);
143         }
144 
145         /// <summary>
146         /// If I try to add a new item to a project, and my new item's Include has a property that
147         /// contains an unescaped semicolon in it, then we shouldn't try to match it up against any existing
148         /// wildcards.
149         /// </summary>
150         /// <owner>RGoel</owner>
151         [Test]
AddNewItemWithPropertyContainingSemicolon()152         public void AddNewItemWithPropertyContainingSemicolon()
153         {
154             // ************************************
155             //               BEFORE
156             // ************************************
157             string projectOriginalContents = @"
158                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
159                     <PropertyGroup>
160                         <FilenameWithSemicolon>foo;bar</FilenameWithSemicolon>
161                     </PropertyGroup>
162                     <ItemGroup>
163                         <MyWildCard Include=`*.weirdo`/>
164                     </ItemGroup>
165                 </Project>
166                 ";
167 
168 
169             // ************************************
170             //               AFTER
171             // ************************************
172             string projectNewExpectedContents = @"
173                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
174                     <PropertyGroup>
175                         <FilenameWithSemicolon>foo;bar</FilenameWithSemicolon>
176                     </PropertyGroup>
177                     <ItemGroup>
178                         <MyWildCard Include=`$(FilenameWithSemicolon).weirdo`/>
179                         <MyWildCard Include=`*.weirdo`/>
180                     </ItemGroup>
181                 </Project>
182                 ";
183 
184             BuildItem newItem = AddItem.AddNewItemHelper(projectOriginalContents,
185                 projectNewExpectedContents, "MyWildCard", "$(FilenameWithSemicolon).weirdo");
186 
187             Assertion.AssertEquals("Newly added item should have correct ItemName", "MyWildCard", newItem.Name);
188             Assertion.AssertEquals("Newly added item should have correct Include", "$(FilenameWithSemicolon).weirdo", newItem.Include);
189         }
190 
191         /// <summary>
192         /// If I try to modify an item in a project, and my new item's Include has an unescaped semicolon
193         /// in it, then we shouldn't try to match it up against any existing wildcards.  This is a really
194         /// bizarre scenario ... the caller probably meant to escape the semicolon.
195         /// </summary>
196         /// <owner>RGoel</owner>
197         [Test]
ModifyItemIncludeSemicolon()198         public void ModifyItemIncludeSemicolon()
199         {
200             // Populate the project directory with three physical files on disk -- a.weirdo, b.weirdo, c.weirdo.
201             ModifyItem.CreateThreeWeirdoFilesHelper();
202 
203             // ************************************
204             //               BEFORE
205             // ************************************
206             string projectOriginalContents = @"
207                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
208 
209                     <ItemGroup>
210                         <MyWildcard Include=`*.weirdo` />
211                     </ItemGroup>
212 
213                 </Project>
214                 ";
215 
216 
217             // ************************************
218             //               AFTER
219             // ************************************
220             string projectNewExpectedContents = @"
221                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
222 
223                     <ItemGroup>
224                         <MyWildcard Include=`a.weirdo` />
225                         <MyWildcard Include=`foo;bar.weirdo` />
226                         <MyWildcard Include=`c.weirdo` />
227                     </ItemGroup>
228 
229                 </Project>
230                 ";
231 
232             // Change b.weirdo to foo;bar.weirdo.
233             ModifyItem.ModifyItemIncludeHelper(projectOriginalContents, projectNewExpectedContents,
234                 "b.weirdo", "foo;bar.weirdo");
235 
236             ModifyItem.CleanupWeirdoFilesHelper();
237         }
238 
239         /// <summary>
240         /// If I try to modify an item in a project, and my new item's Include has an escaped semicolon
241         /// in it, and it matches the existing wildcard, then we shouldn't need to modify the project file.
242         /// </summary>
243         /// <owner>RGoel</owner>
244         [Test]
ModifyItemIncludeEscapedSemicolon()245         public void ModifyItemIncludeEscapedSemicolon()
246         {
247             // Populate the project directory with three physical files on disk -- a.weirdo, b.weirdo, c.weirdo.
248             ModifyItem.CreateThreeWeirdoFilesHelper();
249 
250             // ************************************
251             //               BEFORE
252             // ************************************
253             string projectOriginalContents = @"
254                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
255 
256                     <ItemGroup>
257                         <MyWildcard Include=`*.weirdo` />
258                     </ItemGroup>
259 
260                 </Project>
261                 ";
262 
263 
264             // ************************************
265             //               AFTER
266             // ************************************
267             string projectNewExpectedContents = @"
268                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
269 
270                     <ItemGroup>
271                         <MyWildcard Include=`*.weirdo` />
272                     </ItemGroup>
273 
274                 </Project>
275                 ";
276 
277             // Change b.weirdo to foo;bar.weirdo.
278             ModifyItem.ModifyItemIncludeHelper(projectOriginalContents, projectNewExpectedContents,
279                 "b.weirdo", "foo%253Bbar.weirdo");
280 
281             ModifyItem.CleanupWeirdoFilesHelper();
282         }
283 
284         /// <summary>
285         /// If I try to modify an item in a project, and my new item's Include has a property that
286         /// contains an unescaped semicolon in it, then we shouldn't try to match it up against any existing
287         /// wildcards.
288         /// </summary>
289         /// <owner>RGoel</owner>
290         [Test]
ModifyItemAddPropertyContainingSemicolon()291         public void ModifyItemAddPropertyContainingSemicolon()
292         {
293             // Populate the project directory with three physical files on disk -- a.weirdo, b.weirdo, c.weirdo.
294             ModifyItem.CreateThreeWeirdoFilesHelper();
295 
296             // ************************************
297             //               BEFORE
298             // ************************************
299             string projectOriginalContents = @"
300                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
301 
302                     <PropertyGroup>
303                         <FilenameWithSemicolon>foo;bar</FilenameWithSemicolon>
304                     </PropertyGroup>
305 
306                     <ItemGroup>
307                         <MyWildcard Include=`*.weirdo` />
308                     </ItemGroup>
309 
310                 </Project>
311                 ";
312 
313 
314             // ************************************
315             //               AFTER
316             // ************************************
317             string projectNewExpectedContents = @"
318                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
319 
320                     <PropertyGroup>
321                         <FilenameWithSemicolon>foo;bar</FilenameWithSemicolon>
322                     </PropertyGroup>
323 
324                     <ItemGroup>
325                         <MyWildcard Include=`a.weirdo` />
326                         <MyWildcard Include=`$(FileNameWithSemicolon).weirdo` />
327                         <MyWildcard Include=`c.weirdo` />
328                     </ItemGroup>
329 
330                 </Project>
331                 ";
332 
333             // Change b.weirdo to foo;bar.weirdo.
334             ModifyItem.ModifyItemIncludeHelper(projectOriginalContents, projectNewExpectedContents,
335                 "b.weirdo", "$(FileNameWithSemicolon).weirdo");
336 
337             ModifyItem.CleanupWeirdoFilesHelper();
338         }
339 
340         /// <summary>
341         /// Make sure that character escaping works as expected when adding a new item that matches
342         /// an existing wildcarded item in the project file.
343         /// </summary>
344         /// <owner>RGoel</owner>
345         [Test]
AddNewItemThatMatchesWildcard1()346         public void AddNewItemThatMatchesWildcard1()
347         {
348             // ************************************
349             //               BEFORE
350             // ************************************
351             string projectOriginalContents = @"
352                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
353                     <ItemGroup>
354                         <MyWildCard Include=`*.weirdo`/>
355                     </ItemGroup>
356                 </Project>
357                 ";
358 
359 
360             // ************************************
361             //               AFTER
362             // ************************************
363             string projectNewExpectedContents = @"
364                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
365                     <ItemGroup>
366                         <MyWildCard Include=`*.weirdo`/>
367                     </ItemGroup>
368                 </Project>
369                 ";
370 
371             BuildItem newItem = AddItem.AddNewItemHelper(projectOriginalContents,
372                 projectNewExpectedContents, "MyWildCard", "foo%253bbar.weirdo");
373 
374             Assertion.AssertEquals("Newly added item should have correct ItemName", "MyWildCard", newItem.Name);
375             Assertion.AssertEquals("Newly added item should have correct Include", "*.weirdo", newItem.Include);
376             Assertion.AssertEquals("Newly added item should have correct FinalItemSpec", "foo%253bbar.weirdo", newItem.FinalItemSpecEscaped);
377             Assertion.AssertEquals("Newly added item should have correct FinalItemSpec", "foo%3bbar.weirdo", newItem.FinalItemSpec);
378         }
379 
380         /// <summary>
381         /// Make sure that character escaping works as expected when adding a new item that matches
382         /// an existing wildcarded item in the project file.
383         /// </summary>
384         /// <owner>RGoel</owner>
385         [Test]
AddNewItemThatMatchesWildcard2()386         public void AddNewItemThatMatchesWildcard2()
387         {
388             // ************************************
389             //               BEFORE
390             // ************************************
391             string projectOriginalContents = @"
392                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
393                     <ItemGroup>
394                         <MyWildCard Include=`*.AAA%253bBBB`/>
395                     </ItemGroup>
396                 </Project>
397                 ";
398 
399 
400             // ************************************
401             //               AFTER
402             // ************************************
403             string projectNewExpectedContents = @"
404                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
405                     <ItemGroup>
406                         <MyWildCard Include=`*.AAA%253bBBB`/>
407                     </ItemGroup>
408                 </Project>
409                 ";
410 
411             BuildItem newItem = AddItem.AddNewItemHelper(projectOriginalContents,
412                 projectNewExpectedContents, "MyWildCard", "foobar.AAA%253bBBB");
413 
414             Assertion.AssertEquals("Newly added item should have correct ItemName", "MyWildCard", newItem.Name);
415             Assertion.AssertEquals("Newly added item should have correct Include", "*.AAA%253bBBB", newItem.Include);
416             Assertion.AssertEquals("Newly added item should have correct FinalItemSpec", "foobar.AAA%253bBBB", newItem.FinalItemSpecEscaped);
417             Assertion.AssertEquals("Newly added item should have correct FinalItemSpec", "foobar.AAA%3bBBB", newItem.FinalItemSpec);
418         }
419 
420         /// <summary>
421         /// Make sure that all inferred task outputs (those that are determined without actually
422         /// executing the task) are left escaped when they become real items in the engine, and
423         /// they only get unescaped when fed into a subsequent task.
424         /// </summary>
425         /// <owner>RGoel</owner>
426         [Test]
InferEscapedOutputsFromTask()427         public void InferEscapedOutputsFromTask()
428         {
429             string inputFile = ObjectModelHelpers.CreateTempFileOnDisk("");
430             string outputFile = ObjectModelHelpers.CreateTempFileOnDisk("");
431 
432             try
433             {
434                 MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(String.Format(@"
435 
436                 <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
437 
438                     <Target Name=`GenerateResources` Inputs=`{0}` Outputs=`{1}`>
439                         <NonExistentTask OutputResources=`aaa%253bbbb.resx; ccc%253bddd.resx`>
440                             <Output ItemName=`Resource` TaskParameter=`OutputResources`/>
441                         </NonExistentTask>
442                     </Target>
443 
444                     <Target Name=`Build` DependsOnTargets=`GenerateResources`>
445                         <Message Text=`Resources = @(Resource)`/>
446                     </Target>
447 
448                 </Project>
449 
450                 ", inputFile, outputFile));
451 
452                 logger.AssertLogContains("Resources = aaa%3bbbb.resx;ccc%3bddd.resx");
453             }
454             finally
455             {
456                 File.Delete(inputFile);
457                 File.Delete(outputFile);
458             }
459         }
460 
461         /// <summary>
462         /// Do an item transform, where the transform expression contains an unescaped semicolon as well
463         /// as an escaped percent sign.
464         /// </summary>
465         /// <owner>RGoel</owner>
466         [Test]
ItemTransformContainingSemicolon()467         public void ItemTransformContainingSemicolon()
468         {
469             MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(@"
470 
471                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
472                     <ItemGroup>
473                         <TextFile Include=`X.txt`/>
474                         <TextFile Include=`Y.txt`/>
475                         <TextFile Include=`Z.txt`/>
476                     </ItemGroup>
477                     <Target Name=`Build`>
478                         <Message Text=`Transformed item list: '@(TextFile->'%(FileName);%(FileName)%253b%(FileName)%(Extension)','    ')'` />
479                     </Target>
480                 </Project>
481 
482                 ");
483 
484             logger.AssertLogContains("Transformed item list: 'X;X%3bX.txt    Y;Y%3bY.txt    Z;Z%3bZ.txt'");
485         }
486 
487         /// <summary>
488         /// Test that we can pass in global properties containing escaped characters.
489         /// </summary>
490         /// <owner>RGoel</owner>
491         [Test]
GlobalPropertyWithEscapedCharacters()492         public void GlobalPropertyWithEscapedCharacters()
493         {
494             MockLogger logger = new MockLogger();
495             Project project = ObjectModelHelpers.CreateInMemoryProject(@"
496                 <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
497                     <Target Name=`Build`>
498                         <Message Text=`MyGlobalProperty = '$(MyGlobalProperty)'` />
499                     </Target>
500                 </Project>
501                 ", logger);
502 
503             project.GlobalProperties.SetProperty("MyGlobalProperty", "foo%253bbar");
504 
505             bool success = project.Build(null, null);
506             Assertion.Assert("Build failed.  See Standard Out tab for details", success);
507 
508             logger.AssertLogContains("MyGlobalProperty = 'foo%3bbar'");
509         }
510     }
511 
512     [TestFixture]
513     public class FullProjectsUsingMicrosoftCommonTargets
514     {
515         /// <summary>
516         /// Regression test for bug VSWhidbey 282492:
517         ///     ESCAPING: Escaping in conditionals is broken.
518         /// </summary>
519         /// <owner>RGoel</owner>
520         [Test]
SemicolonInConfiguration()521         public void SemicolonInConfiguration()
522         {
523             ObjectModelHelpers.DeleteTempProjectDirectory();
524 
525             // ---------------------
526             // Foo.csproj
527             // ---------------------
528             ObjectModelHelpers.CreateFileInTempProjectDirectory("foo.csproj", @"
529                 <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
530                     <PropertyGroup>
531                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
532                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
533                         <OutputType>Library</OutputType>
534                         <AssemblyName>ClassLibrary16</AssemblyName>
535                     </PropertyGroup>
536                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'a%3bb%27c|AnyCPU' `>
537                         <OutputPath>bin\a%3bb%27c\</OutputPath>
538                     </PropertyGroup>
539                     <ItemGroup>
540                         <Reference Include=`System` />
541                         <Compile Include=`Class1.cs` />
542                     </ItemGroup>
543                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
544                 </Project>
545             ");
546 
547             // ---------------------
548             // Class1.cs
549             // ---------------------
550             ObjectModelHelpers.CreateFileInTempProjectDirectory("Class1.cs", @"
551                 namespace ClassLibrary16
552                 {
553 	                public class Class1
554 	                {
555 	                }
556                 }
557             ");
558 
559             // Create a logger.
560             MockLogger logger = new MockLogger();
561 
562             Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory("foo.csproj", logger);
563 
564             // Build the default targets using the Configuration "a;b'c".
565             project.GlobalProperties.SetProperty("Configuration", "a;b'c", true /* literal value */);
566             bool success = project.Build(null, null);
567             Assertion.Assert("Build failed.  See Standard Out tab for details", success);
568 
569             ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"obj\a;b'c\ClassLibrary16.dll");
570             ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"bin\a;b'c\ClassLibrary16.dll");
571 
572             logger.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\a;b'c\ClassLibrary16.dll")));
573         }
574 
575         /// <summary>
576         /// Regression test for bug VSWhidbey 157204:
577         ///     ESCAPING: CopyBuildTarget target fails if the output assembly name contains a semicolon or single-quote
578         /// </summary>
579         /// <owner>RGoel</owner>
580         [Test]
SemicolonInAssemblyName()581         public void SemicolonInAssemblyName()
582         {
583             ObjectModelHelpers.DeleteTempProjectDirectory();
584 
585             // ---------------------
586             // Foo.csproj
587             // ---------------------
588             ObjectModelHelpers.CreateFileInTempProjectDirectory("foo.csproj", @"
589                 <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
590                     <PropertyGroup>
591                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
592                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
593                         <OutputType>Library</OutputType>
594                         <AssemblyName>Class%3bLibrary16</AssemblyName>
595                     </PropertyGroup>
596                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
597                         <OutputPath>bin\Debug\</OutputPath>
598                     </PropertyGroup>
599                     <ItemGroup>
600                         <Reference Include=`System` />
601                         <Compile Include=`Class1.cs` />
602                     </ItemGroup>
603                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
604                 </Project>
605             ");
606 
607             // ---------------------
608             // Class1.cs
609             // ---------------------
610             ObjectModelHelpers.CreateFileInTempProjectDirectory("Class1.cs", @"
611                 namespace ClassLibrary16
612                 {
613 	                public class Class1
614 	                {
615 	                }
616                 }
617             ");
618 
619             MockLogger log = ObjectModelHelpers.BuildTempProjectFileExpectSuccess("foo.csproj");
620 
621             Assertion.Assert(@"Did not find expected file obj\debug\Class;Library16.dll",
622                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\Class;Library16.dll")));
623             Assertion.Assert(@"Did not find expected file obj\debug\Class;Library16.pdb",
624                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\Class;Library16.pdb")));
625             Assertion.Assert(@"Did not find expected file bin\debug\Class;Library16.dll",
626                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\Class;Library16.dll")));
627             Assertion.Assert(@"Did not find expected file bin\debug\Class;Library16.pdb",
628                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\Class;Library16.pdb")));
629 
630             log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\Class;Library16.dll")));
631         }
632 
633         /// <summary>
634         /// Regression test for bug VSWhidbey 157236:
635         ///     ESCAPING: Conversion Issue: Properties with $(xxx) as literals are not being converted correctly
636         /// </summary>
637         /// <owner>RGoel</owner>
638         [Test]
DollarSignInAssemblyName()639         public void DollarSignInAssemblyName()
640         {
641             ObjectModelHelpers.DeleteTempProjectDirectory();
642 
643             // ---------------------
644             // Foo.csproj
645             // ---------------------
646             ObjectModelHelpers.CreateFileInTempProjectDirectory("foo.csproj", @"
647                 <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
648                     <PropertyGroup>
649                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
650                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
651                         <OutputType>Library</OutputType>
652                         <AssemblyName>Class%24%28prop%29Library16</AssemblyName>
653                     </PropertyGroup>
654                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
655                         <OutputPath>bin\Debug\</OutputPath>
656                     </PropertyGroup>
657                     <ItemGroup>
658                         <Reference Include=`System` />
659                         <Compile Include=`Class1.cs` />
660                     </ItemGroup>
661                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
662                 </Project>
663             ");
664 
665             // ---------------------
666             // Class1.cs
667             // ---------------------
668             ObjectModelHelpers.CreateFileInTempProjectDirectory("Class1.cs", @"
669                 namespace ClassLibrary16
670                 {
671 	                public class Class1
672 	                {
673 	                }
674                 }
675             ");
676 
677             MockLogger log = ObjectModelHelpers.BuildTempProjectFileExpectSuccess("foo.csproj");
678 
679             Assertion.Assert(@"Did not find expected file obj\debug\Class$(prop)Library16.dll",
680                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\Class$(prop)Library16.dll")));
681             Assertion.Assert(@"Did not find expected file obj\debug\Class$(prop)Library16.pdb",
682                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\Class$(prop)Library16.pdb")));
683             Assertion.Assert(@"Did not find expected file bin\debug\Class$(prop)Library16.dll",
684                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\Class$(prop)Library16.dll")));
685             Assertion.Assert(@"Did not find expected file bin\debug\Class$(prop)Library16.pdb",
686                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\Class$(prop)Library16.pdb")));
687 
688             log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\Class$(prop)Library16.dll")));
689         }
690 
691         /// <summary>
692         /// Regression test for bug VSWhidbey 146010 and related bugs.  This is the case when one of the
693         /// source code files in the project has a filename containing a semicolon.
694         /// </summary>
695         /// <owner>RGoel</owner>
696         [Test]
SemicolonInSourceCodeFilename()697         public void SemicolonInSourceCodeFilename()
698         {
699             ObjectModelHelpers.DeleteTempProjectDirectory();
700 
701             // ---------------------
702             // Foo.csproj
703             // ---------------------
704             ObjectModelHelpers.CreateFileInTempProjectDirectory("foo.csproj", @"
705                 <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
706                     <PropertyGroup>
707                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
708                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
709                         <OutputType>Library</OutputType>
710                         <AssemblyName>ClassLibrary16</AssemblyName>
711                     </PropertyGroup>
712                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
713                         <OutputPath>bin\Debug\</OutputPath>
714                     </PropertyGroup>
715                     <ItemGroup>
716                         <Reference Include=`System` />
717                         <Compile Include=`Class%3b1.cs` />
718                     </ItemGroup>
719                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
720                 </Project>
721             ");
722 
723             // ---------------------
724             // Class1.cs
725             // ---------------------
726             ObjectModelHelpers.CreateFileInTempProjectDirectory("Class;1.cs", @"
727                 namespace ClassLibrary16
728                 {
729 	                public class Class1
730 	                {
731 	                }
732                 }
733             ");
734 
735             MockLogger log = ObjectModelHelpers.BuildTempProjectFileExpectSuccess("foo.csproj");
736 
737             Assertion.Assert(@"Did not find expected file obj\debug\ClassLibrary16.dll",
738                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\ClassLibrary16.dll")));
739             Assertion.Assert(@"Did not find expected file obj\debug\ClassLibrary16.pdb",
740                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"obj\debug\ClassLibrary16.pdb")));
741             Assertion.Assert(@"Did not find expected file bin\debug\ClassLibrary16.dll",
742                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\ClassLibrary16.dll")));
743             Assertion.Assert(@"Did not find expected file bin\debug\ClassLibrary16.pdb",
744                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\ClassLibrary16.pdb")));
745 
746             log.AssertLogContains(String.Format("foo -> {0}", Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\Debug\ClassLibrary16.dll")));
747         }
748 
749         /// <summary>
750         /// Build a .SLN file using MSBuild.  The .SLN and the projects contained within
751         /// have all sorts of crazy characters in their name (courtesy of DanMose who apparently
752         /// just ran his fingers up and down the on the upper row of his keyboard :) ).  There
753         /// is even a P2P reference between the two projects in the .SLN.
754         /// </summary>
755         /// <owner>RGoel</owner>
756         [Test]
SolutionWithLotsaCrazyCharacters()757         public void SolutionWithLotsaCrazyCharacters()
758         {
759             if (ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version35) == null)
760             {
761                 Assert.Ignore(".NET Framework 3.5 is required to be installed for this test, but it is not installed.");
762             }
763 
764             ObjectModelHelpers.DeleteTempProjectDirectory();
765 
766             // ---------------------------------------------------------------------
767             // Console;!@(foo)'^(Application1.sln
768             // ---------------------------------------------------------------------
769             ObjectModelHelpers.CreateFileInTempProjectDirectory(
770                 @"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1.sln",
771 
772                 @"Microsoft Visual Studio Solution File, Format Version 10.00
773                 # Visual Studio 2005
774                 Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `Cons.ole;!@(foo)'^(Application1`, `Console;!@(foo)'^(Application1\Cons.ole;!@(foo)'^(Application1.csproj`, `{770F2381-8C39-49E9-8C96-0538FA4349A7}`
775                 EndProject
776                 Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `Class;!@(foo)'^(Library1`, `Class;!@(foo)'^(Library1\Class;!@(foo)'^(Library1.csproj`, `{0B4B78CC-C752-43C2-BE9A-319D20216129}`
777                 EndProject
778                 Global
779 	                GlobalSection(SolutionConfigurationPlatforms) = preSolution
780 		                Debug|Any CPU = Debug|Any CPU
781 		                Release|Any CPU = Release|Any CPU
782 	                EndGlobalSection
783 	                GlobalSection(ProjectConfigurationPlatforms) = postSolution
784 		                {770F2381-8C39-49E9-8C96-0538FA4349A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
785 		                {770F2381-8C39-49E9-8C96-0538FA4349A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
786 		                {770F2381-8C39-49E9-8C96-0538FA4349A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
787 		                {770F2381-8C39-49E9-8C96-0538FA4349A7}.Release|Any CPU.Build.0 = Release|Any CPU
788 		                {0B4B78CC-C752-43C2-BE9A-319D20216129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
789 		                {0B4B78CC-C752-43C2-BE9A-319D20216129}.Debug|Any CPU.Build.0 = Debug|Any CPU
790 		                {0B4B78CC-C752-43C2-BE9A-319D20216129}.Release|Any CPU.ActiveCfg = Release|Any CPU
791 		                {0B4B78CC-C752-43C2-BE9A-319D20216129}.Release|Any CPU.Build.0 = Release|Any CPU
792 	                EndGlobalSection
793 	                GlobalSection(SolutionProperties) = preSolution
794 		                HideSolutionNode = FALSE
795 	                EndGlobalSection
796                 EndGlobal
797                 ");
798 
799             // ---------------------------------------------------------------------
800             // Console;!@(foo)'^(Application1.csproj
801             // ---------------------------------------------------------------------
802             ObjectModelHelpers.CreateFileInTempProjectDirectory(
803                 @"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1\Cons.ole;!@(foo)'^(Application1.csproj",
804 
805                 @"
806                 <Project DefaultTargets=`Build` ToolsVersion=`3.5` xmlns=`msbuildnamespace`>
807                     <PropertyGroup>
808                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
809                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
810                         <ProductVersion>8.0.50510</ProductVersion>
811                         <SchemaVersion>2.0</SchemaVersion>
812                         <ProjectGuid>{770F2381-8C39-49E9-8C96-0538FA4349A7}</ProjectGuid>
813                         <OutputType>Exe</OutputType>
814                         <AppDesignerFolder>Properties</AppDesignerFolder>
815                         <RootNamespace>Console____foo____Application1</RootNamespace>
816                         <AssemblyName>Console%3b!%40%28foo%29%27^%28Application1</AssemblyName>
817                     </PropertyGroup>
818                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
819                         <DebugSymbols>true</DebugSymbols>
820                         <DebugType>full</DebugType>
821                         <Optimize>false</Optimize>
822                         <OutputPath>bin\Debug\</OutputPath>
823                         <DefineConstants>DEBUG;TRACE</DefineConstants>
824                         <ErrorReport>prompt</ErrorReport>
825                         <WarningLevel>4</WarningLevel>
826                     </PropertyGroup>
827                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
828                         <DebugType>pdbonly</DebugType>
829                         <Optimize>true</Optimize>
830                         <OutputPath>bin\Release\</OutputPath>
831                         <DefineConstants>TRACE</DefineConstants>
832                         <ErrorReport>prompt</ErrorReport>
833                         <WarningLevel>4</WarningLevel>
834                     </PropertyGroup>
835                     <ItemGroup>
836                         <Reference Include=`System` />
837                         <Reference Include=`System.Data` />
838                         <Reference Include=`System.Xml` />
839                     </ItemGroup>
840                     <ItemGroup>
841                         <Compile Include=`Program.cs` />
842                     </ItemGroup>
843                     <ItemGroup>
844                         <ProjectReference Include=`..\Class%3b!%40%28foo%29%27^%28Library1\Class%3b!%40%28foo%29%27^%28Library1.csproj`>
845                             <Project>{0B4B78CC-C752-43C2-BE9A-319D20216129}</Project>
846                             <Name>Class%3b!%40%28foo%29%27^%28Library1</Name>
847                         </ProjectReference>
848                     </ItemGroup>
849                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
850                 </Project>
851                 ");
852 
853             // ---------------------------------------------------------------------
854             // Program.cs
855             // ---------------------------------------------------------------------
856             ObjectModelHelpers.CreateFileInTempProjectDirectory(
857                 @"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1\Program.cs",
858 
859                 @"
860                 using System;
861                 using System.Collections.Generic;
862                 using System.Text;
863 
864                 namespace Console____foo____Application1
865                 {
866 	                class Program
867 	                {
868 		                static void Main(string[] args)
869 		                {
870 			                Class____foo____Library1.Class1 foo = new Class____foo____Library1.Class1();
871 		                }
872 	                }
873                 }
874                 ");
875 
876             // ---------------------------------------------------------------------
877             // Class;!@(foo)'^(Library1.csproj
878             // ---------------------------------------------------------------------
879             ObjectModelHelpers.CreateFileInTempProjectDirectory(
880                 @"SLN;!@(foo)'^1\Class;!@(foo)'^(Library1\Class;!@(foo)'^(Library1.csproj",
881 
882                 @"
883                 <Project DefaultTargets=`Build` ToolsVersion=`3.5` xmlns=`msbuildnamespace`>
884                     <PropertyGroup>
885                         <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
886                         <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
887                         <ProductVersion>8.0.50510</ProductVersion>
888                         <SchemaVersion>2.0</SchemaVersion>
889                         <ProjectGuid>{0B4B78CC-C752-43C2-BE9A-319D20216129}</ProjectGuid>
890                         <OutputType>Library</OutputType>
891                         <AppDesignerFolder>Properties</AppDesignerFolder>
892                         <RootNamespace>Class____foo____Library1</RootNamespace>
893                         <AssemblyName>Class%3b!%40%28foo%29%27^%28Library1</AssemblyName>
894                     </PropertyGroup>
895                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
896                         <DebugSymbols>true</DebugSymbols>
897                         <DebugType>full</DebugType>
898                         <Optimize>false</Optimize>
899                         <OutputPath>bin\Debug\</OutputPath>
900                         <DefineConstants>DEBUG;TRACE</DefineConstants>
901                         <ErrorReport>prompt</ErrorReport>
902                         <WarningLevel>4</WarningLevel>
903                     </PropertyGroup>
904                     <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
905                         <DebugType>pdbonly</DebugType>
906                         <Optimize>true</Optimize>
907                         <OutputPath>bin\Release\</OutputPath>
908                         <DefineConstants>TRACE</DefineConstants>
909                         <ErrorReport>prompt</ErrorReport>
910                         <WarningLevel>4</WarningLevel>
911                     </PropertyGroup>
912                     <ItemGroup>
913                         <Reference Include=`System` />
914                         <Reference Include=`System.Data` />
915                         <Reference Include=`System.Xml` />
916                     </ItemGroup>
917                     <ItemGroup>
918                         <Compile Include=`Class1.cs` />
919                     </ItemGroup>
920                     <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
921 
922                     <!-- The old OM, which is what this solution is being built under, doesn't understand
923                          BeforeTargets, so this test was failing, because _AssignManagedMetadata was set
924                          up as a BeforeTarget for Build.  Copied here so that build will return the correct
925                          information again. -->
926                     <Target Name=`BeforeBuild`>
927                         <ItemGroup>
928                             <BuiltTargetPath Include=`$(TargetPath)`>
929                                 <ManagedAssembly>$(ManagedAssembly)</ManagedAssembly>
930                             </BuiltTargetPath>
931                         </ItemGroup>
932                     </Target>
933                 </Project>
934                 ");
935 
936             // ---------------------------------------------------------------------
937             // Class1.cs
938             // ---------------------------------------------------------------------
939             ObjectModelHelpers.CreateFileInTempProjectDirectory(
940                 @"SLN;!@(foo)'^1\Class;!@(foo)'^(Library1\Class1.cs",
941 
942                 @"
943                 namespace Class____foo____Library1
944                 {
945 	                public class Class1
946 	                {
947 	                }
948                 }
949                 ");
950 
951             // Cons.ole;!@(foo)'^(Application1
952             string targetForFirstProject = "Cons_ole_!__foo__^_Application1";
953             MockLogger log = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1.sln", new string[] { targetForFirstProject }, new BuildPropertyGroup());
954 
955             Assertion.Assert(@"Did not find expected file Console;!@(foo)'^(Application1.exe",
956                 File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir,
957                 @"SLN;!@(foo)'^1\Console;!@(foo)'^(Application1\bin\debug\Console;!@(foo)'^(Application1.exe")));
958         }
959     }
960 }
961