8f2aa2e7b28daf2b2f4f41ae052bae1b3097e233
[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_UpdateMetadata ()
703                 {
704                         ItemGroupInsideTarget (
705                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
706                                         <ItemGroup>
707                                                 <ProjectReference Include='xyz'/>
708                                         </ItemGroup>
709
710                                         <Target Name='Main' DependsOnTargets='CreateBar'>
711                                                 <Message Text='Before: $(Bar)'/>
712                                                 <ItemGroup>
713                                                         <ProjectReference>
714                                                                 <AdditionalProperties>A=b</AdditionalProperties>
715                                                         </ProjectReference>
716                                                 </ItemGroup>
717                                                 <Message Text='After: $(Bar)'/>
718                                         </Target>
719
720                                         <Target Name='CreateBar'>
721                                                 <PropertyGroup>
722                                                         <Bar>Bar01</Bar>
723                                                 </PropertyGroup>
724                                         </Target>
725                                 </Project>", 2, "Before: Bar01", "After: Bar01");
726                 }
727
728                 [Test]
729                 public void ItemGroupInsideTarget_Batching ()
730                 {
731                         ItemGroupInsideTarget (
732                                 @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
733                                         <Target Name='Main'>
734                                                 <ItemGroup>
735                                                         <Foo Include='A;B' />
736                                                         <All Include='%(Foo.Identity)' />
737                                                 </ItemGroup>
738                                                 <Message Text='%(All.Identity)' />
739                                         </Target>
740                                 </Project>", "A", "B");
741                 }
742
743                 [Test]
744                 public void ItemGroupInsideTarget_Condition ()
745                 {
746                         ItemGroupInsideTarget (
747                                 @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
748                                         <PropertyGroup>
749                                                 <Summer>true</Summer>
750                                         </PropertyGroup>
751                                         <ItemGroup>
752                                                 <Weather Include='Sun;Rain' />
753                                         </ItemGroup>
754                                 
755                                         <Target Name='Main'>
756                                                 <ItemGroup Condition=""'$(Summer)' != 'true'"">
757                                                         <Weather Include='Snow' />
758                                                 </ItemGroup>
759                                                 <Message Text='%(Weather.Identity)' />
760                                         </Target>
761                                 </Project>", "Sun", "Rain");
762                 }
763
764                 [Test]
765                 public void PropertyGroupInsideTarget_Condition ()
766                 {
767                         ItemGroupInsideTarget (
768                                 @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
769                                         <ItemGroup>
770                                                 <Shells Include=""/bin/sh;/bin/bash;/bin/false"" />
771                                         </ItemGroup>
772
773                                         <Target Name='Main'>
774                                                 <PropertyGroup>
775                                                         <HasBash Condition=""'%(Shells.Filename)' == 'bash'"">true</HasBash>
776                                                 </PropertyGroup>
777
778                                                 <ItemGroup Condition=""'$(HasBash)' == 'true'"">
779                                                         <Weather Include='Rain' />
780                                                 </ItemGroup>
781                                                 <Message Text='%(Weather.Identity)' />
782                                         </Target>
783                                 </Project>", "Rain");
784                 }
785
786                 [Test]
787                 // Bug #14661
788                 public void ItemGroupInsideTarget_Expression_in_Metadata ()
789                 {
790                         ItemGroupInsideTarget (
791                         @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
792                                 <ItemGroup>
793                                         <Foo Include='output1'>
794                                                 <Inputs>input1a;input1b</Inputs>
795                                         </Foo>
796                                         <Foo Include='output2'>
797                                                 <Inputs>input2a;input2b</Inputs>
798                                         </Foo>
799                                 </ItemGroup>
800
801                                 <Target Name='Main' DependsOnTargets='_PrepareItems' Inputs='@(_Foo)' Outputs='%(Result)'>
802                                         <Message Text='COMPILE: @(_Foo) - %(_Foo.Result)' />
803                                 </Target>
804
805                                 <Target Name='_PrepareItems'>
806                                         <ItemGroup>
807                                                 <_Foo Include='%(Foo.Inputs)'>
808                                                         <Result>%(Foo.Identity)</Result>
809                                                 </_Foo>
810                                         </ItemGroup>
811                                 </Target>
812                         </Project>",
813                         3, "COMPILE: input1a;input1b - output1", "COMPILE: input2a;input2b - output2");
814                 }
815
816
817                 [Test]
818                 public void TestTargetOutputsIncludingMetadata ()
819                 {
820                         Engine engine;
821                         Project project;
822
823                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
824                         <ItemGroup>
825                                 <fruit Include=""apple""><md>a</md></fruit>
826                                 <fruit Include=""rhubarb""><md>b</md></fruit>
827                                 <fruit Include=""apricot""><md>c</md></fruit>
828                         </ItemGroup>
829
830                         <Target Name=""Main"">
831                                 <CallTarget Targets=""foo"">
832                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
833                                 </CallTarget>
834
835                                 <CallTarget Targets=""foo"">
836                                         <Output TaskParameter=""TargetOutputs"" ItemName=""AllOut""/>
837                                 </CallTarget>
838                                 <Message Text=""AllOut: @(AllOut) metadata: %(AllOut.md)""/>
839                         </Target>
840
841                         <Target Name=""foo"" Outputs=""@(FooItem)"">
842                                 <Message Text=""foo called""/>
843                                 <CreateItem Include=""@(fruit)"">
844                                         <Output TaskParameter=""Include"" ItemName=""FooItem""/>
845                                 </CreateItem>
846                                 <Message Text=""FooItem: @(FooItem) metadata: %(FooItem.md)""/>
847                         </Target>
848                 </Project>";
849
850                         engine = new Engine (Consts.BinPath);
851                         project = engine.CreateNewProject ();
852                         project.LoadXml (documentString);
853
854                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
855                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
856                         engine.RegisterLogger (logger);
857
858                         bool result = project.Build ("Main");
859                         if (!result) {
860                                 logger.DumpMessages ();
861                                 Assert.Fail ("Build failed");
862                         }
863
864                         try {
865                                 logger.CheckLoggedMessageHead ("foo called", "A1");
866                                 logger.CheckLoggedMessageHead ("FooItem: apple metadata: a", "A2");
867                                 logger.CheckLoggedMessageHead ("FooItem: rhubarb metadata: b", "A3");
868                                 logger.CheckLoggedMessageHead ("FooItem: apricot metadata: c", "A4");
869
870                                 logger.CheckLoggedMessageHead ("AllOut: apple;apple metadata: a", "A5");
871                                 logger.CheckLoggedMessageHead ("AllOut: rhubarb;rhubarb metadata: b", "A6");
872                                 logger.CheckLoggedMessageHead ("AllOut: apricot;apricot metadata: c", "A7");
873
874                                 Assert.AreEqual (0, logger.NormalMessageCount, "Extra messages found");
875
876                                 Assert.AreEqual (2, logger.TargetStarted, "TargetStarted count");
877                                 Assert.AreEqual (2, logger.TargetFinished, "TargetFinished count");
878                                 Assert.AreEqual (10, logger.TaskStarted, "TaskStarted count");
879                                 Assert.AreEqual (10, logger.TaskFinished, "TaskFinished count");
880
881                         } catch (AssertionException) {
882                                 logger.DumpMessages ();
883                                 throw;
884                         }
885                 }
886
887                 [Test]
888                 public void TestOverridingTargets ()
889                 {
890                         Engine engine;
891                         Project project;
892
893                         string second = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
894                                 <Target Name='BeforeBuild'/>
895                                 <Target Name='AfterBuild'/>
896                                 <Target Name='Build' DependsOnTargets='BeforeBuild'>
897                                         <Message Text='Build executing'/>
898                                         <CallTarget Targets='AfterBuild'/>
899                                 </Target>
900                 </Project>";
901                         using (StreamWriter sw = new StreamWriter (Path.Combine ("Test", Path.Combine ("resources", "second.proj")))) {
902                                 sw.Write (second);
903                         }
904
905                         string documentString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
906                                 <Target Name='AfterBuild'>
907                                         <Message Text='Overriding AfterBuild'/>
908                                 </Target>
909
910                                 <Import Project='Test/resources/second.proj'/>
911                                 <Target Name='BeforeBuild'>
912                                         <Message Text='Overriding BeforeBuild'/>
913                                 </Target>
914                 </Project>";
915
916                         engine = new Engine (Consts.BinPath);
917                         project = engine.CreateNewProject ();
918                         project.LoadXml (documentString);
919
920                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
921                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
922                         engine.RegisterLogger (logger);
923
924                         bool result = project.Build ("Build");
925                         if (!result) {
926                                 logger.DumpMessages ();
927                                 Assert.Fail ("Build failed");
928                         }
929
930                         logger.CheckLoggedMessageHead ("Overriding BeforeBuild", "A1");
931                         logger.CheckLoggedMessageHead ("Build executing", "A1");
932
933                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected extra messages found");
934                 }
935
936                 [Test]
937                 [Category ("NotDotNet")]
938                 public void TestBeforeAndAfterTargets ()
939                 {
940                         Engine engine;
941                         Project project;
942
943                         string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
944                           <Target Name=""DefaultBeforeTarget1"" BeforeTargets=""Default"">
945                             <Message Text=""Hello from DefaultBeforeTarget1""/>
946                           </Target>
947
948                           <Target Name=""DefaultBeforeTarget2"" BeforeTargets=""Default;Default;NonExistant"">
949                             <Message Text=""Hello from DefaultBeforeTarget2""/>
950                           </Target>
951
952
953                           <Target Name=""DefaultAfterTarget"" AfterTargets=""Default  ; Foo"">
954                             <Message Text=""Hello from DefaultAfterTarget""/>
955                           </Target>
956
957                           <Target Name=""Default"" DependsOnTargets=""DefaultDependsOn"">
958                             <Message Text=""Hello from Default""/>
959                           </Target>
960
961                           <Target Name=""DefaultDependsOn"">
962                             <Message Text=""Hello from DefaultDependsOn""/>
963                           </Target>
964                         </Project>";
965
966                         engine = new Engine ();
967                         project = engine.CreateNewProject ();
968                         project.LoadXml (projectString);
969
970                         MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
971                                 new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
972                         engine.RegisterLogger (logger);
973
974                         if (!project.Build ("Default")) {
975                                 logger.DumpMessages ();
976                                 Assert.Fail ("Build failed");
977                         }
978
979                         logger.CheckLoggedMessageHead ("Hello from DefaultDependsOn", "A1");
980                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget1", "A1");
981                         logger.CheckLoggedMessageHead ("Hello from DefaultBeforeTarget2", "A1");
982                         logger.CheckLoggedMessageHead ("Hello from Default", "A1");
983                         logger.CheckLoggedMessageHead ("Hello from DefaultAfterTarget", "A1");
984
985                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected messages found");
986
987                         //warnings for referencing unknown targets: NonExistant and Foo
988                         Assert.AreEqual (2, logger.WarningsCount, "Expected warnings not raised");
989                 }
990
991                 [Test]
992                 public void TestTargetReturns ()
993                 {
994                         engine = new Engine (Consts.BinPath);
995                         project = engine.CreateNewProject ();
996                         project.Load (Path.Combine ("Test", Path.Combine ("resources", "TestReturns.csproj")));
997
998                         var logger = new TestMessageLogger ();
999                         engine.RegisterLogger (logger);
1000
1001                         bool result = project.Build ("Main");
1002                         if (!result) {
1003                                 logger.DumpMessages ();
1004                                 Assert.Fail ("Build failed");
1005                         }
1006
1007                         logger.CheckLoggedMessageHead ("Result: Bar", "A1");
1008
1009                         Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected extra messages found");
1010                 }
1011
1012         }
1013 }