Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Microsoft.Build.Engine / Test / Microsoft.Build.BuildEngine / TargetTest.cs
1 //
2 // TargetTest.cs
3 //
4 // Authors:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //   Andres G. Aragoneses (knocte@gmail.com)
7 //
8 // (C) 2006 Marek Sieradzki
9 // (C) 2012 Andres G. Aragoneses
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 using System;
31 using System.Collections;
32 using Microsoft.Build.BuildEngine;
33 using Microsoft.Build.Framework;
34 using Microsoft.Build.Utilities;
35 using NUnit.Framework;
36 using System.IO;
37
38 namespace MonoTests.Microsoft.Build.BuildEngine {
39         [TestFixture]
40         public class TargetTest {
41                 
42                 Engine                  engine;
43                 Project                 project;
44                 
45                 [Test]
46                 public void TestFromXml1 ()
47                 {
48                         string documentString = @"
49                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
50                                         <Target Name='Target'>
51                                         </Target>
52                                 </Project>
53                         ";
54
55                         engine = new Engine (Consts.BinPath);
56
57                         project = engine.CreateNewProject ();
58                         project.LoadXml (documentString);
59
60                         Target[] t = new Target [1];
61                         project.Targets.CopyTo (t, 0);
62
63                         Assert.AreEqual (String.Empty, t [0].Condition, "A1");
64                         Assert.AreEqual (String.Empty, t [0].DependsOnTargets, "A2");
65                         Assert.IsFalse (t [0].IsImported, "A3");
66                         Assert.AreEqual ("Target", t [0].Name, "A4");
67                 }
68
69                 [Test]
70                 public void TestFromXml2 ()
71                 {
72                         string documentString = @"
73                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
74                                         <Target Name='Target' Condition='false' DependsOnTargets='X' >
75                                         </Target>
76                                 </Project>
77                         ";
78
79                         engine = new Engine (Consts.BinPath);
80
81                         project = engine.CreateNewProject ();
82                         project.LoadXml (documentString);
83
84                         Target[] t = new Target [1];
85                         project.Targets.CopyTo (t, 0);
86
87                         Assert.AreEqual ("false", t [0].Condition, "A1");
88                         Assert.AreEqual ("X", t [0].DependsOnTargets, "A2");
89
90                         t [0].Condition = "true";
91                         t [0].DependsOnTargets = "A;B";
92
93                         Assert.AreEqual ("true", t [0].Condition, "A3");
94                         Assert.AreEqual ("A;B", t [0].DependsOnTargets, "A4");
95                 }
96
97                 [Test]
98                 public void TestAddNewTask1 ()
99                 {
100                         string documentString = @"
101                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
102                                         <Target Name='Target' >
103                                         </Target>
104                                 </Project>
105                         ";
106
107                         engine = new Engine (Consts.BinPath);
108
109                         project = engine.CreateNewProject ();
110                         project.LoadXml (documentString);
111
112                         Target[] t = new Target [1];
113                         project.Targets.CopyTo (t, 0);
114
115                         BuildTask bt = t [0].AddNewTask ("Message");
116
117                         Assert.AreEqual ("Message", bt.Name, "A1");
118                 }
119
120                 [Test]
121                 [ExpectedException (typeof (ArgumentNullException))]
122                 public void TestAddNewTask2 ()
123                 {
124                         string documentString = @"
125                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
126                                         <Target Name='Target' >
127                                         </Target>
128                                 </Project>
129                         ";
130
131                         engine = new Engine (Consts.BinPath);
132
133                         project = engine.CreateNewProject ();
134                         project.LoadXml (documentString);
135
136                         Target[] t = new Target [1];
137                         project.Targets.CopyTo (t, 0);
138
139                         t [0].AddNewTask (null);
140                 }
141
142                 [Test]
143                 public void TestGetEnumerator ()
144                 {
145                         string documentString = @"
146                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
147                                         <Target Name='Target' >
148                                                 <Message Text='text' />
149                                                 <Warning Text='text' />
150                                         </Target>
151                                 </Project>
152                         ";
153
154                         engine = new Engine (Consts.BinPath);
155
156                         project = engine.CreateNewProject ();
157                         project.LoadXml (documentString);
158
159                         Target[] t = new Target [1];
160                         project.Targets.CopyTo (t, 0);
161
162                         IEnumerator e = t [0].GetEnumerator ();
163                         e.MoveNext ();
164                         Assert.AreEqual ("Message", ((BuildTask) e.Current).Name, "A1");
165                         e.MoveNext ();
166                         Assert.AreEqual ("Warning", ((BuildTask) e.Current).Name, "A2");
167                         Assert.IsFalse (e.MoveNext (), "A3");
168                 }
169
170                 [Test]
171                 public void TestOutOfRangeElementsOfTheEnumerator()
172                 {
173                         string documentString =
174                                 @"
175                                 <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
176                                         <Target Name='A'>
177                                                 <Message Text='text' />
178                                         </Target>
179                                 </Project>";
180
181                         engine = new Engine (Consts.BinPath);
182
183                         project = engine.CreateNewProject ();
184                         project.LoadXml (documentString);
185
186                         Assert.IsFalse (project.Targets == null, "A1");
187                         Assert.AreEqual (1, project.Targets.Count, "A2");
188
189                         Target target = project.Targets ["A"];
190                         Assert.IsFalse (target == null, "A3");
191
192                         IEnumerator e = target.GetEnumerator ();
193
194                         bool thrown = false;
195                         try {
196                                 var name = ((BuildTask)e.Current).Name;
197                         } catch (InvalidOperationException) { // "Enumeration has not started. Call MoveNext"
198                                 thrown = true;
199                         }
200                         if (!thrown)
201                                 Assert.Fail ("A4: Should have thrown IOE");
202
203
204                         Assert.AreEqual (true, e.MoveNext (), "A5");
205                         Assert.AreEqual ("Message", ((BuildTask)e.Current).Name, "A6");
206                         Assert.AreEqual (false, e.MoveNext (), "A7");
207                         try {
208                                 var name = ((BuildTask) e.Current).Name;
209                         } catch (InvalidOperationException) { //"Enumeration already finished."
210                                 return;
211                         }
212                         Assert.Fail ("A8: Should have thrown IOE, because there's only one buidTask");
213                 }
214
215                 [Test]
216                 [ExpectedException (typeof (InvalidProjectFileException))]
217                 public void TestOnError1 ()
218                 {
219                         Engine engine;
220                         Project project;
221
222                         string documentString = @"
223                                 <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
224                                         <Target Name='A'>
225                                                 <OnError ExecuteTargets='B' />
226                                                 <Error Text='text' />
227                                         </Target>
228                                 </Project>
229                         ";
230
231                         engine = new Engine (Consts.BinPath);
232                         project = engine.CreateNewProject ();
233                         project.LoadXml (documentString);
234                 }
235
236                 [Test]
237                 public void TestRemoveTask1 ()
238                 {
239                         string documentString = @"
240                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
241                                         <Target Name='Target' >
242                                                 <Message Text='text' />
243                                                 <Warning Text='text' />
244                                         </Target>
245                                 </Project>
246                         ";
247
248                         engine = new Engine (Consts.BinPath);
249
250                         project = engine.CreateNewProject ();
251                         project.LoadXml (documentString);
252
253                         Target[] t = new Target [1];
254                         project.Targets.CopyTo (t, 0);
255
256                         IEnumerator e = t [0].GetEnumerator ();
257                         e.MoveNext ();
258                         t [0].RemoveTask ((BuildTask) e.Current);
259                         e = t [0].GetEnumerator ();
260                         e.MoveNext ();
261                         Assert.AreEqual ("Warning", ((BuildTask) e.Current).Name, "A1");
262                         Assert.IsFalse (e.MoveNext (), "A2");
263                 }
264
265                 [Test]
266                 [ExpectedException (typeof (ArgumentNullException))]
267                 public void TestRemoveTask2 ()
268                 {
269                         string documentString = @"
270                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
271                                         <Target Name='Target' >
272                                         </Target>
273                                 </Project>
274                         ";
275
276                         engine = new Engine (Consts.BinPath);
277
278                         project = engine.CreateNewProject ();
279                         project.LoadXml (documentString);
280
281                         Target[] t = new Target [1];
282                         project.Targets.CopyTo (t, 0);
283                         t [0].RemoveTask (null);
284                 }
285
286                 [Test]
287                 public void TestTargetOutputs1 ()
288                 {
289                         Engine engine;
290                         Project project;
291
292                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
293                         <ItemGroup>
294                                 <fruit Include=""apple""/>
295                                 <fruit Include=""rhubarb""/>
296                                 <fruit Include=""apricot""/>
297                         </ItemGroup>
298
299                         <Target Name=""Main"">
300                                 <CallTarget Targets=""foo"">
301                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
302                                 </CallTarget>
303
304                                 <CallTarget Targets=""foo"">
305                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
306                                 </CallTarget>
307                                 <Message Text=""AllOut: @(AllOut)""/>
308                         </Target>
309
310                         <Target Name=""foo"" Outputs=""@(FooItem)"">
311                                 <Message Text=""foo called""/>
312                                 <CreateItem Include=""%(fruit.Identity)"">
313                                         <Output TaskParameter=""Include"" ItemName=""FooItem""/>
314                                 </CreateItem>
315                                 <Message Text=""FooItem: @(FooItem)""/>
316                         </Target>
317                 </Project>";
318
319                         engine = new Engine (Consts.BinPath);
320                         project = engine.CreateNewProject ();
321                         project.LoadXml (documentString);
322
323                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
324                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
325                         engine.RegisterLogger (logger);
326
327                         bool result = project.Build ("Main");
328                         if (!result) {
329                                 logger.DumpMessages ();
330                                 Assert.Fail ("Build failed");
331                         }
332
333                         try {
334                                 Assert.AreEqual (3, logger.NormalMessageCount, "Expected number of messages");
335                                 logger.CheckLoggedMessageHead ("foo called", "A1");
336                                 logger.CheckLoggedMessageHead ("FooItem: apple;rhubarb;apricot", "A2");
337                                 logger.CheckLoggedMessageHead ("AllOut: apple;rhubarb;apricot;apple;rhubarb;apricot", "A3");
338                                 Assert.AreEqual (0, logger.NormalMessageCount, "Extra messages found");
339
340                                 Assert.AreEqual (2, logger.TargetStarted, "TargetStarted count");
341                                 Assert.AreEqual (2, logger.TargetFinished, "TargetFinished count");
342                                 Assert.AreEqual (8, logger.TaskStarted, "TaskStarted count");
343                                 Assert.AreEqual (8, logger.TaskFinished, "TaskFinished count");
344
345                         } catch (AssertionException) {
346                                 logger.DumpMessages ();
347                                 throw;
348                         }
349                 }
350
351 #if NET_3_5
352                 [Test]
353                 public void BuildProjectWithItemGroupInsideTarget()
354                 {
355                         ItemGroupInsideATarget ();
356                 }
357
358                 private MonoTests.Microsoft.Build.Tasks.TestMessageLogger ItemGroupInsideATarget() {
359                         var engine = new Engine(Consts.BinPath);
360                         var project = engine.CreateNewProject();
361                         var projectXml = GetProjectXmlWithItemGroupInsideATarget ();
362                         project.LoadXml(projectXml);
363
364                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
365                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
366                         engine.RegisterLogger (logger);
367
368                         bool result = project.Build("Main");
369                         if (!result)
370                         {
371                                 logger.DumpMessages ();
372                                 Assert.Fail("Build failed");
373                         }
374
375                         return logger;
376                 }
377
378                 private string GetProjectXmlWithItemGroupInsideATarget ()
379                 {
380                         return
381                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
382                                         <ItemGroup>
383                                                 <fruit Include=""apple""/>
384                                                 <fruit Include=""apricot""/>
385                                         </ItemGroup>
386
387                                         <Target Name=""Main"">
388                                                 <ItemGroup>
389                                                         <fruit Include=""raspberry"" />
390                                                 </ItemGroup>
391                                                 <Message Text=""%(fruit.Identity)""/>
392                                         </Target>
393                                 </Project>";
394                 }
395
396                 [Test]
397                 [Category ("NotWorking")] //https://bugzilla.xamarin.com/show_bug.cgi?id=1862
398                 public void BuildProjectOutputWithItemGroupInsideTarget()
399                 {
400                         var logger = ItemGroupInsideATarget ();
401
402                         try
403                         {
404                                 Assert.AreEqual(3, logger.NormalMessageCount, "Expected number of messages");
405                                 logger.CheckLoggedMessageHead("apple", "A1");
406                                 logger.CheckLoggedMessageHead("apricot", "A2");
407                                 logger.CheckLoggedMessageHead("raspberry", "A3");
408                                 Assert.AreEqual(0, logger.NormalMessageCount, "Extra messages found");
409
410                                 Assert.AreEqual(1, logger.TargetStarted, "TargetStarted count");
411                                 Assert.AreEqual(1, logger.TargetFinished, "TargetFinished count");
412                                 Assert.AreEqual(3, logger.TaskStarted, "TaskStarted count");
413                                 Assert.AreEqual(3, logger.TaskFinished, "TaskFinished count");
414
415                         }
416                         catch (AssertionException)
417                         {
418                                 logger.DumpMessages();
419                                 throw;
420                         }
421                 }
422 #endif
423
424                 [Test]
425                 public void TestTargetOutputsIncludingMetadata ()
426                 {
427                         Engine engine;
428                         Project project;
429
430                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
431                         <ItemGroup>
432                                 <fruit Include=""apple""><md>a</md></fruit>
433                                 <fruit Include=""rhubarb""><md>b</md></fruit>
434                                 <fruit Include=""apricot""><md>c</md></fruit>
435                         </ItemGroup>
436
437                         <Target Name=""Main"">
438                                 <CallTarget Targets=""foo"">
439                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
440                                 </CallTarget>
441
442                                 <CallTarget Targets=""foo"">
443                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
444                                 </CallTarget>
445                                 <Message Text=""AllOut: @(AllOut) metadata: %(AllOut.md)""/>
446                         </Target>
447
448                         <Target Name=""foo"" Outputs=""@(FooItem)"">
449                                 <Message Text=""foo called""/>
450                                 <CreateItem Include=""@(fruit)"">
451                                         <Output TaskParameter=""Include"" ItemName=""FooItem""/>
452                                 </CreateItem>
453                                 <Message Text=""FooItem: @(FooItem) metadata: %(FooItem.md)""/>
454                         </Target>
455                 </Project>";
456
457                         engine = new Engine (Consts.BinPath);
458                         project = engine.CreateNewProject ();
459                         project.LoadXml (documentString);
460
461                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
462                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
463                         engine.RegisterLogger (logger);
464
465                         bool result = project.Build ("Main");
466                         if (!result) {
467                                 logger.DumpMessages ();
468                                 Assert.Fail ("Build failed");
469                         }
470
471                         try {
472                                 logger.CheckLoggedMessageHead ("foo called", "A1");
473                                 logger.CheckLoggedMessageHead ("FooItem: apple metadata: a", "A2");
474                                 logger.CheckLoggedMessageHead ("FooItem: rhubarb metadata: b", "A3");
475                                 logger.CheckLoggedMessageHead ("FooItem: apricot metadata: c", "A4");
476
477                                 logger.CheckLoggedMessageHead ("AllOut: apple;apple metadata: a", "A5");
478                                 logger.CheckLoggedMessageHead ("AllOut: rhubarb;rhubarb metadata: b", "A6");
479                                 logger.CheckLoggedMessageHead ("AllOut: apricot;apricot metadata: c", "A7");
480
481                                 Assert.AreEqual (0, logger.NormalMessageCount, "Extra messages found");
482
483                                 Assert.AreEqual (2, logger.TargetStarted, "TargetStarted count");
484                                 Assert.AreEqual (2, logger.TargetFinished, "TargetFinished count");
485                                 Assert.AreEqual (10, logger.TaskStarted, "TaskStarted count");
486                                 Assert.AreEqual (10, logger.TaskFinished, "TaskFinished count");
487
488                         } catch (AssertionException) {
489                                 logger.DumpMessages ();
490                                 throw;
491                         }
492                 }
493
494                 [Test]
495                 public void TestOverridingTargets ()
496                 {
497                         Engine engine;
498                         Project project;
499
500                         string second = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
501                                 <Target Name='BeforeBuild'/>
502                                 <Target Name='AfterBuild'/>
503                                 <Target Name='Build' DependsOnTargets='BeforeBuild'>
504                                         <Message Text='Build executing'/>
505                                         <CallTarget Targets='AfterBuild'/>
506                                 </Target>
507                 </Project>";
508                         using (StreamWriter sw = new StreamWriter (Path.Combine ("Test", Path.Combine ("resources", "second.proj")))) {
509                                 sw.Write (second);
510                         }
511
512                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
513                                 <Target Name='AfterBuild'>
514                                         <Message Text='Overriding AfterBuild'/>
515                                 </Target>
516
517                                 <Import Project='Test/resources/second.proj'/>
518                                 <Target Name='BeforeBuild'>
519                                         <Message Text='Overriding BeforeBuild'/>
520                                 </Target>
521                 </Project>";
522
523                         engine = new Engine (Consts.BinPath);
524                         project = engine.CreateNewProject ();
525                         project.LoadXml (documentString);
526
527                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
528                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
529                         engine.RegisterLogger (logger);
530
531                         bool result = project.Build ("Build");
532                         if (!result) {
533                                 logger.DumpMessages ();
534                                 Assert.Fail ("Build failed");
535                         }
536
537                         logger.CheckLoggedMessageHead ("Overriding BeforeBuild", "A1");
538                         logger.CheckLoggedMessageHead ("Build executing", "A1");
539
540                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected extra messages found");
541                 }
542
543 #if NET_4_0
544                 [Test]
545                 public void TestBeforeAndAfterTargets ()
546                 {
547                         Engine engine;
548                         Project project;
549
550                         string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
551                           <Target Name=""DefaultBeforeTarget1"" BeforeTargets=""Default"">
552                             <Message Text=""Hello from DefaultBeforeTarget1""/>
553                           </Target>
554
555                           <Target Name=""DefaultBeforeTarget2"" BeforeTargets=""Default;Default;NonExistant"">
556                             <Message Text=""Hello from DefaultBeforeTarget2""/>
557                           </Target>
558
559
560                           <Target Name=""DefaultAfterTarget"" AfterTargets=""Default  ; Foo"">
561                             <Message Text=""Hello from DefaultAfterTarget""/>
562                           </Target>
563
564                           <Target Name=""Default"" DependsOnTargets=""DefaultDependsOn"">
565                             <Message Text=""Hello from Default""/>
566                           </Target>
567
568                           <Target Name=""DefaultDependsOn"">
569                             <Message Text=""Hello from DefaultDependsOn""/>
570                           </Target>
571                         </Project>";
572
573                         engine = new Engine ();
574                         project = engine.CreateNewProject ();
575                         project.LoadXml (projectString);
576
577                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
578                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
579                         engine.RegisterLogger (logger);
580
581                         if (!project.Build ("Default")) {
582                                 logger.DumpMessages ();
583                                 Assert.Fail ("Build failed");
584                         }
585
586                         logger.CheckLoggedMessageHead ("Hello from DefaultDependsOn", "A1");
587                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget1", "A1");
588                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget2", "A1");
589                         logger.CheckLoggedMessageHead ("Hello from Default", "A1");
590                         logger.CheckLoggedMessageHead ("Hello from DefaultAfterTarget", "A1");
591
592                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected messages found");
593
594                         //warnings for referencing unknown targets: NonExistant and Foo
595                         Assert.AreEqual (2, logger.WarningsCount, "Expected warnings not raised");
596                 }
597 #endif
598
599         }
600 }