Merge pull request #1349 from martinjt/MachineKeyProtect
[mono.git] / mcs / class / Microsoft.Build / Test / Microsoft.Build.Execution / ProjectInstanceTest.cs
1 //
2 // ProjectInstanceTest.cs
3 //
4 // Author:
5 //   Atsushi Enomoto (atsushi@xamarin.com)
6 //
7 // Copyright (C) 2013 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.IO;
30 using System.Linq;
31 using System.Xml;
32 using Microsoft.Build.Construction;
33 using Microsoft.Build.Execution;
34 using NUnit.Framework;
35 using Microsoft.Build.Evaluation;
36 using Microsoft.Build.Utilities;
37 using Microsoft.Build.Framework;
38 using Microsoft.Build.Logging;
39
40 namespace MonoTests.Microsoft.Build.Execution
41 {
42         [TestFixture]
43         public class ProjectInstanceTest
44         {
45                 [Test]
46                 public void ItemsAndProperties ()
47                 {
48             string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
49   <ItemGroup>
50     <X Condition='false' Include='bar.txt' />
51     <X Include='foo.txt'>
52       <M>m</M>
53       <N>=</N>
54     </X>
55   </ItemGroup>
56   <PropertyGroup>
57     <P Condition='false'>void</P>
58     <P Condition='true'>valid</P>
59   </PropertyGroup>
60 </Project>";
61             var xml = XmlReader.Create (new StringReader(project_xml));
62             var root = ProjectRootElement.Create (xml);
63             var proj = new ProjectInstance (root);
64             var item = proj.Items.First ();
65                         Assert.AreEqual ("foo.txt", item.EvaluatedInclude, "#1");
66                         var prop = proj.Properties.First (p => p.Name=="P");
67                         Assert.AreEqual ("valid", prop.EvaluatedValue, "#2");
68                         Assert.IsNotNull (proj.GetProperty ("MSBuildProjectDirectory"), "#3");
69                         Assert.AreEqual ("4.0", proj.ToolsVersion, "#4");
70                 }
71                 
72                 [Test]
73                 public void ExplicitToolsVersion ()
74                 {
75             string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' />";
76             var xml = XmlReader.Create (new StringReader(project_xml));
77             var root = ProjectRootElement.Create (xml);
78                         var proj = new ProjectInstance (root, null, "4.0", new ProjectCollection ());
79                         Assert.AreEqual ("4.0", proj.ToolsVersion, "#1");
80                 }
81                 
82                 [Test]
83                 public void BuildEmptyProject ()
84                 {
85                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' />";
86                         var xml = XmlReader.Create (new StringReader (project_xml), null, "file://localhost/foo.xml");
87                         var root = ProjectRootElement.Create (xml);
88                         // This seems to do nothing and still returns true
89                         root.FullPath = "ProjectInstanceTest.BuildEmptyProject.1.proj";
90                         Assert.IsTrue (new ProjectInstance (root).Build (), "#1");
91                         // This seems to fail to find the appropriate target
92                         root.FullPath = "ProjectInstanceTest.BuildEmptyProject.2.proj";
93                         Assert.IsFalse (new ProjectInstance (root).Build ("Build", null), "#2");
94                         // Thus, this tries to build all the targets (empty) and no one failed, so returns true(!)
95                         root.FullPath = "ProjectInstanceTest.BuildEmptyProject.3.proj";
96                         Assert.IsTrue (new ProjectInstance (root).Build (new string [0], null), "#3");
97                         // Actially null "targets" is accepted and returns true(!!)
98                         root.FullPath = "ProjectInstanceTest.BuildEmptyProject.4.proj";
99                         Assert.IsTrue (new ProjectInstance (root).Build ((string []) null, null), "#4");
100                         // matching seems to be blindly done, null string also results in true(!!)
101                         root.FullPath = "ProjectInstanceTest.BuildEmptyProject.5.proj";
102                         Assert.IsTrue (new ProjectInstance (root).Build ((string) null, null), "#5");
103                 }
104                 
105                 [Test]
106                 public void DefaultTargets ()
107                 {
108                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
109   <Import Project='$(MSBuildToolsPath)\Microsoft.Common.targets' />
110 </Project>";
111                         var xml = XmlReader.Create (new StringReader(project_xml));
112                         var root = ProjectRootElement.Create (xml);
113                         var proj = new ProjectInstance (root);
114                         Assert.AreEqual (1, proj.DefaultTargets.Count, "#1");
115                         Assert.AreEqual ("Build", proj.DefaultTargets [0], "#2");
116                 }
117                 
118                 [Test]
119                 public void DefaultTargets2 ()
120                 {
121             string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
122   <Import Project='$(MSBuildToolsPath)\Microsoft.CSharp.targets' />
123 </Project>";
124             var xml = XmlReader.Create (new StringReader (project_xml));
125             var root = ProjectRootElement.Create (xml);
126                         root.FullPath = "ProjectTest.BuildCSharpTargetBuild.proj";
127                         var proj = new ProjectInstance (root);
128                         Assert.AreEqual (1, proj.DefaultTargets.Count, "#1");
129                         Assert.AreEqual ("Build", proj.DefaultTargets [0], "#2");
130                 }
131                 
132                 [Test]
133                 public void PropertyOverrides ()
134                 {
135             string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
136   <PropertyGroup>
137     <X>x</X>
138   </PropertyGroup>
139   <PropertyGroup>
140     <X>y</X>
141   </PropertyGroup>
142 </Project>";
143             var xml = XmlReader.Create (new StringReader (project_xml));
144             var root = ProjectRootElement.Create (xml);
145                         root.FullPath = "ProjectTest.BuildCSharpTargetBuild.proj";
146                         var proj = new ProjectInstance (root);
147                         Assert.AreEqual ("y", proj.GetPropertyValue ("X"), "#1");
148                 }
149                 
150                 [Test]
151                 public void FirstUsingTaskTakesPrecedence1 ()
152                 {
153                         FirstUsingTaskTakesPrecedenceCommon (false, false);
154                 }
155                 
156                 [Test]
157                 public void FirstUsingTaskTakesPrecedence2 ()
158                 {
159                         FirstUsingTaskTakesPrecedenceCommon (true, true);
160                 }
161                 
162                 public void FirstUsingTaskTakesPrecedenceCommon (bool importFirst, bool buildShouldSucceed)
163                 {
164                         string thisAssembly = new Uri (GetType ().Assembly.CodeBase).LocalPath;
165                         string filename = "Test/ProjectTargetInstanceTest.FirstUsingTaskTakesPrecedence.Import.proj";
166                         string imported_xml = string.Format (@"<Project DefaultTargets='Foo' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
167   <UsingTask TaskName='MonoTests.Microsoft.Build.Execution.MyTask' AssemblyFile='{0}' />
168 </Project>", thisAssembly);
169                         string usingTask =  string.Format ("<UsingTask TaskName='MonoTests.Microsoft.Build.Execution.SubNamespace.MyTask' AssemblyFile='{0}' />", thisAssembly);
170                         string import = string.Format ("<Import Project='{0}' />", filename);
171                         string project_xml = string.Format (@"<Project DefaultTargets='Foo' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
172                         {0}
173                         {1}
174   <Target Name='Foo'>
175     <MyTask />
176   </Target>
177 </Project>", 
178                                 importFirst ? import : usingTask, importFirst ? usingTask : import);
179                         try {
180                                 File.WriteAllText (filename, imported_xml);
181                                 var xml = XmlReader.Create (new StringReader (project_xml));
182                                 var root = ProjectRootElement.Create (xml);
183                                 Assert.IsTrue (root.UsingTasks.All (u => !string.IsNullOrEmpty (u.AssemblyFile)), "#1");
184                                 Assert.IsTrue (root.UsingTasks.All (u => string.IsNullOrEmpty (u.AssemblyName)), "#2");
185                                 root.FullPath = "ProjectTargetInstanceTest.FirstUsingTaskTakesPrecedence.proj";
186                                 var proj = new ProjectInstance (root);
187                                 Assert.AreEqual (buildShouldSucceed, proj.Build (), "#3");
188                         } finally {
189                                 File.Delete (filename);
190                         }
191                 }
192                 
193                 [Test]
194                 public void MissingTypeForUsingTaskStillWorks ()
195                 {
196                         string thisAssembly = new Uri (GetType ().Assembly.CodeBase).LocalPath;
197                         string project_xml = string.Format (@"<Project DefaultTargets='X' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
198   <UsingTask AssemblyFile='{0}' TaskName='NonExistent' />
199   <Target Name='X' />
200 </Project>", thisAssembly);
201                         var xml = XmlReader.Create (new StringReader (project_xml));
202                         var root = ProjectRootElement.Create (xml);
203                         root.FullPath = "ProjectInstanceTest.MissingTypeForUsingTaskStillWorks.proj";
204                         var proj = new ProjectInstance (root);
205                         Assert.IsTrue (proj.Build (), "#1");
206                 }
207                 
208                 [Test]
209                 public void MissingTypeForUsingTaskStillWorks2 ()
210                 {
211                         string thisAssembly = new Uri (GetType ().Assembly.CodeBase).LocalPath;
212                         string project_xml = @"<Project DefaultTargets='X' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
213   <UsingTask AssemblyFile='nonexistent.dll' TaskName='NonExistent' />
214   <Target Name='X' />
215 </Project>";
216             var xml = XmlReader.Create (new StringReader (project_xml));
217             var root = ProjectRootElement.Create (xml);
218                         root.FullPath = "ProjectInstanceTest.MissingTypeForUsingTaskStillWorks2.proj";
219                         var proj = new ProjectInstance (root);
220                         Assert.IsTrue (proj.Build (), "#1");
221                 }
222
223                 [Test]
224                 public void ExpandStringWithMetadata ()
225                 {
226                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
227   <ItemGroup>
228     <Foo Include='xxx'><M>x</M></Foo>
229     <Foo Include='yyy'><M>y</M></Foo>
230   </ItemGroup>
231 </Project>";
232                         var xml = XmlReader.Create (new StringReader (project_xml));
233                         var root = ProjectRootElement.Create (xml);
234                         root.FullPath = "ProjectInstanceTest.ExpandStringWithMetadata.proj";
235                         var proj = new ProjectInstance (root);
236                         Assert.AreEqual ("xxx;yyy", proj.ExpandString ("@(FOO)"), "#1"); // so, metadata is gone...
237                 }
238
239                 [Test]
240                 public void EvaluatePropertyWithQuotation ()
241                 {
242                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
243   <ItemGroup>
244     <Foo Include='abc/xxx.txt' />
245   </ItemGroup>
246   <PropertyGroup>
247     <B>foobar</B>
248   </PropertyGroup>
249   <Target Name='default'>
250     <CreateProperty Value=""@(Foo->'%(Filename)%(Extension)')"">
251       <Output TaskParameter='Value' PropertyName='P' />
252     </CreateProperty>
253     <CreateProperty Value='$(B)|$(P)'>
254       <Output TaskParameter='Value' PropertyName='Q' />
255     </CreateProperty>
256   </Target>
257 </Project>";
258                         var xml = XmlReader.Create (new StringReader (project_xml));
259                         var root = ProjectRootElement.Create (xml);
260                         root.FullPath = "ProjectInstanceTest.EvaluatePropertyWithQuotation.proj";
261                         var proj = new ProjectInstance (root);
262                         proj.Build ();
263                         var p = proj.GetProperty ("P");
264                         Assert.AreEqual ("xxx.txt", p.EvaluatedValue, "#1");
265                         var q = proj.GetProperty ("Q");
266                         Assert.AreEqual ("foobar|xxx.txt", q.EvaluatedValue, "#2");
267                 }
268
269                 [Test]
270                 public void Choose ()
271                 {
272                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
273   <Choose>
274     <When Condition="" '$(DebugSymbols)' != '' "">
275       <PropertyGroup>
276         <DebugXXX>True</DebugXXX>
277       </PropertyGroup>
278     </When>
279     <Otherwise>
280       <PropertyGroup>
281         <DebugXXX>False</DebugXXX>
282       </PropertyGroup>
283     </Otherwise>
284   </Choose>
285 </Project>";
286                         var xml = XmlReader.Create (new StringReader (project_xml));
287                         var root = ProjectRootElement.Create (xml);
288                         root.FullPath = "ProjectInstanceTest.Choose.proj";
289                         var proj = new ProjectInstance (root);
290                         var p = proj.GetProperty ("DebugXXX");
291                         Assert.IsNotNull (p, "#1");
292                         Assert.AreEqual ("False", p.EvaluatedValue, "#2");
293                 }
294
295                 [Test]
296                 public void ConditionalExpression ()
297                 {
298                         string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
299         <PropertyGroup>
300                 <NoCompilerStandardLib>true</NoCompilerStandardLib>
301                 <ResolveAssemblyReferencesDependsOn>$(ResolveAssemblyReferencesDependsOn);_AddCorlibReference</ResolveAssemblyReferencesDependsOn>
302         </PropertyGroup>
303 </Project>";
304                         var xml = XmlReader.Create (new StringReader (project_xml));
305                         var root = ProjectRootElement.Create (xml);
306                         root.FullPath = "ProjectInstanceTest.ConditionalExpression.proj";
307                         var proj = new ProjectInstance (root);
308                         var p = proj.GetProperty ("ResolveAssemblyReferencesDependsOn");
309                         Assert.IsNotNull (p, "#1");
310                         Assert.AreEqual (";_AddCorlibReference", p.EvaluatedValue, "#2");
311                 }
312
313                 [Test]
314                 public void ItemsAndPostEvaluationCondition ()
315                 {
316                         // target-assigned property X is not considered when evaluating condition for C.
317                         string project_xml = @"<Project DefaultTargets='X;Y' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
318         <ItemGroup>
319                 <A Include='foo.txt' />
320                 <B Condition='False' Include='bar.txt' />
321                 <C Condition=""'$(X)'=='True'"" Include='baz.txt' />
322         </ItemGroup>
323         <Target Name='X'>
324                 <CreateProperty Value='True'>
325                         <Output TaskParameter='Value' PropertyName='X' />
326                     </CreateProperty>
327         </Target>
328         <Target Name='Y'>
329                 <Error Condition=""'@(C)'==''"" Text='missing C. X is $(X)' />
330         </Target>
331 </Project>";
332                         var xml = XmlReader.Create (new StringReader (project_xml));
333                         var root = ProjectRootElement.Create (xml);
334                         root.FullPath = "ProjectInstanceTest.ItemsAndPostEvaluationCondition.proj";
335                         var proj = new ProjectInstance (root);
336                         Assert.AreEqual (1, proj.Items.Count, "Count1");
337                         Assert.IsFalse (proj.Build (), "Build");
338                         Assert.AreEqual (1, proj.Items.Count, "Count2");
339                 }
340
341                 [Test]
342                 [Category ("NotWorking")] // until we figure out why it fails on wrench.
343                 public void ItemsInTargets ()
344                 {
345                         string project_xml = @"<Project DefaultTargets='Default' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
346         <Target Name='Default'>
347                 <PropertyGroup>
348                         <_ExplicitMSCorlibPath>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToStandardLibraries ('$(TargetFrameworkIdentifier)', '$(TargetFrameworkVersion)', '$(TargetFrameworkProfile)'))\mscorlib.dll</_ExplicitMSCorlibPath>
349                 </PropertyGroup>
350                 <ItemGroup>
351                         <_ExplicitReference
352                                 Include='$(_ExplicitMSCorlibPath)'
353                                 Condition='Exists($(_ExplicitMSCorlibPath))'>
354                                 <Private>false</Private>
355                         </_ExplicitReference>
356                 </ItemGroup>
357         </Target>
358         <Import Project='$(MSBuildBinPath)\\Microsoft.CSharp.targets' />
359 </Project>";
360                         var xml = XmlReader.Create (new StringReader (project_xml));
361                         var root = ProjectRootElement.Create (xml);
362                         root.FullPath = "ProjectInstanceTest.ConditionalExpression.proj";
363                         var proj = new ProjectInstance (root, null, "4.0", ProjectCollection.GlobalProjectCollection);
364                         proj.Build ();
365                         // make sure the property value expansion is done successfully.
366                         Assert.IsTrue (!string.IsNullOrEmpty (proj.GetPropertyValue ("_ExplicitMSCorlibPath")), "premise: propertyValue by ToolLocationHelper func call");
367                         var items = proj.GetItems ("_ExplicitReference");
368                         // make sure items are stored after build.
369                         Assert.IsTrue (items.Any (), "items.Any");
370                         Assert.IsTrue (!string.IsNullOrEmpty (items.First ().EvaluatedInclude), "item.EvaluatedInclude");
371                 }
372
373                 [Test]
374                 [Category ("NotWorking")]
375                 public void ConditionalCyclicDependence ()
376                 {
377                         string project_xml = @"<Project DefaultTargets='Build' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
378         <PropertyGroup>
379                 <C>False</C>
380         </PropertyGroup>
381         <Target Name='Build' DependsOnTargets='ResolveReferences' />
382         <Target Name='Build2' DependsOnTargets='Bar' />
383         <Target Name='ResolveReferences' DependsOnTargets='Foo;Bar' />
384         <Target Name='Foo'>
385                 <CreateProperty Value='True'>
386                         <Output TaskParameter='Value' PropertyName='C' />
387                 </CreateProperty>
388         </Target>
389         <Target Name='Bar' Condition='!($(C))' DependsOnTargets='ResolveReferences'>
390         </Target>
391 </Project>";
392                         var xml = XmlReader.Create (new StringReader (project_xml));
393                         var root = ProjectRootElement.Create (xml);
394                         root.FullPath = "ProjectInstanceTest.ConditionalCyclicDependence.proj";
395                         var proj = new ProjectInstance (root, null, "4.0", ProjectCollection.GlobalProjectCollection);
396                         Assert.IsTrue (proj.Build (), "#1");
397                         Assert.IsFalse (proj.Build ("Build2", new ILogger [0]), "#2");
398                 }
399         }
400         
401         namespace SubNamespace
402         {
403                 public class MyTask : Task
404                 {
405                         public override bool Execute ()
406                         {
407                                 return false;
408                         }
409                 }
410         }
411                 
412         public class MyTask : Task
413         {
414                 public override bool Execute ()
415                 {
416                         return true;
417                 }
418         }
419 }
420