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