5 // Ankit Jain (jankit@novell.com)
7 // Copyright 2008 Novell, Inc (http://www.novell.com)
8 // Copyright 2009 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
32 using NUnit.Framework;
33 using Microsoft.Build.BuildEngine;
34 using Microsoft.Build.Framework;
35 using Microsoft.Build.Tasks;
36 using Microsoft.Build.Utilities;
38 namespace MonoTests.Microsoft.Build.Tasks
41 public class TaskBatchingTest
44 public TaskBatchingTest ()
46 projectHeader = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" " + Consts.ToolsVersionString + ">";
52 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
54 <ResXFile Include=""Item1"">
57 <ResXFile Include=""Item2"">
60 <ResXFile Include=""Item3"">
63 <ResXFile Include=""Item4"">
66 <ResXFile Include=""Item5"">
69 <ResXFile Include=""Item6"">
74 <Target Name=""ShowMessage"">
76 Text = ""Culture: %(ResXFile.Culture) -- ResXFile: @(ResXFile)"" />
80 Engine engine = new Engine (Consts.BinPath);
81 Project project = engine.CreateNewProject ();
83 TestMessageLogger testLogger = new TestMessageLogger ();
84 engine.RegisterLogger (testLogger);
86 project.LoadXml (projectString);
87 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
89 CheckMessage (testLogger, "fr", "Item1;Item2;Item5", "A2");
90 CheckMessage (testLogger, "en", "Item3", "A3");
91 CheckMessage (testLogger, "gb", "Item4", "A4");
92 CheckMessage (testLogger, "it", "Item6", "A5");
94 CheckEngineEventCounts (testLogger, 1, 1, 4, 4);
97 // Test1 with unqualified %(Culture)
101 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
103 <ResXFile Include=""Item1"">
104 <Culture>fr</Culture>
106 <ResXFile Include=""Item2"">
107 <Culture>fr</Culture>
109 <ResXFile Include=""Item3"">
110 <Culture>en</Culture>
112 <ResXFile Include=""Item4"">
113 <Culture>gb</Culture>
115 <ResXFile Include=""Item5"">
116 <Culture>fr</Culture>
118 <ResXFile Include=""Item6"">
119 <Culture>it</Culture>
123 <Target Name=""ShowMessage"">
125 Text = ""Culture: %(Culture) -- ResXFile: @(ResXFile)"" />
129 Engine engine = new Engine (Consts.BinPath);
130 Project project = engine.CreateNewProject ();
132 TestMessageLogger testLogger = new TestMessageLogger ();
133 engine.RegisterLogger (testLogger);
135 project.LoadXml (projectString);
136 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
138 CheckMessage (testLogger, "fr", "Item1;Item2;Item5", "A2");
139 CheckMessage (testLogger, "en", "Item3", "A3");
140 CheckMessage (testLogger, "gb", "Item4", "A4");
141 CheckMessage (testLogger, "it", "Item6", "A5");
143 CheckEngineEventCounts (testLogger, 1, 1, 4, 4);
147 public void TestUnqualifiedMetadataReference ()
149 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
151 <ResXFile Include=""Item1"">
152 <Culture>fr</Culture>
154 <ResXFile Include=""Item5"" />
155 <ResXFile Include=""Item6"">
156 <Culture>it</Culture>
160 <Target Name=""ShowMessage"">
162 Text = ""Culture: %(Culture) -- ResXFile: @(ResXFile)"" />
166 Engine engine = new Engine (Consts.BinPath);
167 Project project = engine.CreateNewProject ();
169 TestMessageLogger testLogger = new TestMessageLogger ();
170 engine.RegisterLogger (testLogger);
172 project.LoadXml (projectString);
174 //Fails as Culture is being referenced unqualified, and no Culture is
175 //specified for "Item5"
176 bool result = project.Build ("ShowMessage");
178 Assert.Fail ("A1: Build should have failed");
180 CheckEngineEventCounts (testLogger, 1, 1, 0, 0);
186 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
188 <ResXFile Include=""Item1"">
189 <Culture>fr</Culture>
191 <ResXFile Include=""Item5"" />
192 <ResXFile Include=""Item6"">
193 <Culture>it</Culture>
197 <Target Name=""ShowMessage"">
199 Text = ""Culture: %(ResXFile.Culture) -- ResXFile: @(ResXFile)"" />
203 Engine engine = new Engine (Consts.BinPath);
204 Project project = engine.CreateNewProject ();
206 TestMessageLogger testLogger = new TestMessageLogger ();
207 engine.RegisterLogger (testLogger);
209 project.LoadXml (projectString);
211 //no Culture is specified for "Item5", but
212 //Culture is being referenced __qualified__, so works
213 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
215 CheckMessage (testLogger, "fr", "Item1", "A2");
216 CheckMessage (testLogger, "", "Item5", "A3");
217 CheckMessage (testLogger, "it", "Item6", "A3");
218 CheckEngineEventCounts (testLogger, 1, 1, 3, 3);
222 public void TestMultiItemCollections ()
224 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
226 <ResXFile Include=""Item1"">
227 <Culture>fr</Culture>
229 <ResXFile Include=""Item2"">
230 <Culture>fr</Culture>
232 <ResXFile Include=""Item3"">
233 <Culture>en</Culture>
235 <ResXFile Include=""Item4"">
236 <Culture>gb</Culture>
238 <ResXFile Include=""Item6"">
239 <Culture>it</Culture>
242 <NonResXFile Include=""Item7"">
243 <Culture>it</Culture>
245 <NonResXFile Include=""Item8"">
246 <Culture>en</Culture>
248 <NonResXFile Include=""Item9"">
249 <Culture>en</Culture>
253 <Target Name=""ShowMessage"">
255 Text = ""Culture: %(Culture) -- ResXFiles: @(ResXFile) NonResXFiles: @(NonResXFile)"" />
259 Engine engine = new Engine (Consts.BinPath);
260 Project project = engine.CreateNewProject ();
262 TestMessageLogger testLogger = new TestMessageLogger ();
263 engine.RegisterLogger (testLogger);
265 project.LoadXml (projectString);
266 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
268 CheckMessage2 (testLogger, "fr", "Item1;Item2", string.Empty, "A2");
269 CheckMessage2 (testLogger, "en", "Item3", "Item8;Item9", "A3");
270 CheckMessage2 (testLogger, "gb", "Item4", string.Empty, "A4");
271 CheckMessage2 (testLogger, "it", "Item6", "Item7", "A6");
272 CheckEngineEventCounts (testLogger, 1, 1, 4, 4);
276 public void TestConditionalBatching ()
278 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
280 <ResXFile Include=""Item1"">
281 <Culture>fr</Culture>
283 <ResXFile Include=""Item2"">
284 <Culture>fr</Culture>
286 <ResXFile Include=""Item3"">
287 <Culture>en</Culture>
289 <ResXFile Include=""Item4"">
290 <Culture>gb</Culture>
292 <ResXFile Include=""Item6"">
293 <Culture>it</Culture>
296 <NonResXFile Include=""Item7"">
297 <Culture>it</Culture>
299 <NonResXFile Include=""Item8"">
300 <Culture>en</Culture>
302 <NonResXFile Include=""Item9"">
303 <Culture>en</Culture>
307 <Target Name=""ShowMessage"">
309 Text = ""ResXFiles: @(ResXFile) NonResXFiles: @(NonResXFile)""
310 Condition = ""'%(Culture)' == 'fr'""/>
314 Engine engine = new Engine (Consts.BinPath);
315 Project project = engine.CreateNewProject ();
317 TestMessageLogger testLogger = new TestMessageLogger ();
318 engine.RegisterLogger (testLogger);
320 project.LoadXml (projectString);
321 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
323 testLogger.CheckLoggedMessageHead ("ResXFiles: Item1;Item2 NonResXFiles: ", "A2");
324 CheckEngineEventCounts (testLogger, 1, 1, 1, 1);
328 public void TestMultipleMetadataReference ()
330 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
332 <ExampColl Include=""Item1"">
335 <ExampColl Include=""Item2"">
338 <ExampColl Include=""Item3"">
342 <ExampColl2 Include=""Item4"">
345 <ExampColl2 Include=""Item5"">
349 <ExampColl2 Include=""Item6"">
354 <Target Name=""ShowMessage"">
355 <Message Text = ""Number: %(Number) Color: %(ExampColl2.Color)-- Items in ExampColl: @(ExampColl) ExampColl2: @(ExampColl2)""/>
359 Engine engine = new Engine (Consts.BinPath);
360 Project project = engine.CreateNewProject ();
362 TestMessageLogger testLogger = new TestMessageLogger ();
363 engine.RegisterLogger (testLogger);
365 project.LoadXml (projectString);
366 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
368 CheckLoggedMessageAny (testLogger, "Number: 1 Color: -- Items in ExampColl: Item1;Item3 ExampColl2: Item4", "A2");
369 CheckLoggedMessageAny (testLogger, "Number: 2 Color: Red-- Items in ExampColl: ExampColl2: Item5", "A3");
370 CheckLoggedMessageAny (testLogger, "Number: 3 Color: Green-- Items in ExampColl: ExampColl2: Item6", "A4");
371 CheckLoggedMessageAny (testLogger, "Number: 2 Color: -- Items in ExampColl: Item2 ExampColl2: ", "A5");
372 Assert.AreEqual (0, testLogger.NormalMessageCount, "A6");
373 Assert.AreEqual (0, testLogger.WarningMessageCount, "A7");
374 CheckEngineEventCounts (testLogger, 1, 1, 4, 4);
378 public void TestMultipleMetadataReference2 ()
380 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
382 <GroupA Include=""file1.txt""/>
383 <GroupA Include=""file2.txt""/>
384 <GroupA Include=""file3.txt""/>
385 <GroupA Include=""file3.txt""/>
386 <GroupA Include=""file4.txt""/>
390 <GroupB Include=""file1.txt""/>
391 <GroupB Include=""file3.txt""/>
392 <GroupB Include=""file5.txt""/>
394 <GroupC Include=""PreExistingValue""/>
397 <Target Name=""Build"">
398 <CreateItem Include=""@(GroupA)"" Condition=""'%(Identity)' != '' and '@(GroupA)' != '' and '@(GroupB)' != ''"" >
399 <Output TaskParameter=""Include"" ItemName=""GroupC""/>
401 <Message Text=""%(GroupC.Identity)""/>
405 Engine engine = new Engine (Consts.BinPath);
406 Project project = engine.CreateNewProject ();
408 TestMessageLogger testLogger = new TestMessageLogger ();
409 engine.RegisterLogger (testLogger);
411 project.LoadXml (projectString);
412 Assert.IsTrue (project.Build ("Build"), "A1: Build failed");
414 BuildItemGroup include = project.GetEvaluatedItemsByName ("GroupC");
415 Assert.AreEqual (4, include.Count, "A2");
417 string [,] additional_metadata = new string [,] { { "Identity", "PreExistingValue" } };
418 CreateItemTest.CheckBuildItem (include [0], "GroupC", additional_metadata, "PreExistingValue", "A3");
420 additional_metadata = new string [,] { { "Identity", "file1.txt" } };
421 CreateItemTest.CheckBuildItem (include [1], "GroupC", additional_metadata, "file1.txt", "A4");
423 additional_metadata = new string [,] { { "Identity", "file3.txt" } };
424 CreateItemTest.CheckBuildItem (include [2], "GroupC", additional_metadata, "file3.txt", "A5");
425 CreateItemTest.CheckBuildItem (include [3], "GroupC", additional_metadata, "file3.txt", "A6");
427 CheckEngineEventCounts (testLogger, 1, 1, 5, 5);
431 public void TestIdentity ()
433 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
435 <ExampColl Include=""Item1""/>
436 <ExampColl Include=""Item2""/>
437 <ExampColl Include=""Item3""/>
438 <ExampColl Include=""Item4""/>
439 <ExampColl Include=""Item4""/>
440 <ExampColl Include=""Item5""/>
441 <ExampColl Include=""Item6""/>
443 <Target Name=""ShowMessage"">
444 <Message Text = ""Identity: %(IdenTIty) -- Items in ExampColl: @(ExampColl)""/>
448 Engine engine = new Engine (Consts.BinPath);
449 Project project = engine.CreateNewProject ();
451 TestMessageLogger testLogger = new TestMessageLogger ();
452 engine.RegisterLogger (testLogger);
454 project.LoadXml (projectString);
455 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
457 CheckLoggedMessageAny (testLogger, "Identity: Item1 -- Items in ExampColl: Item1", "A2");
458 CheckLoggedMessageAny (testLogger, "Identity: Item2 -- Items in ExampColl: Item2", "A3");
459 CheckLoggedMessageAny (testLogger, "Identity: Item3 -- Items in ExampColl: Item3", "A4");
460 CheckLoggedMessageAny (testLogger, "Identity: Item4 -- Items in ExampColl: Item4;Item4", "A5");
461 CheckLoggedMessageAny (testLogger, "Identity: Item5 -- Items in ExampColl: Item5", "A6");
462 CheckLoggedMessageAny (testLogger, "Identity: Item6 -- Items in ExampColl: Item6", "A7");
463 Assert.AreEqual (0, testLogger.NormalMessageCount, "A8");
464 Assert.AreEqual (0, testLogger.WarningMessageCount, "A7");
465 CheckEngineEventCounts (testLogger, 1, 1, 6, 6);
469 public void TestFilter ()
471 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
473 <fruit Include=""apple"">
474 <consistency>firm</consistency>
476 <fruit Include=""orange"">
477 <consistency>pulpy</consistency>
479 <fruit Include=""banana"">
480 <consistency>softish</consistency>
482 <fruit Include=""pear"">
483 <consistency>unsound</consistency>
485 <fruit Include=""apricot"">
486 <consistency>unsound</consistency>
489 <Target Name=""Compost"">
490 <CreateItem Include=""@(fruit)"" Condition=""'%(consistency)' == 'pulpy' or '%(consistency)' == 'unsound' "">
491 <Output TaskParameter=""Include"" ItemName=""Final""/>
496 Engine engine = new Engine (Consts.BinPath);
497 Project project = engine.CreateNewProject ();
499 TestMessageLogger testLogger = new TestMessageLogger ();
500 engine.RegisterLogger (testLogger);
502 project.LoadXml (projectString);
503 Assert.IsTrue (project.Build ("Compost"), "A1: Build failed");
505 BuildItemGroup include = project.GetEvaluatedItemsByName ("Final");
506 Assert.AreEqual (3, include.Count, "A2");
508 string [,] additional_metadata = new string [,] { { "Identity", "orange" } };
509 CreateItemTest.CheckBuildItem (include [0], "Final", additional_metadata, "orange", "A3");
511 additional_metadata = new string [,] { { "Identity", "pear" } };
512 CreateItemTest.CheckBuildItem (include [1], "Final", additional_metadata, "pear", "A4");
514 additional_metadata = new string [,] { { "Identity", "apricot" } };
515 CreateItemTest.CheckBuildItem (include [2], "Final", additional_metadata, "apricot", "A5");
516 CheckEngineEventCounts (testLogger, 1, 1, 2, 2);
520 // test for metadata refs in properties or items
521 public void TestNoBatching () {
522 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
524 <item3 Include=""foo""/>
525 <item2 Include=""%(item3.Identity)""/>
526 <item0 Include=""@(item3)""/>
529 <Prop1>%(item0.Identity)</Prop1>
532 <Message Text=""Prop1: $(Prop1)""/>
533 <Message Text=""Item2: @(item2)""/>
537 Engine engine = new Engine (Consts.BinPath);
538 Project project = engine.CreateNewProject ();
540 TestMessageLogger testLogger = new TestMessageLogger ();
541 engine.RegisterLogger (testLogger);
543 project.LoadXml (projectString);
544 if (!project.Build ("1")) {
545 testLogger.DumpMessages ();
546 Assert.Fail ("Build failed");
549 testLogger.CheckLoggedMessageHead ("Prop1: %(item0.Identity)", "A1");
550 testLogger.CheckLoggedMessageHead ("Item2: %(item3.Identity)", "A2");
551 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
555 // test for metadata refs via metadata refs
556 // batching should happen only on basis of the task attributes,
557 // and not the resolved expression values
558 public void TestBatching1 () {
559 string projectString = projectHeader + @"
561 <item3 Include=""foo""/>
562 <item2 Include=""%(item3.Identity)""/>
564 <item4 Include=""%(item2.Identity);@(item3);@(nonexistant)""/>
565 <item4 Include=""bar""/>
568 <Message Text=""Item4: %(item4.Identity)""/>
572 Engine engine = new Engine (Consts.BinPath);
573 Project project = engine.CreateNewProject ();
575 TestMessageLogger testLogger = new TestMessageLogger ();
576 engine.RegisterLogger (testLogger);
578 project.LoadXml (projectString);
579 if (!project.Build ("1")) {
580 testLogger.DumpMessages ();
581 Assert.Fail ("Build failed");
584 testLogger.CheckLoggedMessageHead ("Item4: %(item2.Identity)", "A1");
585 testLogger.CheckLoggedMessageHead ("Item4: foo", "A2");
586 testLogger.CheckLoggedMessageHead ("Item4: bar", "A3");
587 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
591 // test for metadata refs via metadata refs
592 // batching should happen only on basis of the task attributes,
593 // and not the resolved expression values
594 public void TestConditionalBatching2 () {
595 string projectString = projectHeader + @"
597 <item2 Include=""%(item3.Identity)""/>
598 <item4 Include=""%(item2.Identity);@(item3)""/>
601 <Message Text=""Item3: %(item2.Identity)"" Condition="" '%(item5.Identity)' == '' ""/>
602 <Message Text=""Item4: %(item4.Identity)""/>
606 Engine engine = new Engine (Consts.BinPath);
607 Project project = engine.CreateNewProject ();
609 TestMessageLogger testLogger = new TestMessageLogger ();
610 engine.RegisterLogger (testLogger);
612 project.LoadXml (projectString);
613 if (!project.Build ("1")) {
614 testLogger.DumpMessages ();
615 Assert.Fail ("Build failed");
618 testLogger.CheckLoggedMessageHead ("Item3: %(item3.Identity)", "A1");
619 testLogger.CheckLoggedMessageHead ("Item4: %(item2.Identity)", "A2");
620 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
624 public void TestBatchingWithUnbatchedItems () {
625 string projectString = projectHeader + @"
627 <Item1 Include=""One""/>
628 <Item1 Include=""Two""/>
633 <Message Text=""Item1: %(Item1.Identity) | B: @(B)""/>
637 Engine engine = new Engine (Consts.BinPath);
638 Project project = engine.CreateNewProject ();
640 TestMessageLogger testLogger = new TestMessageLogger ();
641 engine.RegisterLogger (testLogger);
643 project.LoadXml (projectString);
644 if (!project.Build ("1")) {
645 testLogger.DumpMessages ();
646 Assert.Fail ("Build failed");
650 testLogger.CheckLoggedMessageHead ("Item1: One | B: abc", "A1");
651 testLogger.CheckLoggedMessageHead ("Item1: Two | B: abc", "A2");
653 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
654 } catch (AssertionException) {
655 testLogger.DumpMessages ();
661 public void TestPropertiesWithBatchedReferences () {
662 string projectString = projectHeader + @"
664 <Item1 Include=""One""/>
665 <Item1 Include=""Two""/>
667 <Item1Ref Include=""@(Item1)""/>
670 <Prop1>@(Item1)</Prop1>
671 <Prop2>@(Item1Ref)</Prop2>
674 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
678 Engine engine = new Engine (Consts.BinPath);
679 Project project = engine.CreateNewProject ();
681 TestMessageLogger testLogger = new TestMessageLogger ();
682 engine.RegisterLogger (testLogger);
684 project.LoadXml (projectString);
685 if (!project.Build ("1")) {
687 testLogger.DumpMessages ();
688 Assert.Fail ("Build failed");
692 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: One | Prop2: One;Two", "A1");
693 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Two | Prop2: One;Two", "A2");
695 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
696 } catch (AssertionException) {
697 testLogger.DumpMessages ();
703 public void TestPropertiesWithDynamicItems () {
704 string projectString = projectHeader + @"
706 <Item1 Include=""One""/>
707 <Item1 Include=""Two""/>
709 <Item2 Include=""Z""/>
710 <Item2Ref Include=""@(Item2)"" />
713 <Prop1>@(Item2)</Prop1>
714 <Prop2>@(Item2Ref)</Prop2>
717 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
718 <Message Text=""Item2: @(Item2) | Item2Ref: @(Item2Ref)""/>
719 <CreateItem Include=""A;B"">
720 <Output TaskParameter=""Include"" ItemName=""Item2""/>
722 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
723 <Message Text=""Item2: @(Item2) | Item2Ref: @(Item2Ref)""/>
727 Engine engine = new Engine (Consts.BinPath);
728 Project project = engine.CreateNewProject ();
730 TestMessageLogger testLogger = new TestMessageLogger ();
731 engine.RegisterLogger (testLogger);
733 project.LoadXml (projectString);
734 if (!project.Build ("1")) {
736 testLogger.DumpMessages ();
737 Assert.Fail ("Build failed");
742 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: Z | Prop2: Z", "A1");
743 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Z | Prop2: Z", "A2");
744 testLogger.CheckLoggedMessageHead ("Item2: Z | Item2Ref: Z", "A3");
746 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: Z;A;B | Prop2: Z", "A4");
747 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Z;A;B | Prop2: Z", "A5");
748 testLogger.CheckLoggedMessageHead ("Item2: Z;A;B | Item2Ref: Z", "A3");
750 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
751 } catch (AssertionException) {
752 testLogger.DumpMessages ();
758 public void TestTargetInvocationFromBatchedTask () {
759 string projectString = projectHeader + @"
761 <Item1 Include=""One""/>
762 <Item1 Include=""Two""/>
764 <Item1Ref Include=""@(Item1)"" />
767 <Prop1>@(Item1)</Prop1>
768 <Prop2>@(Item1Ref)</Prop2>
771 <CallTarget Targets='foo' Condition="" '%(Item1.Identity)' != ''"" />
772 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
773 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
776 <Message Text=""(foo) Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
777 <Message Text=""(foo) Prop1: $(Prop1) Prop2: $(Prop2)""/>
781 Engine engine = new Engine (Consts.BinPath);
782 Project project = engine.CreateNewProject ();
784 TestMessageLogger testLogger = new TestMessageLogger ();
785 engine.RegisterLogger (testLogger);
787 project.LoadXml (projectString);
788 if (!project.Build ("1")) {
790 testLogger.DumpMessages ();
791 Assert.Fail ("Build failed");
795 testLogger.CheckLoggedMessageHead ("(foo) Item1: One;Two Item1Ref: One;Two", "A1");
796 testLogger.CheckLoggedMessageHead ("(foo) Prop1: One;Two Prop2: One;Two", "A2");
798 testLogger.CheckLoggedMessageHead ("Item1: One;Two Item1Ref: One;Two", "A3");
799 testLogger.CheckLoggedMessageHead ("Prop1: One;Two Prop2: One;Two", "A4");
801 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
802 } catch (AssertionException) {
803 testLogger.DumpMessages ();
809 public void TestTargetInvocationFromBatchedTarget () {
810 string projectString = projectHeader + @"
812 <Item1 Include=""One""/>
813 <Item1 Include=""Two""/>
815 <Item1Ref Include=""@(Item1)"" />
818 <Prop1>@(Item1)</Prop1>
819 <Prop2>@(Item1Ref)</Prop2>
821 <Target Name='1' Inputs=""%(Item1.Identity)"" Outputs=""Nonexistant.foobar"">
822 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
823 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
825 <CallTarget Targets='foo' />
827 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
828 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
830 <Target Name='foo' Condition="" '@(Item1)' != 'One' "">
831 <Message Text=""(foo) Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
832 <Message Text=""(foo) Prop1: $(Prop1) Prop2: $(Prop2)""/>
836 Engine engine = new Engine (Consts.BinPath);
837 Project project = engine.CreateNewProject ();
839 TestMessageLogger testLogger = new TestMessageLogger ();
840 engine.RegisterLogger (testLogger);
842 project.LoadXml (projectString);
843 if (!project.Build ("1")) {
845 testLogger.DumpMessages ();
846 Assert.Fail ("Build failed");
850 testLogger.CheckLoggedMessageHead ("Item1: One Item1Ref: One;Two", "A1");
851 testLogger.CheckLoggedMessageHead ("Prop1: One Prop2: One;Two", "A2");
853 testLogger.CheckLoggedMessageHead ("(foo) Item1: One;Two Item1Ref: One;Two", "A3");
854 testLogger.CheckLoggedMessageHead ("(foo) Prop1: One;Two Prop2: One;Two", "A4");
856 testLogger.CheckLoggedMessageHead ("Item1: One Item1Ref: One;Two", "A5");
857 testLogger.CheckLoggedMessageHead ("Prop1: One Prop2: One;Two", "A6");
859 //second batch, foo has already run, so doesn't execute again
860 testLogger.CheckLoggedMessageHead ("Item1: Two Item1Ref: One;Two", "A7");
861 testLogger.CheckLoggedMessageHead ("Prop1: Two Prop2: One;Two", "A8");
863 testLogger.CheckLoggedMessageHead ("Item1: Two Item1Ref: One;Two", "A9");
864 testLogger.CheckLoggedMessageHead ("Prop1: Two Prop2: One;Two", "A10");
866 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
867 } catch (AssertionException) {
868 testLogger.DumpMessages ();
874 public void TestBatchingWithUnqualifiedMetadataReference () {
875 string projectString = projectHeader + @"
877 <Item1 Include=""One""><Md>1</Md></Item1>
878 <Item1 Include=""Two""><Md>2</Md></Item1>
879 <Item1Ref Include=""@(Item1)"" />
881 <Item2 Include=""Three""><Md>3</Md></Item2>
882 <Item2 Include=""Four""><Md>4</Md></Item2>
883 <Item2Ref Include=""@(Item2)"" />
886 <Prop1>@(Item1)</Prop1>
887 <Prop1Ref>@(Item1Ref)</Prop1Ref>
889 <Prop2>@(Item2)</Prop2>
890 <Prop2Ref>@(Item2Ref)</Prop2Ref>
893 <Message Text=""For md: %(Md) Item1: @(Item1) Item1Ref: @(Item1Ref) Item2: @(Item2) Item2Ref: @(Item2Ref) " +
894 @" Prop1: $(Prop1) Prop1Ref: $(Prop1Ref) Prop2: $(Prop2) Prop2Ref: $(Prop2Ref)""/>
898 Engine engine = new Engine (Consts.BinPath);
899 Project project = engine.CreateNewProject ();
901 TestMessageLogger testLogger = new TestMessageLogger ();
902 engine.RegisterLogger (testLogger);
904 project.LoadXml (projectString);
905 if (!project.Build ("1")) {
907 testLogger.DumpMessages ();
908 Assert.Fail ("Build failed");
912 testLogger.CheckLoggedAny ("For md: 3 Item1: Item1Ref: Item2: Three Item2Ref: Three Prop1: Prop1Ref: Prop2: Three Prop2Ref: Three", MessageImportance.Normal, "A1");
913 testLogger.CheckLoggedAny ("For md: 4 Item1: Item1Ref: Item2: Four Item2Ref: Four Prop1: Prop1Ref: Prop2: Four Prop2Ref: Four", MessageImportance.Normal, "A2");
914 testLogger.CheckLoggedAny ("For md: 1 Item1: One Item1Ref: One Item2: Item2Ref: Prop1: One Prop1Ref: One Prop2: Prop2Ref: ", MessageImportance.Normal, "A3");
915 testLogger.CheckLoggedAny ("For md: 2 Item1: Two Item1Ref: Two Item2: Item2Ref: Prop1: Two Prop1Ref: Two Prop2: Prop2Ref: ", MessageImportance.Normal, "A4");
917 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
918 } catch (AssertionException) {
919 testLogger.DumpMessages ();
928 public void TestTargetBatching1 ()
930 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
932 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
933 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
934 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
935 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
937 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
938 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
940 <Foo Include=""1_a1""><Md>1</Md></Foo>
941 <Foo Include=""2_b1""><Md>2</Md></Foo>
942 <Foo Include=""1_c1""><Md>1</Md></Foo>
945 <Target Name=""foo"" >
946 <Message Text=""TargetStarted""/>
947 <Message Text=""List1: @(List1): %(Culture)""/>
948 <Message Text=""Foo: @(Foo): %(Md)""/>
952 Engine engine = new Engine (Consts.BinPath);
953 Project project = engine.CreateNewProject ();
955 TestMessageLogger testLogger = new TestMessageLogger ();
956 engine.RegisterLogger (testLogger);
958 project.LoadXml (projectString);
959 bool res = project.Build ("foo");
961 testLogger.DumpMessages ();
962 Assert.Fail ("A1: Build failed");
965 CheckLoggedMessagesInOrder (testLogger, new string [] {
966 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
967 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
968 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
970 CheckEngineEventCounts (testLogger, 1, 1, 6, 6);
974 public void TestTargetBatching2 ()
976 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
978 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
979 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
980 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
981 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
983 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
984 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
986 <Foo Include=""1_a1""><Md>1</Md></Foo>
987 <Foo Include=""2_b1""><Md>2</Md></Foo>
988 <Foo Include=""1_c1""><Md>1</Md></Foo>
991 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
992 <Message Text=""TargetStarted""/>
993 <Message Text=""List1: @(List1): %(Culture)""/>
994 <Message Text=""Foo: @(Foo): %(Md)""/>
998 Engine engine = new Engine (Consts.BinPath);
999 Project project = engine.CreateNewProject ();
1001 TestMessageLogger testLogger = new TestMessageLogger ();
1002 engine.RegisterLogger (testLogger);
1004 project.LoadXml (projectString);
1005 bool res = project.Build ("foo");
1007 testLogger.DumpMessages ();
1008 Assert.Fail ("A1: Build failed");
1011 CheckLoggedMessagesInOrder (testLogger, new string [] {
1012 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1013 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1015 "TargetStarted", "List1: en_b.txt: en",
1016 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1018 "TargetStarted", "List1: gb_d.txt: gb",
1019 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1021 CheckEngineEventCounts (testLogger, 3, 3, 12, 12);
1025 public void TestTargetBatching3 ()
1027 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1029 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1030 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1031 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1032 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1034 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1035 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1037 <Foo Include=""1_a1""><Md>1</Md></Foo>
1038 <Foo Include=""2_b1""><Md>2</Md></Foo>
1039 <Foo Include=""1_c1""><Md>1</Md></Foo>
1041 <Target Name=""foo"" Inputs=""@(Foo)"" Outputs=""%(Md).foo"">
1042 <Message Text=""TargetStarted""/>
1043 <Message Text=""List1: @(List1): %(Culture)""/>
1044 <Message Text=""Foo: @(Foo): %(Md)""/>
1048 Engine engine = new Engine (Consts.BinPath);
1049 Project project = engine.CreateNewProject ();
1051 TestMessageLogger testLogger = new TestMessageLogger ();
1052 engine.RegisterLogger (testLogger);
1054 project.LoadXml (projectString);
1055 bool res = project.Build ("foo");
1057 testLogger.DumpMessages ();
1058 Assert.Fail ("A1: Build failed");
1061 CheckLoggedMessagesInOrder (testLogger, new string [] {
1062 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1063 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1064 "Foo: 1_a1;1_c1: 1",
1065 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1066 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1069 CheckEngineEventCounts (testLogger, 2, 2, 10, 10);
1073 public void TestTargetBatching4 ()
1075 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1077 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1078 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1079 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1080 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1082 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1083 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1085 <Foo Include=""1_a1""><Md>1</Md></Foo>
1086 <Foo Include=""2_b1""><Md>2</Md></Foo>
1087 <Foo Include=""1_c1""><Md>1</Md></Foo>
1089 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1090 <Message Text=""TargetStarted""/>
1091 <Message Text=""List1: @(List1): %(Culture)""/>
1092 <Message Text=""List2: @(List2): %(Culture)""/>
1093 <Message Text=""Foo: @(Foo): %(Md)""/>
1097 Engine engine = new Engine (Consts.BinPath);
1098 Project project = engine.CreateNewProject ();
1100 TestMessageLogger testLogger = new TestMessageLogger ();
1101 engine.RegisterLogger (testLogger);
1103 project.LoadXml (projectString);
1104 bool res = project.Build ("foo");
1106 testLogger.DumpMessages ();
1107 Assert.Fail ("A1: Build failed");
1110 CheckLoggedMessagesInOrder (testLogger, new string [] {
1111 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1112 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1113 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1115 "TargetStarted", "List1: en_b.txt: en",
1116 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1117 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1119 "TargetStarted", "List1: gb_d.txt: gb",
1120 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1121 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1123 CheckEngineEventCounts (testLogger, 3, 3, 18, 18);
1127 public void TestTargetBatching5 ()
1129 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1130 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1131 <Message Text=""TargetStarted""/>
1135 Engine engine = new Engine (Consts.BinPath);
1136 Project project = engine.CreateNewProject ();
1138 TestMessageLogger testLogger = new TestMessageLogger ();
1139 engine.RegisterLogger (testLogger);
1141 project.LoadXml (projectString);
1142 bool res = project.Build ("foo");
1144 testLogger.DumpMessages ();
1145 Assert.Fail ("A1: Build failed");
1147 Assert.AreEqual (1, testLogger.CheckAny ("TargetStarted", MessageImportance.Normal),
1148 "A2: Target should've been skipped because of no inputs");
1149 CheckEngineEventCounts (testLogger, 1, 1, 0, 0);
1153 public void TestTargetBatching6 ()
1155 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1157 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1158 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1159 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1160 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1162 <List3 Include=""fr_x.txt""><Culture>fr</Culture></List3>
1163 <List3 Include=""gb_z.txt""><Culture>gb</Culture></List3>
1165 <Foo Include=""1_a1""><Md>1</Md></Foo>
1166 <Foo Include=""2_b1""><Md>2</Md></Foo>
1167 <Foo Include=""1_c1""><Md>1</Md></Foo>
1170 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1171 <Message Text=""TargetStarted"" />
1172 <Message Text=""List1: %(List1.Culture), List2: %(List2.Culture)"" />
1173 <Message Text=""List2: @(List2), Culture: %(Culture)"" />
1174 <Message Text=""List3: @(List3), Culture: %(Culture)"" />
1178 Engine engine = new Engine (Consts.BinPath);
1179 Project project = engine.CreateNewProject ();
1181 TestMessageLogger testLogger = new TestMessageLogger ();
1182 engine.RegisterLogger (testLogger);
1184 project.LoadXml (projectString);
1185 bool res = project.Build ("foo");
1187 testLogger.DumpMessages ();
1188 Assert.Fail ("A1: Build failed");
1191 CheckLoggedMessagesInOrder (testLogger, new string [] {
1193 "List1: fr, List2: ",
1194 "List2: , Culture: ",
1195 "List3: fr_x.txt, Culture: fr",
1196 "List3: gb_z.txt, Culture: gb",
1199 "List1: en, List2: ",
1200 "List2: , Culture: ",
1201 "List3: fr_x.txt, Culture: fr",
1202 "List3: gb_z.txt, Culture: gb",
1205 "List1: gb, List2: ",
1206 "List2: , Culture: ",
1207 "List3: fr_x.txt, Culture: fr",
1208 "List3: gb_z.txt, Culture: gb"
1210 CheckEngineEventCounts (testLogger, 3, 3, 15, 15);
1214 public void TestTargetBatching7 ()
1216 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1218 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1219 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1220 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1221 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1223 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1224 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1226 <Foo Include=""1_a1""><Md>1</Md></Foo>
1227 <Foo Include=""2_b1""><Md>2</Md></Foo>
1228 <Foo Include=""1_c1""><Md>1</Md></Foo>
1231 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1232 <Message Text=""TargetStarted"" />
1233 <Message Text=""List1: @(List1), List2: @(List2)""/>
1237 Engine engine = new Engine (Consts.BinPath);
1238 Project project = engine.CreateNewProject ();
1240 TestMessageLogger testLogger = new TestMessageLogger ();
1241 engine.RegisterLogger (testLogger);
1243 project.LoadXml (projectString);
1244 bool res = project.Build ("foo");
1246 testLogger.DumpMessages ();
1247 Assert.Fail ("A1: Build failed");
1250 CheckLoggedMessagesInOrder (testLogger, new string [] {
1252 "List1: fr_a.txt;fr_c.txt, List2: fr_x.txt",
1255 "List1: en_b.txt, List2: ",
1258 "List1: gb_d.txt, List2: gb_z.txt"
1260 CheckEngineEventCounts (testLogger, 3, 3, 6, 6);
1263 void CheckLoggedMessagesInOrder (TestMessageLogger logger, string [] values, string prefix)
1266 for (int i = 0; i < values.Length; i++) {
1267 logger.CheckLoggedMessageHead (values [i], prefix + "#" + i);
1269 if (logger.NormalMessageCount > 0)
1270 Assert.Fail ("{0}: Expected {1} messages, but found {2}",
1271 prefix, values.Length, values.Length + logger.NormalMessageCount);
1272 } catch (NUnit.Framework.AssertionException) {
1273 logger.DumpMessages ();
1278 void CheckMessage (TestMessageLogger logger, string culture, string items, string id)
1280 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFile: {1}", culture, items), id);
1283 void CheckMessage2 (TestMessageLogger logger, string culture, string resx_files, string nonresx_files, string id)
1285 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFiles: {1} NonResXFiles: {2}", culture, resx_files, nonresx_files), id);
1288 void CheckLoggedMessageAny (TestMessageLogger logger, string expected, string id)
1290 if (logger.CheckAny (expected, MessageImportance.Normal) == 1)
1291 Assert.Fail ("{0}: Expected message '{1}' was not emitted.", id, expected);
1294 void CheckEngineEventCounts (TestMessageLogger logger, int target_start, int target_finish, int task_start, int task_finish)
1296 Assert.AreEqual (target_start, logger.TargetStarted, "TargetStarted event count doesn't match");
1297 Assert.AreEqual (target_finish, logger.TargetFinished, "TargetFinished event count doesn't match");
1298 Assert.AreEqual (task_start, logger.TaskStarted, "TaskStarted event count doesn't match");
1299 Assert.AreEqual (task_finish, logger.TaskFinished, "TaskFinished event count doesn't match");