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