Merge pull request #600 from tr8dr/master
[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 using System;
30 using System.Collections;
31 using Microsoft.Build.BuildEngine;
32 using Microsoft.Build.Framework;
33 using Microsoft.Build.Utilities;
34 using MonoTests.Microsoft.Build.Tasks;
35 using NUnit.Framework;
36 using System.IO;
37 using System.Xml;
38
39 namespace MonoTests.Microsoft.Build.BuildEngine {
40         [TestFixture]
41         public class TargetTest {
42                 
43                 Engine                  engine;
44                 Project                 project;
45                 
46                 [Test]
47                 public void TestFromXml1 ()
48                 {
49                         string documentString = @"
50                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
51                                         <Target Name='Target'>
52                                         </Target>
53                                 </Project>
54                         ";
55
56                         engine = new Engine (Consts.BinPath);
57
58                         project = engine.CreateNewProject ();
59                         project.LoadXml (documentString);
60
61                         Target[] t = new Target [1];
62                         project.Targets.CopyTo (t, 0);
63
64                         Assert.AreEqual (String.Empty, t [0].Condition, "A1");
65                         Assert.AreEqual (String.Empty, t [0].DependsOnTargets, "A2");
66                         Assert.IsFalse (t [0].IsImported, "A3");
67                         Assert.AreEqual ("Target", t [0].Name, "A4");
68                 }
69
70                 [Test]
71                 public void TestFromXml2 ()
72                 {
73                         string documentString = @"
74                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
75                                         <Target Name='Target' Condition='false' DependsOnTargets='X' >
76                                         </Target>
77                                 </Project>
78                         ";
79
80                         engine = new Engine (Consts.BinPath);
81
82                         project = engine.CreateNewProject ();
83                         project.LoadXml (documentString);
84
85                         Target[] t = new Target [1];
86                         project.Targets.CopyTo (t, 0);
87
88                         Assert.AreEqual ("false", t [0].Condition, "A1");
89                         Assert.AreEqual ("X", t [0].DependsOnTargets, "A2");
90
91                         t [0].Condition = "true";
92                         t [0].DependsOnTargets = "A;B";
93
94                         Assert.AreEqual ("true", t [0].Condition, "A3");
95                         Assert.AreEqual ("A;B", t [0].DependsOnTargets, "A4");
96                 }
97
98                 [Test]
99                 public void TestAddNewTask1 ()
100                 {
101                         string documentString = @"
102                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
103                                         <Target Name='Target' >
104                                         </Target>
105                                 </Project>
106                         ";
107
108                         engine = new Engine (Consts.BinPath);
109
110                         project = engine.CreateNewProject ();
111                         project.LoadXml (documentString);
112
113                         Target[] t = new Target [1];
114                         project.Targets.CopyTo (t, 0);
115
116                         BuildTask bt = t [0].AddNewTask ("Message");
117
118                         Assert.AreEqual ("Message", bt.Name, "A1");
119                 }
120
121                 [Test]
122                 [ExpectedException (typeof (ArgumentNullException))]
123                 public void TestAddNewTask2 ()
124                 {
125                         string documentString = @"
126                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
127                                         <Target Name='Target' >
128                                         </Target>
129                                 </Project>
130                         ";
131
132                         engine = new Engine (Consts.BinPath);
133
134                         project = engine.CreateNewProject ();
135                         project.LoadXml (documentString);
136
137                         Target[] t = new Target [1];
138                         project.Targets.CopyTo (t, 0);
139
140                         t [0].AddNewTask (null);
141                 }
142
143                 [Test]
144                 public void TestGetEnumerator ()
145                 {
146                         string documentString = @"
147                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
148                                         <Target Name='Target' >
149                                                 <Message Text='text' />
150                                                 <Warning Text='text' />
151                                         </Target>
152                                 </Project>
153                         ";
154
155                         engine = new Engine (Consts.BinPath);
156
157                         project = engine.CreateNewProject ();
158                         project.LoadXml (documentString);
159
160                         Target[] t = new Target [1];
161                         project.Targets.CopyTo (t, 0);
162
163                         IEnumerator e = t [0].GetEnumerator ();
164                         e.MoveNext ();
165                         Assert.AreEqual ("Message", ((BuildTask) e.Current).Name, "A1");
166                         e.MoveNext ();
167                         Assert.AreEqual ("Warning", ((BuildTask) e.Current).Name, "A2");
168                         Assert.IsFalse (e.MoveNext (), "A3");
169                 }
170
171                 [Test]
172                 public void TestOutOfRangeElementsOfTheEnumerator()
173                 {
174                         string documentString =
175                                 @"
176                                 <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
177                                         <Target Name='A'>
178                                                 <Message Text='text' />
179                                         </Target>
180                                 </Project>";
181
182                         engine = new Engine (Consts.BinPath);
183
184                         project = engine.CreateNewProject ();
185                         project.LoadXml (documentString);
186
187                         Assert.IsFalse (project.Targets == null, "A1");
188                         Assert.AreEqual (1, project.Targets.Count, "A2");
189
190                         Target target = project.Targets ["A"];
191                         Assert.IsFalse (target == null, "A3");
192
193                         IEnumerator e = target.GetEnumerator ();
194
195                         bool thrown = false;
196                         try {
197                                 var name = ((BuildTask)e.Current).Name;
198                         } catch (InvalidOperationException) { // "Enumeration has not started. Call MoveNext"
199                                 thrown = true;
200                         }
201                         if (!thrown)
202                                 Assert.Fail ("A4: Should have thrown IOE");
203
204
205                         Assert.AreEqual (true, e.MoveNext (), "A5");
206                         Assert.AreEqual ("Message", ((BuildTask)e.Current).Name, "A6");
207                         Assert.AreEqual (false, e.MoveNext (), "A7");
208                         try {
209                                 var name = ((BuildTask) e.Current).Name;
210                         } catch (InvalidOperationException) { //"Enumeration already finished."
211                                 return;
212                         }
213                         Assert.Fail ("A8: Should have thrown IOE, because there's only one buidTask");
214                 }
215
216                 [Test]
217                 [ExpectedException (typeof (InvalidProjectFileException))]
218                 public void TestOnError1 ()
219                 {
220                         Engine engine;
221                         Project project;
222
223                         string documentString = @"
224                                 <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
225                                         <Target Name='A'>
226                                                 <OnError ExecuteTargets='B' />
227                                                 <Error Text='text' />
228                                         </Target>
229                                 </Project>
230                         ";
231
232                         engine = new Engine (Consts.BinPath);
233                         project = engine.CreateNewProject ();
234                         project.LoadXml (documentString);
235                 }
236
237                 [Test]
238                 public void TestRemoveTask1 ()
239                 {
240                         string documentString = @"
241                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
242                                         <Target Name='Target' >
243                                                 <Message Text='text' />
244                                                 <Warning Text='text' />
245                                         </Target>
246                                 </Project>
247                         ";
248
249                         engine = new Engine (Consts.BinPath);
250
251                         project = engine.CreateNewProject ();
252                         project.LoadXml (documentString);
253
254                         Target[] t = new Target [1];
255                         project.Targets.CopyTo (t, 0);
256
257                         IEnumerator e = t [0].GetEnumerator ();
258                         e.MoveNext ();
259                         t [0].RemoveTask ((BuildTask) e.Current);
260                         e = t [0].GetEnumerator ();
261                         e.MoveNext ();
262                         Assert.AreEqual ("Warning", ((BuildTask) e.Current).Name, "A1");
263                         Assert.IsFalse (e.MoveNext (), "A2");
264                 }
265
266                 [Test]
267                 [ExpectedException (typeof (ArgumentNullException))]
268                 public void TestRemoveTask2 ()
269                 {
270                         string documentString = @"
271                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
272                                         <Target Name='Target' >
273                                         </Target>
274                                 </Project>
275                         ";
276
277                         engine = new Engine (Consts.BinPath);
278
279                         project = engine.CreateNewProject ();
280                         project.LoadXml (documentString);
281
282                         Target[] t = new Target [1];
283                         project.Targets.CopyTo (t, 0);
284                         t [0].RemoveTask (null);
285                 }
286
287                 [Test]
288                 public void TestTargetOutputs1 ()
289                 {
290                         Engine engine;
291                         Project project;
292
293                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
294                         <ItemGroup>
295                                 <fruit Include=""apple""/>
296                                 <fruit Include=""rhubarb""/>
297                                 <fruit Include=""apricot""/>
298                         </ItemGroup>
299
300                         <Target Name=""Main"">
301                                 <CallTarget Targets=""foo"">
302                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
303                                 </CallTarget>
304
305                                 <CallTarget Targets=""foo"">
306                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
307                                 </CallTarget>
308                                 <Message Text=""AllOut: @(AllOut)""/>
309                         </Target>
310
311                         <Target Name=""foo"" Outputs=""@(FooItem)"">
312                                 <Message Text=""foo called""/>
313                                 <CreateItem Include=""%(fruit.Identity)"">
314                                         <Output TaskParameter=""Include"" ItemName=""FooItem""/>
315                                 </CreateItem>
316                                 <Message Text=""FooItem: @(FooItem)""/>
317                         </Target>
318                 </Project>";
319
320                         engine = new Engine (Consts.BinPath);
321                         project = engine.CreateNewProject ();
322                         project.LoadXml (documentString);
323
324                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
325                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
326                         engine.RegisterLogger (logger);
327
328                         bool result = project.Build ("Main");
329                         if (!result) {
330                                 logger.DumpMessages ();
331                                 Assert.Fail ("Build failed");
332                         }
333
334                         try {
335                                 Assert.AreEqual (3, logger.NormalMessageCount, "Expected number of messages");
336                                 logger.CheckLoggedMessageHead ("foo called", "A1");
337                                 logger.CheckLoggedMessageHead ("FooItem: apple;rhubarb;apricot", "A2");
338                                 logger.CheckLoggedMessageHead ("AllOut: apple;rhubarb;apricot;apple;rhubarb;apricot", "A3");
339                                 Assert.AreEqual (0, logger.NormalMessageCount, "Extra messages found");
340
341                                 Assert.AreEqual (2, logger.TargetStarted, "TargetStarted count");
342                                 Assert.AreEqual (2, logger.TargetFinished, "TargetFinished count");
343                                 Assert.AreEqual (8, logger.TaskStarted, "TaskStarted count");
344                                 Assert.AreEqual (8, logger.TaskFinished, "TaskFinished count");
345
346                         } catch (AssertionException) {
347                                 logger.DumpMessages ();
348                                 throw;
349                         }
350                 }
351
352 #if NET_3_5
353                 bool Build (string projectXml, ILogger logger)
354                 {
355                         if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
356                                 var reader = new StringReader (projectXml);
357                                 var xml = XmlReader.Create (reader);
358                                 return BuildOnWindows (xml, logger);
359                         } else {
360                                 return BuildOnLinux (projectXml, logger);
361                         }
362                 }
363
364                 bool BuildOnWindows (XmlReader reader, ILogger logger)
365                 {
366                         var type = Type.GetType ("Microsoft.Build.Evaluation.ProjectCollection, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
367
368                         var prop = type.GetProperty ("GlobalProjectCollection");
369                         var coll = prop.GetValue (null);
370                                 
371                         var loadProject = coll.GetType ().GetMethod (
372                                         "LoadProject", new Type[] { typeof (XmlReader), typeof (string) });
373                         var proj = loadProject.Invoke (coll, new object[] { reader, "4.0" });
374                                 
375                         var build = proj.GetType ().GetMethod ("Build", new Type[] { typeof (string), typeof (ILogger[]) });
376                         var ret = (bool)build.Invoke (proj, new object[] { "Main", new ILogger[] { logger }});
377                         return ret;
378                 }
379
380                 bool BuildOnLinux (string projectXml, ILogger logger)
381                 {
382                         var engine = new Engine (Consts.BinPath);
383                         var project = engine.CreateNewProject ();
384                         project.LoadXml (projectXml);
385                         
386                         engine.RegisterLogger (logger);
387                         
388                         return project.Build ("Main");
389                 }
390
391                 TestMessageLogger CreateLogger (string projectXml)
392                 {
393                         var logger = new TestMessageLogger ();
394                         var result = Build (projectXml, logger);
395
396                         if (!result) {
397                                 logger.DumpMessages ();
398                                 Assert.Fail ("Build failed");
399                         }
400
401                         return logger;
402                 }
403
404                 void ItemGroupInsideTarget (string xml, params string[] messages)
405                 {
406                         var logger = CreateLogger (xml);
407                         
408                         try
409                         {
410                                 Assert.AreEqual(messages.Length, logger.NormalMessageCount, "Expected number of messages");
411                                 for (int i = 0; i < messages.Length; i++)
412                                         logger.CheckLoggedMessageHead (messages [i], i.ToString ());
413                                 Assert.AreEqual(0, logger.NormalMessageCount, "Extra messages found");
414                                 
415                                 Assert.AreEqual(1, logger.TargetStarted, "TargetStarted count");
416                                 Assert.AreEqual(1, logger.TargetFinished, "TargetFinished count");
417                                 Assert.AreEqual(messages.Length, logger.TaskStarted, "TaskStarted count");
418                                 Assert.AreEqual(messages.Length, logger.TaskFinished, "TaskFinished count");
419                         }
420                         catch (AssertionException)
421                         {
422                                 logger.DumpMessages();
423                                 throw;
424                         }
425                 }
426
427                 [Test]
428                 public void BuildProjectWithItemGroupInsideTarget ()
429                 {
430                         ItemGroupInsideTarget (
431                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
432                                         <ItemGroup>
433                                         <fruit Include=""apple""/>
434                                                 <fruit Include=""apricot""/>
435                                         </ItemGroup>
436
437                                         <Target Name=""Main"">
438                                                 <ItemGroup>
439                                                         <fruit Include=""raspberry"" />
440                                                 </ItemGroup>
441                                                 <Message Text=""%(fruit.Identity)""/>
442                                         </Target>
443                                 </Project>", "apple", "apricot", "raspberry");
444                 }
445                 
446                 [Test]
447                 public void BuildProjectWithItemGroupInsideTarget2 ()
448                 {
449                         ItemGroupInsideTarget (
450                                 @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
451                                         <ItemGroup>
452                                                 <A Include='1'>
453                                                         <Sub>Foo</Sub>
454                                                 </A>
455                                         </ItemGroup>
456                                         <PropertyGroup>
457                                                 <Foo>Bar</Foo>
458                                         </PropertyGroup>
459
460                                         <Target Name='Main'>
461                                                 <ItemGroup>
462                                                         <A Include='2'>
463                                                                 <Sub>$(Foo);Hello</Sub>
464                                                         </A>
465                                                 </ItemGroup>
466                                 
467                                                 <Message Text='@(A)' />
468                                                 <Message Text='%(A.Sub)' />
469                                         </Target>
470                                 </Project>", "1;2", "Foo", "Bar;Hello");
471                 }
472                 
473                 [Test]
474                 public void BuildProjectWithPropertyGroupInsideTarget ()
475                 {
476                         ItemGroupInsideTarget (
477                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
478                                         <PropertyGroup>
479                                                 <A>Foo</A>
480                                                 <B>Bar</B>
481                                         </PropertyGroup>
482
483                                         <Target Name=""Main"">
484                                                 <Message Text='$(A)' />
485                                                 <PropertyGroup>
486                                                         <A>$(B)</A>
487                                                 </PropertyGroup>
488                                                 <Message Text='$(A)' />
489                                         </Target>
490                                 </Project>", "Foo", "Bar");
491                 }
492
493                 [Test]
494                 public void BuildProjectWithPropertyGroupInsideTarget2 ()
495                 {
496                         ItemGroupInsideTarget (
497                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
498                                         <PropertyGroup>
499                                                 <A>Foo</A>
500                                                 <B>Bar</B>
501                                         </PropertyGroup>
502
503                                         <Target Name=""Main"">
504                                                 <Message Text='$(A)' />
505                                                 <PropertyGroup Condition='true'>
506                                                         <B Condition='false'>False</B>
507                                                 </PropertyGroup>
508                                                 <PropertyGroup Condition='true'>
509                                                         <A>$(B)</A>
510                                                 </PropertyGroup>
511                                                 <Message Text='$(A)' />
512                                                 <Message Text='$(B)' />
513                                                 <PropertyGroup>
514                                                         <A Condition='$(A) == $(B)'>Equal</A>
515                                                 </PropertyGroup>
516                                                 <Message Text='$(A)' />
517                                         </Target>
518                                 </Project>", "Foo", "Bar", "Bar", "Equal");
519                 }
520
521                 [Test]
522                 public void ItemGroupInsideTarget_ModifyMetadata ()
523                 {
524                         ItemGroupInsideTarget (
525                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
526                                         <ItemGroup>
527                                                 <Server Include='Server1'>
528                                                         <AdminContact>Mono</AdminContact>
529                                                 </Server>
530                                                 <Server Include='Server2'>
531                                                         <AdminContact>Mono</AdminContact>
532                                                 </Server>
533                                                 <Server Include='Server3'>
534                                                         <AdminContact>Root</AdminContact>
535                                                 </Server>
536                                         </ItemGroup>
537
538                                         <Target Name='Main'>
539                                                 <ItemGroup>
540                                                         <Server Condition=""'%(Server.AdminContact)' == 'Mono'"">
541                                                                 <AdminContact>Monkey</AdminContact>
542                                                         </Server>
543                                                 </ItemGroup>
544                                         
545                                                 <Message Text='%(Server.Identity) : %(Server.AdminContact)' />
546                                                 </Target>
547                                         </Project>", "Server1 : Monkey", "Server2 : Monkey", "Server3 : Root");
548                 }
549
550                 [Test]
551                 public void ItemGroupInsideTarget_RemoveItem ()
552                 {
553                         ItemGroupInsideTarget (
554                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
555                                         <ItemGroup>
556                                                 <Foo Include='A;B;C;D' />
557                                         </ItemGroup>
558
559                                         <Target Name='Main'>
560                                                 <ItemGroup>
561                                                         <Foo Remove='B' />
562                                                 </ItemGroup>
563
564                                                 <Message Text='@(Foo)' />
565                                         </Target>
566                                 </Project>", "A;C;D");
567                 }
568
569                 [Test]
570                 public void ItemGroupInsideTarget_DontKeepDuplicates ()
571                 {
572                         ItemGroupInsideTarget (
573                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
574                                         <ItemGroup>
575                                                 <Foo Include='A;B' />
576                                                 <Foo Include='C'>
577                                                         <Hello>World</Hello>
578                                                 </Foo>
579                                                 <Foo Include='D'>
580                                                         <Hello>Boston</Hello>
581                                                 </Foo>
582                                         </ItemGroup>
583
584                                         <Target Name='Main'>
585                                                 <ItemGroup>
586                                                         <Foo Include='B;C;D' KeepDuplicates='false'>
587                                                                 <Hello>Boston</Hello>
588                                                         </Foo>
589                                                 </ItemGroup>
590                                 
591                                                 <Message Text='@(Foo)' />
592                                         </Target>
593                                 </Project>", "A;B;C;D;B;C");
594                 }
595
596                 [Test]
597                 public void ItemGroupInsideTarget_RemoveMetadata ()
598                 {
599                         ItemGroupInsideTarget (
600                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
601                                         <ItemGroup>
602                                                 <Foo Include='A' />
603                                                 <Foo Include='B'>
604                                                         <Hello>World</Hello>
605                                                 </Foo>
606                                                 <Foo Include='C'>
607                                                         <Hello>Boston</Hello>
608                                                 </Foo>
609                                                 <Foo Include='D'>
610                                                         <Test>Monkey</Test>
611                                                 </Foo>
612                                         </ItemGroup>
613                                         <PropertyGroup>
614                                                 <Foo>Hello</Foo>
615                                         </PropertyGroup>
616
617                                         <Target Name='Main'>
618                                                 <ItemGroup>
619                                                         <Bar Include='@(Foo)' RemoveMetadata='$(Foo)' />
620                                                         <Bar Include='E'>
621                                                                 <Hello>Monkey</Hello>
622                                                         </Bar>
623                                                 </ItemGroup>
624                                 
625                                                 <Message Text='%(Bar.Identity)' Condition=""'%(Bar.Hello)' != ''""/>
626                                         </Target>
627                                 </Project>", "E");
628                 }
629
630                 [Test]
631                 public void ItemGroupInsideTarget_RemoveMetadata2 ()
632                 {
633                         ItemGroupInsideTarget (
634                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
635                                         <ItemGroup>
636                                                 <Foo Include='A' />
637                                                 <Foo Include='B'>
638                                                         <Hello>World</Hello>
639                                                 </Foo>
640                                                 <Foo Include='C'>
641                                                         <Hello>Boston</Hello>
642                                                 </Foo>
643                                                 <Foo Include='D'>
644                                                         <Test>Monkey</Test>
645                                                 </Foo>
646                                         </ItemGroup>
647                                         <PropertyGroup>
648                                         <Foo>Hello</Foo>
649                                         </PropertyGroup>
650
651                                         <Target Name='Main'>
652                                                 <ItemGroup>
653                                                         <Foo RemoveMetadata='$(Foo)' />
654                                                         <Foo Include='E'>
655                                                                 <Hello>Monkey</Hello>
656                                                         </Foo>
657                                                 </ItemGroup>
658                                 
659                                         <Message Text='%(Foo.Identity)' Condition=""'%(Foo.Hello)' != ''""/>
660                                         </Target>
661                                 </Project>", "E");
662                 }
663
664                 [Test]
665                 public void ItemGroupInsideTarget_KeepMetadata ()
666                 {
667                         ItemGroupInsideTarget (
668                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
669                                         <ItemGroup>
670                                                 <Foo Include='A' />
671                                                 <Foo Include='B'>
672                                                         <Hello>World</Hello>
673                                                 </Foo>
674                                                 <Foo Include='C'>
675                                                         <Hello>Boston</Hello>
676                                                 </Foo>
677                                                 <Foo Include='D'>
678                                                         <Test>Monkey</Test>
679                                                 </Foo>
680                                         </ItemGroup>
681
682                                         <Target Name='Main'>
683                                                 <ItemGroup>
684                                                         <Foo KeepMetadata='Test' />
685                                                         <Foo Include='E'>
686                                                                 <Hello>Monkey</Hello>
687                                                         </Foo>
688                                                 </ItemGroup>
689                                 
690                                                 <Message Text='%(Foo.Identity)' Condition=""'%(Foo.Test)' != ''""/>
691                                         </Target>
692                                 </Project>", "D");
693                 }
694
695                 [Test]
696                 public void ItemGroupInsideTarget_Batching ()
697                 {
698                         ItemGroupInsideTarget (
699                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
700                                         <Target Name='Main'>
701                                                 <ItemGroup>
702                                                         <Foo Include='A;B' />
703                                                         <All Include='%(Foo.Identity)' />
704                                                 </ItemGroup>
705                                                 <Message Text='%(All.Identity)' />
706                                         </Target>
707                                 </Project>", "A", "B");
708                 }
709
710                 [Test]
711                 public void ItemGroupInsideTarget_Condition ()
712                 {
713                         ItemGroupInsideTarget (
714                                 @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
715                                         <PropertyGroup>
716                                                 <Summer>true</Summer>
717                                         </PropertyGroup>
718                                         <ItemGroup>
719                                                 <Weather Include='Sun;Rain' />
720                                         </ItemGroup>
721                                 
722                                         <Target Name='Main'>
723                                                 <ItemGroup Condition=""'$(Summer)' != 'true'"">
724                                                         <Weather Include='Snow' />
725                                                 </ItemGroup>
726                                                 <Message Text='%(Weather.Identity)' />
727                                         </Target>
728                                 </Project>", "Sun", "Rain");
729                 }
730                 #endif
731
732                 [Test]
733                 public void TestTargetOutputsIncludingMetadata ()
734                 {
735                         Engine engine;
736                         Project project;
737
738                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
739                         <ItemGroup>
740                                 <fruit Include=""apple""><md>a</md></fruit>
741                                 <fruit Include=""rhubarb""><md>b</md></fruit>
742                                 <fruit Include=""apricot""><md>c</md></fruit>
743                         </ItemGroup>
744
745                         <Target Name=""Main"">
746                                 <CallTarget Targets=""foo"">
747                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
748                                 </CallTarget>
749
750                                 <CallTarget Targets=""foo"">
751                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
752                                 </CallTarget>
753                                 <Message Text=""AllOut: @(AllOut) metadata: %(AllOut.md)""/>
754                         </Target>
755
756                         <Target Name=""foo"" Outputs=""@(FooItem)"">
757                                 <Message Text=""foo called""/>
758                                 <CreateItem Include=""@(fruit)"">
759                                         <Output TaskParameter=""Include"" ItemName=""FooItem""/>
760                                 </CreateItem>
761                                 <Message Text=""FooItem: @(FooItem) metadata: %(FooItem.md)""/>
762                         </Target>
763                 </Project>";
764
765                         engine = new Engine (Consts.BinPath);
766                         project = engine.CreateNewProject ();
767                         project.LoadXml (documentString);
768
769                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
770                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
771                         engine.RegisterLogger (logger);
772
773                         bool result = project.Build ("Main");
774                         if (!result) {
775                                 logger.DumpMessages ();
776                                 Assert.Fail ("Build failed");
777                         }
778
779                         try {
780                                 logger.CheckLoggedMessageHead ("foo called", "A1");
781                                 logger.CheckLoggedMessageHead ("FooItem: apple metadata: a", "A2");
782                                 logger.CheckLoggedMessageHead ("FooItem: rhubarb metadata: b", "A3");
783                                 logger.CheckLoggedMessageHead ("FooItem: apricot metadata: c", "A4");
784
785                                 logger.CheckLoggedMessageHead ("AllOut: apple;apple metadata: a", "A5");
786                                 logger.CheckLoggedMessageHead ("AllOut: rhubarb;rhubarb metadata: b", "A6");
787                                 logger.CheckLoggedMessageHead ("AllOut: apricot;apricot metadata: c", "A7");
788
789                                 Assert.AreEqual (0, logger.NormalMessageCount, "Extra messages found");
790
791                                 Assert.AreEqual (2, logger.TargetStarted, "TargetStarted count");
792                                 Assert.AreEqual (2, logger.TargetFinished, "TargetFinished count");
793                                 Assert.AreEqual (10, logger.TaskStarted, "TaskStarted count");
794                                 Assert.AreEqual (10, logger.TaskFinished, "TaskFinished count");
795
796                         } catch (AssertionException) {
797                                 logger.DumpMessages ();
798                                 throw;
799                         }
800                 }
801
802                 [Test]
803                 public void TestOverridingTargets ()
804                 {
805                         Engine engine;
806                         Project project;
807
808                         string second = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
809                                 <Target Name='BeforeBuild'/>
810                                 <Target Name='AfterBuild'/>
811                                 <Target Name='Build' DependsOnTargets='BeforeBuild'>
812                                         <Message Text='Build executing'/>
813                                         <CallTarget Targets='AfterBuild'/>
814                                 </Target>
815                 </Project>";
816                         using (StreamWriter sw = new StreamWriter (Path.Combine ("Test", Path.Combine ("resources", "second.proj")))) {
817                                 sw.Write (second);
818                         }
819
820                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
821                                 <Target Name='AfterBuild'>
822                                         <Message Text='Overriding AfterBuild'/>
823                                 </Target>
824
825                                 <Import Project='Test/resources/second.proj'/>
826                                 <Target Name='BeforeBuild'>
827                                         <Message Text='Overriding BeforeBuild'/>
828                                 </Target>
829                 </Project>";
830
831                         engine = new Engine (Consts.BinPath);
832                         project = engine.CreateNewProject ();
833                         project.LoadXml (documentString);
834
835                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
836                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
837                         engine.RegisterLogger (logger);
838
839                         bool result = project.Build ("Build");
840                         if (!result) {
841                                 logger.DumpMessages ();
842                                 Assert.Fail ("Build failed");
843                         }
844
845                         logger.CheckLoggedMessageHead ("Overriding BeforeBuild", "A1");
846                         logger.CheckLoggedMessageHead ("Build executing", "A1");
847
848                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected extra messages found");
849                 }
850
851 #if NET_4_0
852                 [Test]
853                 [Category ("NotDotNet")]
854                 public void TestBeforeAndAfterTargets ()
855                 {
856                         Engine engine;
857                         Project project;
858
859                         string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
860                           <Target Name=""DefaultBeforeTarget1"" BeforeTargets=""Default"">
861                             <Message Text=""Hello from DefaultBeforeTarget1""/>
862                           </Target>
863
864                           <Target Name=""DefaultBeforeTarget2"" BeforeTargets=""Default;Default;NonExistant"">
865                             <Message Text=""Hello from DefaultBeforeTarget2""/>
866                           </Target>
867
868
869                           <Target Name=""DefaultAfterTarget"" AfterTargets=""Default  ; Foo"">
870                             <Message Text=""Hello from DefaultAfterTarget""/>
871                           </Target>
872
873                           <Target Name=""Default"" DependsOnTargets=""DefaultDependsOn"">
874                             <Message Text=""Hello from Default""/>
875                           </Target>
876
877                           <Target Name=""DefaultDependsOn"">
878                             <Message Text=""Hello from DefaultDependsOn""/>
879                           </Target>
880                         </Project>";
881
882                         engine = new Engine ();
883                         project = engine.CreateNewProject ();
884                         project.LoadXml (projectString);
885
886                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
887                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
888                         engine.RegisterLogger (logger);
889
890                         if (!project.Build ("Default")) {
891                                 logger.DumpMessages ();
892                                 Assert.Fail ("Build failed");
893                         }
894
895                         logger.CheckLoggedMessageHead ("Hello from DefaultDependsOn", "A1");
896                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget1", "A1");
897                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget2", "A1");
898                         logger.CheckLoggedMessageHead ("Hello from Default", "A1");
899                         logger.CheckLoggedMessageHead ("Hello from DefaultAfterTarget", "A1");
900
901                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected messages found");
902
903                         //warnings for referencing unknown targets: NonExistant and Foo
904                         Assert.AreEqual (2, logger.WarningsCount, "Expected warnings not raised");
905                 }
906 #endif
907
908         }
909 }