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");
908 testLogger.DumpMessages ();
911 testLogger.CheckLoggedAny ("For md: 3 Item1: Item1Ref: Item2: Three Item2Ref: Three Prop1: Prop1Ref: Prop2: Three Prop2Ref: Three", MessageImportance.Normal, "A1");
912 testLogger.CheckLoggedAny ("For md: 4 Item1: Item1Ref: Item2: Four Item2Ref: Four Prop1: Prop1Ref: Prop2: Four Prop2Ref: Four", MessageImportance.Normal, "A2");
913 testLogger.CheckLoggedAny ("For md: 1 Item1: One Item1Ref: One Item2: Item2Ref: Prop1: One Prop1Ref: One Prop2: Prop2Ref: ", MessageImportance.Normal, "A3");
914 testLogger.CheckLoggedAny ("For md: 2 Item1: Two Item1Ref: Two Item2: Item2Ref: Prop1: Two Prop1Ref: Two Prop2: Prop2Ref: ", MessageImportance.Normal, "A4");
916 Assert.AreEqual (0, testLogger.NormalMessageCount, "Unexpected extra messages found");
917 } catch (AssertionException) {
918 testLogger.DumpMessages ();
927 public void TestTargetBatching1 ()
929 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
931 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
932 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
933 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
934 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
936 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
937 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
939 <Foo Include=""1_a1""><Md>1</Md></Foo>
940 <Foo Include=""2_b1""><Md>2</Md></Foo>
941 <Foo Include=""1_c1""><Md>1</Md></Foo>
944 <Target Name=""foo"" >
945 <Message Text=""TargetStarted""/>
946 <Message Text=""List1: @(List1): %(Culture)""/>
947 <Message Text=""Foo: @(Foo): %(Md)""/>
951 Engine engine = new Engine (Consts.BinPath);
952 Project project = engine.CreateNewProject ();
954 TestMessageLogger testLogger = new TestMessageLogger ();
955 engine.RegisterLogger (testLogger);
957 project.LoadXml (projectString);
958 bool res = project.Build ("foo");
960 testLogger.DumpMessages ();
961 Assert.Fail ("A1: Build failed");
964 CheckLoggedMessagesInOrder (testLogger, new string [] {
965 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
966 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
967 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
969 CheckEngineEventCounts (testLogger, 1, 1, 6, 6);
973 public void TestTargetBatching2 ()
975 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
977 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
978 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
979 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
980 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
982 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
983 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
985 <Foo Include=""1_a1""><Md>1</Md></Foo>
986 <Foo Include=""2_b1""><Md>2</Md></Foo>
987 <Foo Include=""1_c1""><Md>1</Md></Foo>
990 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
991 <Message Text=""TargetStarted""/>
992 <Message Text=""List1: @(List1): %(Culture)""/>
993 <Message Text=""Foo: @(Foo): %(Md)""/>
997 Engine engine = new Engine (Consts.BinPath);
998 Project project = engine.CreateNewProject ();
1000 TestMessageLogger testLogger = new TestMessageLogger ();
1001 engine.RegisterLogger (testLogger);
1003 project.LoadXml (projectString);
1004 bool res = project.Build ("foo");
1006 testLogger.DumpMessages ();
1007 Assert.Fail ("A1: Build failed");
1010 CheckLoggedMessagesInOrder (testLogger, new string [] {
1011 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1012 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1014 "TargetStarted", "List1: en_b.txt: en",
1015 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1017 "TargetStarted", "List1: gb_d.txt: gb",
1018 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1020 CheckEngineEventCounts (testLogger, 3, 3, 12, 12);
1024 public void TestTargetBatching3 ()
1026 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1028 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1029 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1030 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1031 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1033 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1034 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1036 <Foo Include=""1_a1""><Md>1</Md></Foo>
1037 <Foo Include=""2_b1""><Md>2</Md></Foo>
1038 <Foo Include=""1_c1""><Md>1</Md></Foo>
1040 <Target Name=""foo"" Inputs=""@(Foo)"" Outputs=""%(Md).foo"">
1041 <Message Text=""TargetStarted""/>
1042 <Message Text=""List1: @(List1): %(Culture)""/>
1043 <Message Text=""Foo: @(Foo): %(Md)""/>
1047 Engine engine = new Engine (Consts.BinPath);
1048 Project project = engine.CreateNewProject ();
1050 TestMessageLogger testLogger = new TestMessageLogger ();
1051 engine.RegisterLogger (testLogger);
1053 project.LoadXml (projectString);
1054 bool res = project.Build ("foo");
1056 testLogger.DumpMessages ();
1057 Assert.Fail ("A1: Build failed");
1060 CheckLoggedMessagesInOrder (testLogger, new string [] {
1061 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1062 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1063 "Foo: 1_a1;1_c1: 1",
1064 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1065 "List1: en_b.txt: en", "List1: gb_d.txt: gb",
1068 CheckEngineEventCounts (testLogger, 2, 2, 10, 10);
1072 public void TestTargetBatching4 ()
1074 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1076 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1077 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1078 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1079 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1081 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1082 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1084 <Foo Include=""1_a1""><Md>1</Md></Foo>
1085 <Foo Include=""2_b1""><Md>2</Md></Foo>
1086 <Foo Include=""1_c1""><Md>1</Md></Foo>
1088 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1089 <Message Text=""TargetStarted""/>
1090 <Message Text=""List1: @(List1): %(Culture)""/>
1091 <Message Text=""List2: @(List2): %(Culture)""/>
1092 <Message Text=""Foo: @(Foo): %(Md)""/>
1096 Engine engine = new Engine (Consts.BinPath);
1097 Project project = engine.CreateNewProject ();
1099 TestMessageLogger testLogger = new TestMessageLogger ();
1100 engine.RegisterLogger (testLogger);
1102 project.LoadXml (projectString);
1103 bool res = project.Build ("foo");
1105 testLogger.DumpMessages ();
1106 Assert.Fail ("A1: Build failed");
1109 CheckLoggedMessagesInOrder (testLogger, new string [] {
1110 "TargetStarted", "List1: fr_a.txt;fr_c.txt: fr",
1111 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1112 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1114 "TargetStarted", "List1: en_b.txt: en",
1115 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1116 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2",
1118 "TargetStarted", "List1: gb_d.txt: gb",
1119 "List2: fr_x.txt: fr", "List2: gb_z.txt: gb",
1120 "Foo: 1_a1;1_c1: 1", "Foo: 2_b1: 2"
1122 CheckEngineEventCounts (testLogger, 3, 3, 18, 18);
1126 public void TestTargetBatching5 ()
1128 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1129 <Target Name=""foo"" Inputs=""@(List1)"" Outputs=""%(Culture).foo"">
1130 <Message Text=""TargetStarted""/>
1134 Engine engine = new Engine (Consts.BinPath);
1135 Project project = engine.CreateNewProject ();
1137 TestMessageLogger testLogger = new TestMessageLogger ();
1138 engine.RegisterLogger (testLogger);
1140 project.LoadXml (projectString);
1141 bool res = project.Build ("foo");
1143 testLogger.DumpMessages ();
1144 Assert.Fail ("A1: Build failed");
1146 Assert.AreEqual (1, testLogger.CheckAny ("TargetStarted", MessageImportance.Normal),
1147 "A2: Target should've been skipped because of no inputs");
1148 CheckEngineEventCounts (testLogger, 1, 1, 0, 0);
1152 public void TestTargetBatching6 ()
1154 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1156 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1157 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1158 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1159 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1161 <List3 Include=""fr_x.txt""><Culture>fr</Culture></List3>
1162 <List3 Include=""gb_z.txt""><Culture>gb</Culture></List3>
1164 <Foo Include=""1_a1""><Md>1</Md></Foo>
1165 <Foo Include=""2_b1""><Md>2</Md></Foo>
1166 <Foo Include=""1_c1""><Md>1</Md></Foo>
1169 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1170 <Message Text=""TargetStarted"" />
1171 <Message Text=""List1: %(List1.Culture), List2: %(List2.Culture)"" />
1172 <Message Text=""List2: @(List2), Culture: %(Culture)"" />
1173 <Message Text=""List3: @(List3), Culture: %(Culture)"" />
1177 Engine engine = new Engine (Consts.BinPath);
1178 Project project = engine.CreateNewProject ();
1180 TestMessageLogger testLogger = new TestMessageLogger ();
1181 engine.RegisterLogger (testLogger);
1183 project.LoadXml (projectString);
1184 bool res = project.Build ("foo");
1186 testLogger.DumpMessages ();
1187 Assert.Fail ("A1: Build failed");
1190 CheckLoggedMessagesInOrder (testLogger, new string [] {
1192 "List1: fr, List2: ",
1193 "List2: , Culture: ",
1194 "List3: fr_x.txt, Culture: fr",
1195 "List3: gb_z.txt, Culture: gb",
1198 "List1: en, List2: ",
1199 "List2: , Culture: ",
1200 "List3: fr_x.txt, Culture: fr",
1201 "List3: gb_z.txt, Culture: gb",
1204 "List1: gb, List2: ",
1205 "List2: , Culture: ",
1206 "List3: fr_x.txt, Culture: fr",
1207 "List3: gb_z.txt, Culture: gb"
1209 CheckEngineEventCounts (testLogger, 3, 3, 15, 15);
1213 public void TestTargetBatching7 ()
1215 string projectString = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
1217 <List1 Include=""fr_a.txt""><Culture>fr</Culture></List1>
1218 <List1 Include=""en_b.txt""><Culture>en</Culture></List1>
1219 <List1 Include=""fr_c.txt""><Culture>fr</Culture></List1>
1220 <List1 Include=""gb_d.txt""><Culture>gb</Culture></List1>
1222 <List2 Include=""fr_x.txt""><Culture>fr</Culture></List2>
1223 <List2 Include=""gb_z.txt""><Culture>gb</Culture></List2>
1225 <Foo Include=""1_a1""><Md>1</Md></Foo>
1226 <Foo Include=""2_b1""><Md>2</Md></Foo>
1227 <Foo Include=""1_c1""><Md>1</Md></Foo>
1230 <Target Name=""foo"" Inputs=""@(List1);@(List2)"" Outputs=""%(Culture).foo"">
1231 <Message Text=""TargetStarted"" />
1232 <Message Text=""List1: @(List1), List2: @(List2)""/>
1236 Engine engine = new Engine (Consts.BinPath);
1237 Project project = engine.CreateNewProject ();
1239 TestMessageLogger testLogger = new TestMessageLogger ();
1240 engine.RegisterLogger (testLogger);
1242 project.LoadXml (projectString);
1243 bool res = project.Build ("foo");
1245 testLogger.DumpMessages ();
1246 Assert.Fail ("A1: Build failed");
1249 CheckLoggedMessagesInOrder (testLogger, new string [] {
1251 "List1: fr_a.txt;fr_c.txt, List2: fr_x.txt",
1254 "List1: en_b.txt, List2: ",
1257 "List1: gb_d.txt, List2: gb_z.txt"
1259 CheckEngineEventCounts (testLogger, 3, 3, 6, 6);
1262 void CheckLoggedMessagesInOrder (TestMessageLogger logger, string [] values, string prefix)
1265 for (int i = 0; i < values.Length; i++) {
1266 logger.CheckLoggedMessageHead (values [i], prefix + "#" + i);
1268 if (logger.NormalMessageCount > 0)
1269 Assert.Fail ("{0}: Expected {1} messages, but found {2}",
1270 prefix, values.Length, values.Length + logger.NormalMessageCount);
1271 } catch (NUnit.Framework.AssertionException) {
1272 logger.DumpMessages ();
1277 void CheckMessage (TestMessageLogger logger, string culture, string items, string id)
1279 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFile: {1}", culture, items), id);
1282 void CheckMessage2 (TestMessageLogger logger, string culture, string resx_files, string nonresx_files, string id)
1284 logger.CheckLoggedMessageHead (String.Format ("Culture: {0} -- ResXFiles: {1} NonResXFiles: {2}", culture, resx_files, nonresx_files), id);
1287 void CheckLoggedMessageAny (TestMessageLogger logger, string expected, string id)
1289 if (logger.CheckAny (expected, MessageImportance.Normal) == 1)
1290 Assert.Fail ("{0}: Expected message '{1}' was not emitted.", id, expected);
1293 void CheckEngineEventCounts (TestMessageLogger logger, int target_start, int target_finish, int task_start, int task_finish)
1295 Assert.AreEqual (target_start, logger.TargetStarted, "TargetStarted event count doesn't match");
1296 Assert.AreEqual (target_finish, logger.TargetFinished, "TargetFinished event count doesn't match");
1297 Assert.AreEqual (task_start, logger.TaskStarted, "TaskStarted event count doesn't match");
1298 Assert.AreEqual (task_finish, logger.TaskFinished, "TaskFinished event count doesn't match");