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.Count, "A6");
373 CheckEngineEventCounts (testLogger, 1, 1, 4, 4);
377 public void TestMultipleMetadataReference2 ()
379 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
381 <GroupA Include=""file1.txt""/>
382 <GroupA Include=""file2.txt""/>
383 <GroupA Include=""file3.txt""/>
384 <GroupA Include=""file3.txt""/>
385 <GroupA Include=""file4.txt""/>
389 <GroupB Include=""file1.txt""/>
390 <GroupB Include=""file3.txt""/>
391 <GroupB Include=""file5.txt""/>
393 <GroupC Include=""PreExistingValue""/>
396 <Target Name=""Build"">
397 <CreateItem Include=""@(GroupA)"" Condition=""'%(Identity)' != '' and '@(GroupA)' != '' and '@(GroupB)' != ''"" >
398 <Output TaskParameter=""Include"" ItemName=""GroupC""/>
400 <Message Text=""%(GroupC.Identity)""/>
404 Engine engine = new Engine (Consts.BinPath);
405 Project project = engine.CreateNewProject ();
407 TestMessageLogger testLogger = new TestMessageLogger ();
408 engine.RegisterLogger (testLogger);
410 project.LoadXml (projectString);
411 Assert.IsTrue (project.Build ("Build"), "A1: Build failed");
413 BuildItemGroup include = project.GetEvaluatedItemsByName ("GroupC");
414 Assert.AreEqual (4, include.Count, "A2");
416 string [,] additional_metadata = new string [,] { { "Identity", "PreExistingValue" } };
417 CreateItemTest.CheckBuildItem (include [0], "GroupC", additional_metadata, "PreExistingValue", "A3");
419 additional_metadata = new string [,] { { "Identity", "file1.txt" } };
420 CreateItemTest.CheckBuildItem (include [1], "GroupC", additional_metadata, "file1.txt", "A4");
422 additional_metadata = new string [,] { { "Identity", "file3.txt" } };
423 CreateItemTest.CheckBuildItem (include [2], "GroupC", additional_metadata, "file3.txt", "A5");
424 CreateItemTest.CheckBuildItem (include [3], "GroupC", additional_metadata, "file3.txt", "A6");
426 CheckEngineEventCounts (testLogger, 1, 1, 5, 5);
430 public void TestIdentity ()
432 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
434 <ExampColl Include=""Item1""/>
435 <ExampColl Include=""Item2""/>
436 <ExampColl Include=""Item3""/>
437 <ExampColl Include=""Item4""/>
438 <ExampColl Include=""Item4""/>
439 <ExampColl Include=""Item5""/>
440 <ExampColl Include=""Item6""/>
442 <Target Name=""ShowMessage"">
443 <Message Text = ""Identity: %(IdenTIty) -- Items in ExampColl: @(ExampColl)""/>
447 Engine engine = new Engine (Consts.BinPath);
448 Project project = engine.CreateNewProject ();
450 TestMessageLogger testLogger = new TestMessageLogger ();
451 engine.RegisterLogger (testLogger);
453 project.LoadXml (projectString);
454 Assert.IsTrue (project.Build ("ShowMessage"), "A1: Build failed");
456 CheckLoggedMessageAny (testLogger, "Identity: Item1 -- Items in ExampColl: Item1", "A2");
457 CheckLoggedMessageAny (testLogger, "Identity: Item2 -- Items in ExampColl: Item2", "A3");
458 CheckLoggedMessageAny (testLogger, "Identity: Item3 -- Items in ExampColl: Item3", "A4");
459 CheckLoggedMessageAny (testLogger, "Identity: Item4 -- Items in ExampColl: Item4;Item4", "A5");
460 CheckLoggedMessageAny (testLogger, "Identity: Item5 -- Items in ExampColl: Item5", "A6");
461 CheckLoggedMessageAny (testLogger, "Identity: Item6 -- Items in ExampColl: Item6", "A7");
462 Assert.AreEqual (0, testLogger.Count, "A8");
463 CheckEngineEventCounts (testLogger, 1, 1, 6, 6);
467 public void TestFilter ()
469 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
471 <fruit Include=""apple"">
472 <consistency>firm</consistency>
474 <fruit Include=""orange"">
475 <consistency>pulpy</consistency>
477 <fruit Include=""banana"">
478 <consistency>softish</consistency>
480 <fruit Include=""pear"">
481 <consistency>unsound</consistency>
483 <fruit Include=""apricot"">
484 <consistency>unsound</consistency>
487 <Target Name=""Compost"">
488 <CreateItem Include=""@(fruit)"" Condition=""'%(consistency)' == 'pulpy' or '%(consistency)' == 'unsound' "">
489 <Output TaskParameter=""Include"" ItemName=""Final""/>
494 Engine engine = new Engine (Consts.BinPath);
495 Project project = engine.CreateNewProject ();
497 TestMessageLogger testLogger = new TestMessageLogger ();
498 engine.RegisterLogger (testLogger);
500 project.LoadXml (projectString);
501 Assert.IsTrue (project.Build ("Compost"), "A1: Build failed");
503 BuildItemGroup include = project.GetEvaluatedItemsByName ("Final");
504 Assert.AreEqual (3, include.Count, "A2");
506 string [,] additional_metadata = new string [,] { { "Identity", "orange" } };
507 CreateItemTest.CheckBuildItem (include [0], "Final", additional_metadata, "orange", "A3");
509 additional_metadata = new string [,] { { "Identity", "pear" } };
510 CreateItemTest.CheckBuildItem (include [1], "Final", additional_metadata, "pear", "A4");
512 additional_metadata = new string [,] { { "Identity", "apricot" } };
513 CreateItemTest.CheckBuildItem (include [2], "Final", additional_metadata, "apricot", "A5");
514 CheckEngineEventCounts (testLogger, 1, 1, 2, 2);
518 // test for metadata refs in properties or items
519 public void TestNoBatching () {
520 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
522 <item3 Include=""foo""/>
523 <item2 Include=""%(item3.Identity)""/>
524 <item0 Include=""@(item3)""/>
527 <Prop1>%(item0.Identity)</Prop1>
530 <Message Text=""Prop1: $(Prop1)""/>
531 <Message Text=""Item2: @(item2)""/>
535 Engine engine = new Engine (Consts.BinPath);
536 Project project = engine.CreateNewProject ();
538 TestMessageLogger testLogger = new TestMessageLogger ();
539 engine.RegisterLogger (testLogger);
541 project.LoadXml (projectString);
542 if (!project.Build ("1")) {
543 testLogger.DumpMessages ();
544 Assert.Fail ("Build failed");
547 testLogger.CheckLoggedMessageHead ("Prop1: %(item0.Identity)", "A1");
548 testLogger.CheckLoggedMessageHead ("Item2: %(item3.Identity)", "A2");
549 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
553 // test for metadata refs via metadata refs
554 // batching should happen only on basis of the task attributes,
555 // and not the resolved expression values
556 public void TestBatching1 () {
557 string projectString = projectHeader + @"
559 <item3 Include=""foo""/>
560 <item2 Include=""%(item3.Identity)""/>
562 <item4 Include=""%(item2.Identity);@(item3);@(nonexistant)""/>
563 <item4 Include=""bar""/>
566 <Message Text=""Item4: %(item4.Identity)""/>
570 Engine engine = new Engine (Consts.BinPath);
571 Project project = engine.CreateNewProject ();
573 TestMessageLogger testLogger = new TestMessageLogger ();
574 engine.RegisterLogger (testLogger);
576 project.LoadXml (projectString);
577 if (!project.Build ("1")) {
578 testLogger.DumpMessages ();
579 Assert.Fail ("Build failed");
582 testLogger.CheckLoggedMessageHead ("Item4: %(item2.Identity)", "A1");
583 testLogger.CheckLoggedMessageHead ("Item4: foo", "A2");
584 testLogger.CheckLoggedMessageHead ("Item4: bar", "A3");
585 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
589 // test for metadata refs via metadata refs
590 // batching should happen only on basis of the task attributes,
591 // and not the resolved expression values
592 public void TestConditionalBatching2 () {
593 string projectString = projectHeader + @"
595 <item2 Include=""%(item3.Identity)""/>
596 <item4 Include=""%(item2.Identity);@(item3)""/>
599 <Message Text=""Item3: %(item2.Identity)"" Condition="" '%(item5.Identity)' == '' ""/>
600 <Message Text=""Item4: %(item4.Identity)""/>
604 Engine engine = new Engine (Consts.BinPath);
605 Project project = engine.CreateNewProject ();
607 TestMessageLogger testLogger = new TestMessageLogger ();
608 engine.RegisterLogger (testLogger);
610 project.LoadXml (projectString);
611 if (!project.Build ("1")) {
612 testLogger.DumpMessages ();
613 Assert.Fail ("Build failed");
616 testLogger.CheckLoggedMessageHead ("Item3: %(item3.Identity)", "A1");
617 testLogger.CheckLoggedMessageHead ("Item4: %(item2.Identity)", "A2");
618 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
622 public void TestBatchingWithUnbatchedItems () {
623 string projectString = projectHeader + @"
625 <Item1 Include=""One""/>
626 <Item1 Include=""Two""/>
631 <Message Text=""Item1: %(Item1.Identity) | B: @(B)""/>
635 Engine engine = new Engine (Consts.BinPath);
636 Project project = engine.CreateNewProject ();
638 TestMessageLogger testLogger = new TestMessageLogger ();
639 engine.RegisterLogger (testLogger);
641 project.LoadXml (projectString);
642 if (!project.Build ("1")) {
643 testLogger.DumpMessages ();
644 Assert.Fail ("Build failed");
648 testLogger.CheckLoggedMessageHead ("Item1: One | B: abc", "A1");
649 testLogger.CheckLoggedMessageHead ("Item1: Two | B: abc", "A2");
651 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
652 } catch (AssertionException) {
653 testLogger.DumpMessages ();
659 public void TestPropertiesWithBatchedReferences () {
660 string projectString = projectHeader + @"
662 <Item1 Include=""One""/>
663 <Item1 Include=""Two""/>
665 <Item1Ref Include=""@(Item1)""/>
668 <Prop1>@(Item1)</Prop1>
669 <Prop2>@(Item1Ref)</Prop2>
672 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
676 Engine engine = new Engine (Consts.BinPath);
677 Project project = engine.CreateNewProject ();
679 TestMessageLogger testLogger = new TestMessageLogger ();
680 engine.RegisterLogger (testLogger);
682 project.LoadXml (projectString);
683 if (!project.Build ("1")) {
685 testLogger.DumpMessages ();
686 Assert.Fail ("Build failed");
690 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: One | Prop2: One;Two", "A1");
691 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Two | Prop2: One;Two", "A2");
693 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
694 } catch (AssertionException) {
695 testLogger.DumpMessages ();
701 public void TestPropertiesWithDynamicItems () {
702 string projectString = projectHeader + @"
704 <Item1 Include=""One""/>
705 <Item1 Include=""Two""/>
707 <Item2 Include=""Z""/>
708 <Item2Ref Include=""@(Item2)"" />
711 <Prop1>@(Item2)</Prop1>
712 <Prop2>@(Item2Ref)</Prop2>
715 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
716 <Message Text=""Item2: @(Item2) | Item2Ref: @(Item2Ref)""/>
717 <CreateItem Include=""A;B"">
718 <Output TaskParameter=""Include"" ItemName=""Item2""/>
720 <Message Text=""Item1: %(Item1.Identity) | Prop1: $(Prop1) | Prop2: $(Prop2)""/>
721 <Message Text=""Item2: @(Item2) | Item2Ref: @(Item2Ref)""/>
725 Engine engine = new Engine (Consts.BinPath);
726 Project project = engine.CreateNewProject ();
728 TestMessageLogger testLogger = new TestMessageLogger ();
729 engine.RegisterLogger (testLogger);
731 project.LoadXml (projectString);
732 if (!project.Build ("1")) {
734 testLogger.DumpMessages ();
735 Assert.Fail ("Build failed");
740 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: Z | Prop2: Z", "A1");
741 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Z | Prop2: Z", "A2");
742 testLogger.CheckLoggedMessageHead ("Item2: Z | Item2Ref: Z", "A3");
744 testLogger.CheckLoggedMessageHead ("Item1: One | Prop1: Z;A;B | Prop2: Z", "A4");
745 testLogger.CheckLoggedMessageHead ("Item1: Two | Prop1: Z;A;B | Prop2: Z", "A5");
746 testLogger.CheckLoggedMessageHead ("Item2: Z;A;B | Item2Ref: Z", "A3");
748 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
749 } catch (AssertionException) {
750 testLogger.DumpMessages ();
756 public void TestTargetInvocationFromBatchedTask () {
757 string projectString = projectHeader + @"
759 <Item1 Include=""One""/>
760 <Item1 Include=""Two""/>
762 <Item1Ref Include=""@(Item1)"" />
765 <Prop1>@(Item1)</Prop1>
766 <Prop2>@(Item1Ref)</Prop2>
769 <CallTarget Targets='foo' Condition="" '%(Item1.Identity)' != ''"" />
770 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
771 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
774 <Message Text=""(foo) Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
775 <Message Text=""(foo) Prop1: $(Prop1) Prop2: $(Prop2)""/>
779 Engine engine = new Engine (Consts.BinPath);
780 Project project = engine.CreateNewProject ();
782 TestMessageLogger testLogger = new TestMessageLogger ();
783 engine.RegisterLogger (testLogger);
785 project.LoadXml (projectString);
786 if (!project.Build ("1")) {
788 testLogger.DumpMessages ();
789 Assert.Fail ("Build failed");
793 testLogger.CheckLoggedMessageHead ("(foo) Item1: One;Two Item1Ref: One;Two", "A1");
794 testLogger.CheckLoggedMessageHead ("(foo) Prop1: One;Two Prop2: One;Two", "A2");
796 testLogger.CheckLoggedMessageHead ("Item1: One;Two Item1Ref: One;Two", "A3");
797 testLogger.CheckLoggedMessageHead ("Prop1: One;Two Prop2: One;Two", "A4");
799 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
800 } catch (AssertionException) {
801 testLogger.DumpMessages ();
807 public void TestTargetInvocationFromBatchedTarget () {
808 string projectString = projectHeader + @"
810 <Item1 Include=""One""/>
811 <Item1 Include=""Two""/>
813 <Item1Ref Include=""@(Item1)"" />
816 <Prop1>@(Item1)</Prop1>
817 <Prop2>@(Item1Ref)</Prop2>
819 <Target Name='1' Inputs=""%(Item1.Identity)"" Outputs=""Nonexistant.foobar"">
820 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
821 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
823 <CallTarget Targets='foo' />
825 <Message Text=""Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
826 <Message Text=""Prop1: $(Prop1) Prop2: $(Prop2)""/>
828 <Target Name='foo' Condition="" '@(Item1)' != 'One' "">
829 <Message Text=""(foo) Item1: @(Item1) Item1Ref: @(Item1Ref)""/>
830 <Message Text=""(foo) Prop1: $(Prop1) Prop2: $(Prop2)""/>
834 Engine engine = new Engine (Consts.BinPath);
835 Project project = engine.CreateNewProject ();
837 TestMessageLogger testLogger = new TestMessageLogger ();
838 engine.RegisterLogger (testLogger);
840 project.LoadXml (projectString);
841 if (!project.Build ("1")) {
843 testLogger.DumpMessages ();
844 Assert.Fail ("Build failed");
848 testLogger.CheckLoggedMessageHead ("Item1: One Item1Ref: One;Two", "A1");
849 testLogger.CheckLoggedMessageHead ("Prop1: One Prop2: One;Two", "A2");
851 testLogger.CheckLoggedMessageHead ("(foo) Item1: One;Two Item1Ref: One;Two", "A3");
852 testLogger.CheckLoggedMessageHead ("(foo) Prop1: One;Two Prop2: One;Two", "A4");
854 testLogger.CheckLoggedMessageHead ("Item1: One Item1Ref: One;Two", "A5");
855 testLogger.CheckLoggedMessageHead ("Prop1: One Prop2: One;Two", "A6");
857 //second batch, foo has already run, so doesn't execute again
858 testLogger.CheckLoggedMessageHead ("Item1: Two Item1Ref: One;Two", "A7");
859 testLogger.CheckLoggedMessageHead ("Prop1: Two Prop2: One;Two", "A8");
861 testLogger.CheckLoggedMessageHead ("Item1: Two Item1Ref: One;Two", "A9");
862 testLogger.CheckLoggedMessageHead ("Prop1: Two Prop2: One;Two", "A10");
864 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
865 } catch (AssertionException) {
866 testLogger.DumpMessages ();
872 public void TestBatchingWithUnqualifiedMetadataReference () {
873 string projectString = projectHeader + @"
875 <Item1 Include=""One""><Md>1</Md></Item1>
876 <Item1 Include=""Two""><Md>2</Md></Item1>
877 <Item1Ref Include=""@(Item1)"" />
879 <Item2 Include=""Three""><Md>3</Md></Item2>
880 <Item2 Include=""Four""><Md>4</Md></Item2>
881 <Item2Ref Include=""@(Item2)"" />
884 <Prop1>@(Item1)</Prop1>
885 <Prop1Ref>@(Item1Ref)</Prop1Ref>
887 <Prop2>@(Item2)</Prop2>
888 <Prop2Ref>@(Item2Ref)</Prop2Ref>
891 <Message Text=""For md: %(Md) Item1: @(Item1) Item1Ref: @(Item1Ref) Item2: @(Item2) Item2Ref: @(Item2Ref) " +
892 @" Prop1: $(Prop1) Prop1Ref: $(Prop1Ref) Prop2: $(Prop2) Prop2Ref: $(Prop2Ref)""/>
896 Engine engine = new Engine (Consts.BinPath);
897 Project project = engine.CreateNewProject ();
899 TestMessageLogger testLogger = new TestMessageLogger ();
900 engine.RegisterLogger (testLogger);
902 project.LoadXml (projectString);
903 if (!project.Build ("1")) {
905 testLogger.DumpMessages ();
906 Assert.Fail ("Build failed");
910 testLogger.CheckLoggedAny ("For md: 3 Item1: Item1Ref: Item2: Three Item2Ref: Three Prop1: Prop1Ref: Prop2: Three Prop2Ref: Three", MessageImportance.Normal, "A1");
911 testLogger.CheckLoggedAny ("For md: 4 Item1: Item1Ref: Item2: Four Item2Ref: Four Prop1: Prop1Ref: Prop2: Four Prop2Ref: Four", MessageImportance.Normal, "A2");
912 testLogger.CheckLoggedAny ("For md: 1 Item1: One Item1Ref: One Item2: Item2Ref: Prop1: One Prop1Ref: One Prop2: Prop2Ref: ", MessageImportance.Normal, "A3");
913 testLogger.CheckLoggedAny ("For md: 2 Item1: Two Item1Ref: Two Item2: Item2Ref: Prop1: Two Prop1Ref: Two Prop2: Prop2Ref: ", MessageImportance.Normal, "A4");
915 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
916 } catch (AssertionException) {
917 testLogger.DumpMessages ();
926 public void TestTargetBatching1 ()
928 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
930 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
931 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
932 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
933 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
935 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
936 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
938 <Foo Include=""1_a1""><Md>1</Md></Foo>
939 <Foo Include=""2_b1""><Md>2</Md></Foo>
940 <Foo Include=""1_c1""><Md>1</Md></Foo>
943 <Target Name=""foo"" >
944 <Message Text=""TargetStarted""/>
945 <Message Text=""List1: @(List1): %(Culture)""/>
946 <Message Text=""Foo: @(Foo): %(Md)""/>
950 Engine engine = new Engine (Consts.BinPath);
951 Project project = engine.CreateNewProject ();
953 TestMessageLogger testLogger = new TestMessageLogger ();
954 engine.RegisterLogger (testLogger);
956 project.LoadXml (projectString);
957 bool res = project.Build ("foo");
959 testLogger.DumpMessages ();
960 Assert.Fail ("A1: Build failed");
963 CheckLoggedMessagesInOrder (testLogger, new string [] {
964 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
965 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
966 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
968 CheckEngineEventCounts (testLogger, 1, 1, 6, 6);
972 public void TestTargetBatching2 ()
974 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
976 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
977 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
978 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
979 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
981 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
982 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
984 <Foo Include=""1_a1""><Md>1</Md></Foo>
985 <Foo Include=""2_b1""><Md>2</Md></Foo>
986 <Foo Include=""1_c1""><Md>1</Md></Foo>
989 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
990 <Message Text=""TargetStarted""/>
991 <Message Text=""List1: @(List1): %(Culture)""/>
992 <Message Text=""Foo: @(Foo): %(Md)""/>
996 Engine engine = new Engine (Consts.BinPath);
997 Project project = engine.CreateNewProject ();
999 TestMessageLogger testLogger = new TestMessageLogger ();
1000 engine.RegisterLogger (testLogger);
1002 project.LoadXml (projectString);
1003 bool res = project.Build ("foo");
1005 testLogger.DumpMessages ();
1006 Assert.Fail ("A1: Build failed");
1009 CheckLoggedMessagesInOrder (testLogger, new string [] {
1010 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1011 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1013 "TargetStarted", "List1: en_b.txt: en",
1014 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1016 "TargetStarted", "List1: gb_d.txt: gb",
1017 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1019 CheckEngineEventCounts (testLogger, 3, 3, 12, 12);
1023 public void TestTargetBatching3 ()
1025 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1027 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1028 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1029 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1030 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1032 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1033 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1035 <Foo Include=""1_a1""><Md>1</Md></Foo>
1036 <Foo Include=""2_b1""><Md>2</Md></Foo>
1037 <Foo Include=""1_c1""><Md>1</Md></Foo>
1039 <Target Name=""foo"" Inputs=""@(Foo)"" Outputs=""%(Md).foo"">
1040 <Message Text=""TargetStarted""/>
1041 <Message Text=""List1: @(List1): %(Culture)""/>
1042 <Message Text=""Foo: @(Foo): %(Md)""/>
1046 Engine engine = new Engine (Consts.BinPath);
1047 Project project = engine.CreateNewProject ();
1049 TestMessageLogger testLogger = new TestMessageLogger ();
1050 engine.RegisterLogger (testLogger);
1052 project.LoadXml (projectString);
1053 bool res = project.Build ("foo");
1055 testLogger.DumpMessages ();
1056 Assert.Fail ("A1: Build failed");
1059 CheckLoggedMessagesInOrder (testLogger, new string [] {
1060 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1061 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1062 "Foo: 1_a1;1_c1: 1",
1063 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1064 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1067 CheckEngineEventCounts (testLogger, 2, 2, 10, 10);
1071 public void TestTargetBatching4 ()
1073 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1075 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1076 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1077 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1078 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1080 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1081 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1083 <Foo Include=""1_a1""><Md>1</Md></Foo>
1084 <Foo Include=""2_b1""><Md>2</Md></Foo>
1085 <Foo Include=""1_c1""><Md>1</Md></Foo>
1087 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1088 <Message Text=""TargetStarted""/>
1089 <Message Text=""List1: @(List1): %(Culture)""/>
1090 <Message Text=""List2: @(List2): %(Culture)""/>
1091 <Message Text=""Foo: @(Foo): %(Md)""/>
1095 Engine engine = new Engine (Consts.BinPath);
1096 Project project = engine.CreateNewProject ();
1098 TestMessageLogger testLogger = new TestMessageLogger ();
1099 engine.RegisterLogger (testLogger);
1101 project.LoadXml (projectString);
1102 bool res = project.Build ("foo");
1104 testLogger.DumpMessages ();
1105 Assert.Fail ("A1: Build failed");
1108 CheckLoggedMessagesInOrder (testLogger, new string [] {
1109 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1110 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1111 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1113 "TargetStarted", "List1: en_b.txt: en",
1114 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1115 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1117 "TargetStarted", "List1: gb_d.txt: gb",
1118 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1119 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1121 CheckEngineEventCounts (testLogger, 3, 3, 18, 18);
1125 public void TestTargetBatching5 ()
1127 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1128 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1129 <Message Text=""TargetStarted""/>
1133 Engine engine = new Engine (Consts.BinPath);
1134 Project project = engine.CreateNewProject ();
1136 TestMessageLogger testLogger = new TestMessageLogger ();
1137 engine.RegisterLogger (testLogger);
1139 project.LoadXml (projectString);
1140 bool res = project.Build ("foo");
1142 testLogger.DumpMessages ();
1143 Assert.Fail ("A1: Build failed");
1145 Assert.AreEqual (1, testLogger.CheckAny ("TargetStarted", MessageImportance.Normal),
1146 "A2: Target should've been skipped because of no inputs");
1147 CheckEngineEventCounts (testLogger, 1, 1, 0, 0);
1151 public void TestTargetBatching6 ()
1153 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1155 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1156 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1157 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1158 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1160 <List3 Include=""fr_x.txt""><Culture>fr</Culture></List3>
1161 <List3 Include=""gb_z.txt""><Culture>gb</Culture></List3>
1163 <Foo Include=""1_a1""><Md>1</Md></Foo>
1164 <Foo Include=""2_b1""><Md>2</Md></Foo>
1165 <Foo Include=""1_c1""><Md>1</Md></Foo>
1168 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1169 <Message Text=""TargetStarted"" />
1170 <Message Text=""List1: %(List1.Culture), List2: %(List2.Culture)"" />
1171 <Message Text=""List2: @(List2), Culture: %(Culture)"" />
1172 <Message Text=""List3: @(List3), Culture: %(Culture)"" />
1176 Engine engine = new Engine (Consts.BinPath);
1177 Project project = engine.CreateNewProject ();
1179 TestMessageLogger testLogger = new TestMessageLogger ();
1180 engine.RegisterLogger (testLogger);
1182 project.LoadXml (projectString);
1183 bool res = project.Build ("foo");
1185 testLogger.DumpMessages ();
1186 Assert.Fail ("A1: Build failed");
1189 CheckLoggedMessagesInOrder (testLogger, new string [] {
1191 "List1: fr, List2: ",
1192 "List2: , Culture: ",
1193 "List3: fr_x.txt, Culture: fr",
1194 "List3: gb_z.txt, Culture: gb",
1197 "List1: en, List2: ",
1198 "List2: , Culture: ",
1199 "List3: fr_x.txt, Culture: fr",
1200 "List3: gb_z.txt, Culture: gb",
1203 "List1: gb, List2: ",
1204 "List2: , Culture: ",
1205 "List3: fr_x.txt, Culture: fr",
1206 "List3: gb_z.txt, Culture: gb"
1208 CheckEngineEventCounts (testLogger, 3, 3, 15, 15);
1212 public void TestTargetBatching7 ()
1214 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1216 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1217 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1218 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1219 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1221 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1222 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1224 <Foo Include=""1_a1""><Md>1</Md></Foo>
1225 <Foo Include=""2_b1""><Md>2</Md></Foo>
1226 <Foo Include=""1_c1""><Md>1</Md></Foo>
1229 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1230 <Message Text=""TargetStarted"" />
1231 <Message Text=""List1: @(List1), List2: @(List2)""/>
1235 Engine engine = new Engine (Consts.BinPath);
1236 Project project = engine.CreateNewProject ();
1238 TestMessageLogger testLogger = new TestMessageLogger ();
1239 engine.RegisterLogger (testLogger);
1241 project.LoadXml (projectString);
1242 bool res = project.Build ("foo");
1244 testLogger.DumpMessages ();
1245 Assert.Fail ("A1: Build failed");
1248 CheckLoggedMessagesInOrder (testLogger, new string [] {
1250 "List1: fr_a.txt;fr_c.txt, List2: fr_x.txt",
1253 "List1: en_b.txt, List2: ",
1256 "List1: gb_d.txt, List2: gb_z.txt"
1258 CheckEngineEventCounts (testLogger, 3, 3, 6, 6);
1261 void CheckLoggedMessagesInOrder (TestMessageLogger logger, string [] values, string prefix)
1264 for (int i = 0; i < values.Length; i++) {
1265 logger.CheckLoggedMessageHead (values [i], prefix + "#" + i);
1267 if (logger.NormalMessageCount > 0)
1268 Assert.Fail ("{0}: Expected {1} messages, but found {2}",
1269 prefix, values.Length, values.Length + logger.NormalMessageCount);
1270 } catch (NUnit.Framework.AssertionException) {
1271 logger.DumpMessages ();
1276 void CheckMessage (TestMessageLogger logger, string culture, string items, string id)
1278 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFile: {1}", culture, items), id);
1281 void CheckMessage2 (TestMessageLogger logger, string culture, string resx_files, string nonresx_files, string id)
1283 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFiles: {1} NonResXFiles: {2}", culture, resx_files, nonresx_files), id);
1286 void CheckLoggedMessageAny (TestMessageLogger logger, string expected, string id)
1288 if (logger.CheckAny (expected, MessageImportance.Normal) == 1)
1289 Assert.Fail ("{0}: Expected message '{1}' was not emitted.", id, expected);
1292 void CheckEngineEventCounts (TestMessageLogger logger, int target_start, int target_finish, int task_start, int task_finish)
1294 Assert.AreEqual (target_start, logger.TargetStarted, "TargetStarted event count doesn't match");
1295 Assert.AreEqual (target_finish, logger.TargetFinished, "TargetFinished event count doesn't match");
1296 Assert.AreEqual (task_start, logger.TaskStarted, "TaskStarted event count doesn't match");
1297 Assert.AreEqual (task_finish, logger.TaskFinished, "TaskFinished event count doesn't match");