1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 //----------------------------------------------------------------------- 4 // </copyright> 5 // <summary>Unit tests for the task execution host object.</summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.IO; 12 using System.Linq; 13 using System.Reflection; 14 using System.Threading; 15 using System.Xml; 16 using Microsoft.Build.BackEnd; 17 using Microsoft.Build.BackEnd.Logging; 18 using Microsoft.Build.Collections; 19 using Microsoft.Build.Construction; 20 using Microsoft.Build.Evaluation; 21 using Microsoft.Build.Execution; 22 using Microsoft.Build.Framework; 23 using Microsoft.Build.Shared; 24 using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException; 25 using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; 26 using Xunit; 27 28 namespace Microsoft.Build.UnitTests.BackEnd 29 { 30 /// <summary> 31 /// The test class for the TaskExecutionHost 32 /// </summary> 33 public class TaskExecutionHost_Tests : ITestTaskHost, IBuildEngine2, IDisposable 34 { 35 /// <summary> 36 /// The set of parameters which have been initialized on the task. 37 /// </summary> 38 private Dictionary<string, object> _parametersSetOnTask; 39 40 /// <summary> 41 /// The set of outputs which were read from the task. 42 /// </summary> 43 private Dictionary<string, object> _outputsReadFromTask; 44 45 /// <summary> 46 /// The task execution host 47 /// </summary> 48 private ITaskExecutionHost _host; 49 50 /// <summary> 51 /// The mock logging service 52 /// </summary> 53 private ILoggingService _loggingService; 54 55 /// <summary> 56 /// The mock logger 57 /// </summary> 58 private MockLogger _logger; 59 60 /// <summary> 61 /// Array containing one item, used for ITaskItem tests. 62 /// </summary> 63 private ITaskItem[] _oneItem; 64 65 /// <summary> 66 /// Array containing two items, used for ITaskItem tests. 67 /// </summary> 68 private ITaskItem[] _twoItems; 69 70 /// <summary> 71 /// The bucket which receives outputs. 72 /// </summary> 73 private ItemBucket _bucket; 74 75 /// <summary> 76 /// Unused. 77 /// </summary> 78 public bool IsRunningMultipleNodes 79 { 80 get { return false; } 81 } 82 83 /// <summary> 84 /// Unused. 85 /// </summary> 86 public bool ContinueOnError 87 { 88 get { throw new NotImplementedException(); } 89 } 90 91 /// <summary> 92 /// Unused. 93 /// </summary> 94 public int LineNumberOfTaskNode 95 { 96 get { throw new NotImplementedException(); } 97 } 98 99 /// <summary> 100 /// Unused. 101 /// </summary> 102 public int ColumnNumberOfTaskNode 103 { 104 get { throw new NotImplementedException(); } 105 } 106 107 /// <summary> 108 /// Unused. 109 /// </summary> 110 public string ProjectFileOfTaskNode 111 { 112 get { throw new NotImplementedException(); } 113 } 114 115 /// <summary> 116 /// Prepares the environment for the test. 117 /// </summary> TaskExecutionHost_Tests()118 public TaskExecutionHost_Tests() 119 { 120 InitializeHost(false); 121 } 122 123 /// <summary> 124 /// Cleans up after the test 125 /// </summary> Dispose()126 public void Dispose() 127 { 128 if (_host != null) 129 { 130 ((IDisposable)_host).Dispose(); 131 } 132 133 _host = null; 134 } 135 136 /// <summary> 137 /// Validate that setting parameters with only the required parameters works. 138 /// </summary> 139 [Fact] ValidateNoParameters()140 public void ValidateNoParameters() 141 { 142 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 143 parameters["ExecuteReturnParam"] = new Tuple<string, ElementLocation>("true", ElementLocation.Create("foo.proj")); 144 145 Assert.True(_host.SetTaskParameters(parameters)); 146 Assert.Equal(1, _parametersSetOnTask.Count); 147 Assert.True(_parametersSetOnTask.ContainsKey("ExecuteReturnParam")); 148 } 149 150 /// <summary> 151 /// Validate that setting no parameters when a required parameter exists fails and throws an exception. 152 /// </summary> 153 [Fact] ValidateNoParameters_MissingRequired()154 public void ValidateNoParameters_MissingRequired() 155 { 156 Assert.Throws<InvalidProjectFileException>(() => 157 { 158 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 159 _host.SetTaskParameters(parameters); 160 } 161 ); 162 } 163 /// <summary> 164 /// Validate that setting a non-existent parameter fails, but does not throw an exception. 165 /// </summary> 166 [Fact] ValidateNonExistantParameter()167 public void ValidateNonExistantParameter() 168 { 169 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 170 parameters["NonExistantParam"] = new Tuple<string, ElementLocation>("foo", ElementLocation.Create("foo.proj")); 171 Assert.False(_host.SetTaskParameters(parameters)); 172 } 173 174 #region Bool Params 175 176 /// <summary> 177 /// Validate that setting a bool param works and sets the right value. 178 /// </summary> 179 [Fact] TestSetBoolParam()180 public void TestSetBoolParam() 181 { 182 ValidateTaskParameter("BoolParam", "true", true); 183 } 184 185 /// <summary> 186 /// Validate that setting a bool param works and sets the right value. 187 /// </summary> 188 [Fact] TestSetBoolParamFalse()189 public void TestSetBoolParamFalse() 190 { 191 ValidateTaskParameter("BoolParam", "false", false); 192 } 193 194 /// <summary> 195 /// Validate that setting a bool param with an empty value does not cause the parameter to get set. 196 /// </summary> 197 [Fact] TestSetBoolParamEmptyAttribute()198 public void TestSetBoolParamEmptyAttribute() 199 { 200 ValidateTaskParameterNotSet("BoolParam", ""); 201 } 202 203 /// <summary> 204 /// Validate that setting a bool param with a property which evaluates to nothing does not cause the parameter to get set. 205 /// </summary> 206 [Fact] TestSetBoolParamEmptyProperty()207 public void TestSetBoolParamEmptyProperty() 208 { 209 ValidateTaskParameterNotSet("BoolParam", "$(NonExistantProperty)"); 210 } 211 212 /// <summary> 213 /// Validate that setting a bool param with an item which evaluates to nothing does not cause the parameter to get set. 214 /// </summary> 215 [Fact] TestSetBoolParamEmptyItem()216 public void TestSetBoolParamEmptyItem() 217 { 218 ValidateTaskParameterNotSet("BoolParam", "@(NonExistantItem)"); 219 } 220 221 #endregion 222 223 #region Bool Array Params 224 225 /// <summary> 226 /// Validate that setting a bool array with a single true sets the array to one 'true' value. 227 /// </summary> 228 [Fact] TestSetBoolArrayParamOneItem()229 public void TestSetBoolArrayParamOneItem() 230 { 231 ValidateTaskParameterArray("BoolArrayParam", "true", new bool[] { true }); 232 } 233 234 /// <summary> 235 /// Validate that setting a bool array with a list of two values sets them appropriately. 236 /// </summary> 237 [Fact] TestSetBoolArrayParamTwoItems()238 public void TestSetBoolArrayParamTwoItems() 239 { 240 ValidateTaskParameterArray("BoolArrayParam", "false;true", new bool[] { false, true }); 241 } 242 243 /// <summary> 244 /// Validate that setting the parameter with an empty value does not cause it to be set. 245 /// </summary> 246 [Fact] TestSetBoolArrayParamEmptyAttribute()247 public void TestSetBoolArrayParamEmptyAttribute() 248 { 249 ValidateTaskParameterNotSet("BoolArrayParam", ""); 250 } 251 252 /// <summary> 253 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 254 /// </summary> 255 [Fact] TestSetBoolArrayParamEmptyProperty()256 public void TestSetBoolArrayParamEmptyProperty() 257 { 258 ValidateTaskParameterNotSet("BoolArrayParam", "$(NonExistantProperty)"); 259 } 260 261 /// <summary> 262 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 263 /// </summary> 264 [Fact] TestSetBoolArrayParamEmptyItem()265 public void TestSetBoolArrayParamEmptyItem() 266 { 267 ValidateTaskParameterNotSet("BoolArrayParam", "@(NonExistantItem)"); 268 } 269 270 #endregion 271 272 #region Int Params 273 274 /// <summary> 275 /// Validate that setting an int param with a value of 0 causes it to get the correct value. 276 /// </summary> 277 [Fact] TestSetIntParamZero()278 public void TestSetIntParamZero() 279 { 280 ValidateTaskParameter("IntParam", "0", 0); 281 } 282 283 /// <summary> 284 /// Validate that setting an int param with a value of 1 causes it to get the correct value. 285 /// </summary> 286 [Fact] TestSetIntParamOne()287 public void TestSetIntParamOne() 288 { 289 ValidateTaskParameter("IntParam", "1", 1); 290 } 291 292 /// <summary> 293 /// Validate that setting the parameter with an empty value does not cause it to be set. 294 /// </summary> 295 [Fact] TestSetIntParamEmptyAttribute()296 public void TestSetIntParamEmptyAttribute() 297 { 298 ValidateTaskParameterNotSet("IntParam", ""); 299 } 300 301 /// <summary> 302 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 303 /// </summary> 304 [Fact] TestSetIntParamEmptyProperty()305 public void TestSetIntParamEmptyProperty() 306 { 307 ValidateTaskParameterNotSet("IntParam", "$(NonExistantProperty)"); 308 } 309 310 /// <summary> 311 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 312 /// </summary> 313 [Fact] TestSetIntParamEmptyItem()314 public void TestSetIntParamEmptyItem() 315 { 316 ValidateTaskParameterNotSet("IntParam", "@(NonExistantItem)"); 317 } 318 319 #endregion 320 321 #region Int Array Params 322 323 /// <summary> 324 /// Validate that setting an int array with a single value causes it to get a single value. 325 /// </summary> 326 [Fact] TestSetIntArrayParamOneItem()327 public void TestSetIntArrayParamOneItem() 328 { 329 ValidateTaskParameterArray("IntArrayParam", "0", new int[] { 0 }); 330 } 331 332 /// <summary> 333 /// Validate that setting an int array with a list of values causes it to get the correct values. 334 /// </summary> 335 [Fact] TestSetIntArrayParamTwoItems()336 public void TestSetIntArrayParamTwoItems() 337 { 338 SetTaskParameter("IntArrayParam", "1;0"); 339 340 Assert.True(_parametersSetOnTask.ContainsKey("IntArrayParam")); 341 342 Assert.Equal(1, ((int[])_parametersSetOnTask["IntArrayParam"])[0]); 343 Assert.Equal(0, ((int[])_parametersSetOnTask["IntArrayParam"])[1]); 344 } 345 346 /// <summary> 347 /// Validate that setting the parameter with an empty value does not cause it to be set. 348 /// </summary> 349 [Fact] TestSetIntArrayParamEmptyAttribute()350 public void TestSetIntArrayParamEmptyAttribute() 351 { 352 ValidateTaskParameterNotSet("IntArrayParam", ""); 353 } 354 355 /// <summary> 356 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 357 /// </summary> 358 [Fact] TestSetIntArrayParamEmptyProperty()359 public void TestSetIntArrayParamEmptyProperty() 360 { 361 ValidateTaskParameterNotSet("IntArrayParam", "$(NonExistantProperty)"); 362 } 363 364 /// <summary> 365 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 366 /// </summary> 367 [Fact] TestSetIntArrayParamEmptyItem()368 public void TestSetIntArrayParamEmptyItem() 369 { 370 ValidateTaskParameterNotSet("IntArrayParam", "@(NonExistantItem)"); 371 } 372 373 #endregion 374 375 #region String Params 376 377 /// <summary> 378 /// Test that setting a string param sets the correct value. 379 /// </summary> 380 [Fact] TestSetStringParam()381 public void TestSetStringParam() 382 { 383 ValidateTaskParameter("StringParam", "0", "0"); 384 } 385 386 /// <summary> 387 /// Test that setting a string param sets the correct value. 388 /// </summary> 389 [Fact] TestSetStringParamOne()390 public void TestSetStringParamOne() 391 { 392 ValidateTaskParameter("StringParam", "1", "1"); 393 } 394 395 /// <summary> 396 /// Validate that setting the parameter with an empty value does not cause it to be set. 397 /// </summary> 398 [Fact] TestSetStringParamEmptyAttribute()399 public void TestSetStringParamEmptyAttribute() 400 { 401 ValidateTaskParameterNotSet("StringParam", ""); 402 } 403 404 /// <summary> 405 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 406 /// </summary> 407 [Fact] TestSetStringParamEmptyProperty()408 public void TestSetStringParamEmptyProperty() 409 { 410 ValidateTaskParameterNotSet("StringParam", "$(NonExistantProperty)"); 411 } 412 413 /// <summary> 414 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 415 /// </summary> 416 [Fact] TestSetStringParamEmptyItem()417 public void TestSetStringParamEmptyItem() 418 { 419 ValidateTaskParameterNotSet("StringParam", "@(NonExistantItem)"); 420 } 421 422 #endregion 423 424 #region String Array Params 425 426 /// <summary> 427 /// Validate that setting a string array with a single value sets the correct value. 428 /// </summary> 429 [Fact] TestSetStringArrayParam()430 public void TestSetStringArrayParam() 431 { 432 ValidateTaskParameterArray("StringArrayParam", "0", new string[] { "0" }); 433 } 434 435 /// <summary> 436 /// Validate that setting a string array with a list of two values sets the correct values. 437 /// </summary> 438 [Fact] TestSetStringArrayParamOne()439 public void TestSetStringArrayParamOne() 440 { 441 ValidateTaskParameterArray("StringArrayParam", "1;0", new string[] { "1", "0" }); 442 } 443 444 /// <summary> 445 /// Validate that setting the parameter with an empty value does not cause it to be set. 446 /// </summary> 447 [Fact] TestSetStringArrayParamEmptyAttribute()448 public void TestSetStringArrayParamEmptyAttribute() 449 { 450 ValidateTaskParameterNotSet("StringArrayParam", ""); 451 } 452 453 /// <summary> 454 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 455 /// </summary> 456 [Fact] TestSetStringArrayParamEmptyProperty()457 public void TestSetStringArrayParamEmptyProperty() 458 { 459 ValidateTaskParameterNotSet("StringArrayParam", "$(NonExistantProperty)"); 460 } 461 462 /// <summary> 463 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 464 /// </summary> 465 [Fact] TestSetStringArrayParamEmptyItem()466 public void TestSetStringArrayParamEmptyItem() 467 { 468 ValidateTaskParameterNotSet("StringArrayParam", "@(NonExistantItem)"); 469 } 470 471 #endregion 472 473 #region ITaskItem Params 474 475 /// <summary> 476 /// Validate that setting an item with an item list evaluating to one item sets the value appropriately, including metadata. 477 /// </summary> 478 [Fact] TestSetItemParamSingle()479 public void TestSetItemParamSingle() 480 { 481 ValidateTaskParameterItem("ItemParam", "@(ItemListContainingOneItem)", _oneItem[0]); 482 } 483 484 /// <summary> 485 /// Validate that setting an item with an item list evaluating to two items sets the value appropriately, including metadata. 486 /// </summary> 487 [Fact] TestSetItemParamDouble()488 public void TestSetItemParamDouble() 489 { 490 Assert.Throws<InvalidProjectFileException>(() => 491 { 492 ValidateTaskParameterItems("ItemParam", "@(ItemListContainingTwoItems)", _twoItems); 493 } 494 ); 495 } 496 /// <summary> 497 /// Validate that setting an item with a string results in an item with the evaluated include set to the string. 498 /// </summary> 499 [Fact] TestSetItemParamString()500 public void TestSetItemParamString() 501 { 502 ValidateTaskParameterItem("ItemParam", "MyItemName"); 503 } 504 505 /// <summary> 506 /// Validate that setting the parameter with an empty value does not cause it to be set. 507 /// </summary> 508 [Fact] TestSetItemParamEmptyAttribute()509 public void TestSetItemParamEmptyAttribute() 510 { 511 ValidateTaskParameterNotSet("ItemParam", ""); 512 } 513 514 /// <summary> 515 /// Validate that setting the parameter with a property which evaluates to an empty value does not cause it to be set. 516 /// </summary> 517 [Fact] TestSetItemParamEmptyProperty()518 public void TestSetItemParamEmptyProperty() 519 { 520 ValidateTaskParameterNotSet("ItemParam", "$(NonExistantProperty)"); 521 } 522 523 /// <summary> 524 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 525 /// </summary> 526 [Fact] TestSetItemParamEmptyItem()527 public void TestSetItemParamEmptyItem() 528 { 529 ValidateTaskParameterNotSet("ItemParam", "@(NonExistantItem)"); 530 } 531 532 #endregion 533 534 #region ITaskItem Array Params 535 536 /// <summary> 537 /// Validate that setting an item array using an item list containing one item sets a single item. 538 /// </summary> 539 [Fact] TestSetItemArrayParamSingle()540 public void TestSetItemArrayParamSingle() 541 { 542 ValidateTaskParameterItems("ItemArrayParam", "@(ItemListContainingOneItem)", _oneItem); 543 } 544 545 /// <summary> 546 /// Validate that setting an item array using an item list containing two items sets both items. 547 /// </summary> 548 [Fact] TestSetItemArrayParamDouble()549 public void TestSetItemArrayParamDouble() 550 { 551 ValidateTaskParameterItems("ItemArrayParam", "@(ItemListContainingTwoItems)", _twoItems); 552 } 553 554 /// <summary> 555 /// Validate that setting an item array with 556 /// </summary> 557 [Fact] TestSetItemArrayParamString()558 public void TestSetItemArrayParamString() 559 { 560 ValidateTaskParameterItems("ItemArrayParam", "MyItemName"); 561 } 562 563 /// <summary> 564 /// Validate that setting an item array with a list with multiple values creates multiple items. 565 /// </summary> 566 [Fact] TestSetItemArrayParamTwoStrings()567 public void TestSetItemArrayParamTwoStrings() 568 { 569 ValidateTaskParameterItems("ItemArrayParam", "MyItemName;MyOtherItemName", new string[] { "MyItemName", "MyOtherItemName" }); 570 } 571 572 /// <summary> 573 /// Validate that setting the parameter with an empty value does not cause it to be set. 574 /// </summary> 575 [Fact] TestSetItemArrayParamEmptyAttribute()576 public void TestSetItemArrayParamEmptyAttribute() 577 { 578 ValidateTaskParameterNotSet("ItemArrayParam", ""); 579 } 580 581 /// <summary> 582 /// Validate that setting the parameter with a parameter which evaluates to an empty value does not cause it to be set. 583 /// </summary> 584 [Fact] TestSetItemArrayParamEmptyProperty()585 public void TestSetItemArrayParamEmptyProperty() 586 { 587 ValidateTaskParameterNotSet("ItemArrayParam", "$(NonExistantProperty)"); 588 } 589 590 /// <summary> 591 /// Validate that setting the parameter with an item which evaluates to an empty value does not cause it to be set. 592 /// </summary> 593 [Fact] TestSetItemArrayParamEmptyItem()594 public void TestSetItemArrayParamEmptyItem() 595 { 596 ValidateTaskParameterNotSet("ItemArrayParam", "@(NonExistantItem)"); 597 } 598 599 #endregion 600 601 #region Execute Tests 602 603 /// <summary> 604 /// Tests that successful execution returns true. 605 /// </summary> 606 [Fact] TestExecuteTrue()607 public void TestExecuteTrue() 608 { 609 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 610 parameters["ExecuteReturnParam"] = new Tuple<string, ElementLocation>("true", ElementLocation.Create("foo.proj")); 611 612 Assert.True(_host.SetTaskParameters(parameters)); 613 614 bool executeValue = _host.Execute(); 615 616 Assert.Equal(true, executeValue); 617 } 618 619 /// <summary> 620 /// Tests that unsuccessful execution returns false. 621 /// </summary> 622 [Fact] TestExecuteFalse()623 public void TestExecuteFalse() 624 { 625 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 626 parameters["ExecuteReturnParam"] = new Tuple<string, ElementLocation>("false", ElementLocation.Create("foo.proj")); 627 628 Assert.True(_host.SetTaskParameters(parameters)); 629 630 bool executeValue = _host.Execute(); 631 632 Assert.Equal(false, executeValue); 633 } 634 635 /// <summary> 636 /// Tests that when Execute throws, the exception bubbles up. 637 /// </summary> 638 [Fact] TestExecuteThrow()639 public void TestExecuteThrow() 640 { 641 Assert.Throws<IndexOutOfRangeException>(() => 642 { 643 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 644 parameters["ExecuteReturnParam"] = new Tuple<string, ElementLocation>("false", ElementLocation.Create("foo.proj")); 645 646 Dispose(); 647 InitializeHost(true); 648 649 Assert.True(_host.SetTaskParameters(parameters)); 650 651 bool executeValue = _host.Execute(); 652 } 653 ); 654 } 655 #endregion 656 657 #region Bool Outputs 658 659 /// <summary> 660 /// Validate that boolean output to an item produces the correct evaluated include. 661 /// </summary> 662 [Fact] TestOutputBoolToItem()663 public void TestOutputBoolToItem() 664 { 665 SetTaskParameter("BoolParam", "true"); 666 ValidateOutputItem("BoolOutput", "True"); 667 } 668 669 /// <summary> 670 /// Validate that boolean output to a property produces the correct evaluated value. 671 /// </summary> 672 [Fact] TestOutputBoolToProperty()673 public void TestOutputBoolToProperty() 674 { 675 SetTaskParameter("BoolParam", "true"); 676 ValidateOutputProperty("BoolOutput", "True"); 677 } 678 679 /// <summary> 680 /// Validate that boolean array output to an item array produces the correct evaluated includes. 681 /// </summary> 682 [Fact] TestOutputBoolArrayToItems()683 public void TestOutputBoolArrayToItems() 684 { 685 SetTaskParameter("BoolArrayParam", "false;true"); 686 ValidateOutputItems("BoolArrayOutput", new string[] { "False", "True" }); 687 } 688 689 /// <summary> 690 /// Validate that boolean array output to an item produces the correct semi-colon-delimited evaluated value. 691 /// </summary> 692 [Fact] TestOutputBoolArrayToProperty()693 public void TestOutputBoolArrayToProperty() 694 { 695 SetTaskParameter("BoolArrayParam", "false;true"); 696 ValidateOutputProperty("BoolArrayOutput", "False;True"); 697 } 698 699 #endregion 700 701 #region Int Outputs 702 703 /// <summary> 704 /// Validate that an int output to an item produces the correct evaluated include 705 /// </summary> 706 [Fact] TestOutputIntToItem()707 public void TestOutputIntToItem() 708 { 709 SetTaskParameter("IntParam", "42"); 710 ValidateOutputItem("IntOutput", "42"); 711 } 712 713 /// <summary> 714 /// Validate that an int output to an property produces the correct evaluated value. 715 /// </summary> 716 [Fact] TestOutputIntToProperty()717 public void TestOutputIntToProperty() 718 { 719 SetTaskParameter("IntParam", "42"); 720 ValidateOutputProperty("IntOutput", "42"); 721 } 722 723 /// <summary> 724 /// Validate that an int array output to an item produces the correct evaluated includes. 725 /// </summary> 726 [Fact] TestOutputIntArrayToItems()727 public void TestOutputIntArrayToItems() 728 { 729 SetTaskParameter("IntArrayParam", "42;99"); 730 ValidateOutputItems("IntArrayOutput", new string[] { "42", "99" }); 731 } 732 733 /// <summary> 734 /// Validate that an int array output to a property produces the correct semi-colon-delimited evaluated value. 735 /// </summary> 736 [Fact] TestOutputIntArrayToProperty()737 public void TestOutputIntArrayToProperty() 738 { 739 SetTaskParameter("IntArrayParam", "42;99"); 740 ValidateOutputProperty("IntArrayOutput", "42;99"); 741 } 742 743 #endregion 744 745 #region String Outputs 746 747 /// <summary> 748 /// Validate that a string output to an item produces the correct evaluated include. 749 /// </summary> 750 [Fact] TestOutputStringToItem()751 public void TestOutputStringToItem() 752 { 753 SetTaskParameter("StringParam", "FOO"); 754 ValidateOutputItem("StringOutput", "FOO"); 755 } 756 757 /// <summary> 758 /// Validate that a string output to a property produces the correct evaluated value. 759 /// </summary> 760 [Fact] TestOutputStringToProperty()761 public void TestOutputStringToProperty() 762 { 763 SetTaskParameter("StringParam", "FOO"); 764 ValidateOutputProperty("StringOutput", "FOO"); 765 } 766 767 /// <summary> 768 /// Validate that an empty string output overwrites the property value 769 /// </summary> 770 [Fact] TestOutputEmptyStringToProperty()771 public void TestOutputEmptyStringToProperty() 772 { 773 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 774 ValidateOutputProperty("EmptyStringOutput", String.Empty); 775 } 776 777 /// <summary> 778 /// Validate that an empty string array output overwrites the property value 779 /// </summary> 780 [Fact] TestOutputEmptyStringArrayToProperty()781 public void TestOutputEmptyStringArrayToProperty() 782 { 783 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 784 ValidateOutputProperty("EmptyStringArrayOutput", String.Empty); 785 } 786 787 /// <summary> 788 /// A string output returning null should not cause any property set. 789 /// </summary> 790 [Fact] TestOutputNullStringToProperty()791 public void TestOutputNullStringToProperty() 792 { 793 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 794 ValidateOutputProperty("NullStringOutput", "initialvalue"); 795 } 796 797 /// <summary> 798 /// A string output returning null should not cause any property set. 799 /// </summary> 800 [Fact] TestOutputNullITaskItemToProperty()801 public void TestOutputNullITaskItemToProperty() 802 { 803 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 804 ValidateOutputProperty("NullITaskItemOutput", "initialvalue"); 805 } 806 807 /// <summary> 808 /// A string output returning null should not cause any property set. 809 /// </summary> 810 [Fact] TestOutputNullStringArrayToProperty()811 public void TestOutputNullStringArrayToProperty() 812 { 813 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 814 ValidateOutputProperty("NullStringArrayOutput", "initialvalue"); 815 } 816 817 /// <summary> 818 /// A string output returning null should not cause any property set. 819 /// </summary> 820 [Fact] TestOutputNullITaskItemArrayToProperty()821 public void TestOutputNullITaskItemArrayToProperty() 822 { 823 _bucket.Lookup.SetProperty(ProjectPropertyInstance.Create("output", "initialvalue")); 824 ValidateOutputProperty("NullITaskItemArrayOutput", "initialvalue"); 825 } 826 827 /// <summary> 828 /// Validate that a string array output to an item produces the correct evaluated includes. 829 /// </summary> 830 [Fact] TestOutputStringArrayToItems()831 public void TestOutputStringArrayToItems() 832 { 833 SetTaskParameter("StringArrayParam", "FOO;bar"); 834 ValidateOutputItems("StringArrayOutput", new string[] { "FOO", "bar" }); 835 } 836 837 /// <summary> 838 /// Validate that a string array output to a property produces the correct semi-colon-delimited evaluated value. 839 /// </summary> 840 [Fact] TestOutputStringArrayToProperty()841 public void TestOutputStringArrayToProperty() 842 { 843 SetTaskParameter("StringArrayParam", "FOO;bar"); 844 ValidateOutputProperty("StringArrayOutput", "FOO;bar"); 845 } 846 847 #endregion 848 849 #region Item Outputs 850 851 /// <summary> 852 /// Validate that an item output to an item replicates the item, with metadata 853 /// </summary> 854 [Fact] TestOutputItemToItem()855 public void TestOutputItemToItem() 856 { 857 SetTaskParameter("ItemParam", "@(ItemListContainingOneItem)"); 858 ValidateOutputItems("ItemOutput", _oneItem); 859 } 860 861 /// <summary> 862 /// Validate than an item output to a property produces the correct evaluated value. 863 /// </summary> 864 [Fact] TestOutputItemToProperty()865 public void TestOutputItemToProperty() 866 { 867 SetTaskParameter("ItemParam", "@(ItemListContainingOneItem)"); 868 ValidateOutputProperty("ItemOutput", _oneItem[0].ItemSpec); 869 } 870 871 /// <summary> 872 /// Validate that an item array output to an item replicates the items, with metadata. 873 /// </summary> 874 [Fact] TestOutputItemArrayToItems()875 public void TestOutputItemArrayToItems() 876 { 877 SetTaskParameter("ItemArrayParam", "@(ItemListContainingTwoItems)"); 878 ValidateOutputItems("ItemArrayOutput", _twoItems); 879 } 880 881 /// <summary> 882 /// Validate that an item array output to a property produces the correct semi-colon-delimited evaluated value. 883 /// </summary> 884 [Fact] TestOutputItemArrayToProperty()885 public void TestOutputItemArrayToProperty() 886 { 887 SetTaskParameter("ItemArrayParam", "@(ItemListContainingTwoItems)"); 888 ValidateOutputProperty("ItemArrayOutput", String.Concat(_twoItems[0].ItemSpec, ";", _twoItems[1].ItemSpec)); 889 } 890 891 #endregion 892 893 #region Other Output Tests 894 895 /// <summary> 896 /// Attempts to gather outputs into an item list from an string task parameter that 897 /// returns an empty string. This should be a no-op. 898 /// </summary> 899 [Fact] TestEmptyStringInStringArrayParameterIntoItemList()900 public void TestEmptyStringInStringArrayParameterIntoItemList() 901 { 902 SetTaskParameter("StringArrayParam", ""); 903 ValidateOutputItems("StringArrayOutput", new ITaskItem[] { }); 904 } 905 906 /// <summary> 907 /// Attempts to gather outputs into an item list from an string task parameter that 908 /// returns an empty string. This should be a no-op. 909 /// </summary> 910 [Fact] TestEmptyStringParameterIntoItemList()911 public void TestEmptyStringParameterIntoItemList() 912 { 913 SetTaskParameter("StringParam", ""); 914 ValidateOutputItems("StringOutput", new ITaskItem[] { }); 915 } 916 917 /// <summary> 918 /// Attempts to gather outputs from a null task parameter of type "ITaskItem[]". This should succeed. 919 /// </summary> 920 [Fact] TestNullITaskItemArrayParameter()921 public void TestNullITaskItemArrayParameter() 922 { 923 ValidateOutputItems("ItemArrayNullOutput", new ITaskItem[] { }); 924 } 925 926 /// <summary> 927 /// Attempts to gather outputs from a task parameter of type "ArrayList". This should fail. 928 /// </summary> 929 [Fact] TestArrayListParameter()930 public void TestArrayListParameter() 931 { 932 Assert.Throws<InvalidProjectFileException>(() => 933 { 934 ValidateOutputItems("ArrayListOutput", new ITaskItem[] { }); 935 } 936 ); 937 } 938 /// <summary> 939 /// Attempts to gather outputs from a non-existent output. This should fail. 940 /// </summary> 941 [Fact] TestNonexistantOutput()942 public void TestNonexistantOutput() 943 { 944 Assert.Throws<InvalidProjectFileException>(() => 945 { 946 Assert.False(_host.GatherTaskOutputs("NonExistantOutput", ElementLocation.Create(".", 1, 1), true, "output")); 947 } 948 ); 949 } 950 /// <summary> 951 /// object[] should not be a supported output type. 952 /// </summary> 953 [Fact] TestOutputObjectArrayToProperty()954 public void TestOutputObjectArrayToProperty() 955 { 956 Assert.Throws<InvalidProjectFileException>(() => 957 { 958 ValidateOutputProperty("ObjectArrayOutput", ""); 959 } 960 ); 961 } 962 #endregion 963 964 #region Other Tests 965 966 /// <summary> 967 /// Test that cleanup for task clears out the task instance. 968 /// </summary> 969 [Fact] TestCleanupForTask()970 public void TestCleanupForTask() 971 { 972 _host.CleanupForBatch(); 973 Assert.NotNull((_host as TaskExecutionHost)._UNITTESTONLY_TaskFactoryWrapper); 974 _host.CleanupForTask(); 975 Assert.Null((_host as TaskExecutionHost)._UNITTESTONLY_TaskFactoryWrapper); 976 } 977 978 /// <summary> 979 /// Test that a using task which specifies an invalid assembly produces an exception. 980 /// </summary> 981 [Fact] TestTaskResolutionFailureWithUsingTask()982 public void TestTaskResolutionFailureWithUsingTask() 983 { 984 Assert.Throws<InvalidProjectFileException>(() => 985 { 986 _loggingService = new MockLoggingService(); 987 Dispose(); 988 _host = new TaskExecutionHost(); 989 TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); 990 991 ProjectInstance project = CreateTestProject(); 992 _host.InitializeForTask 993 ( 994 this, 995 tlc, 996 project, 997 "TaskWithMissingAssembly", 998 ElementLocation.Create("none", 1, 1), 999 this, 1000 false, 1001 #if FEATURE_APPDOMAIN 1002 null, 1003 #endif 1004 false, 1005 CancellationToken.None 1006 ); 1007 _host.FindTask(null); 1008 _host.InitializeForBatch(new TaskLoggingContext(_loggingService, tlc.BuildEventContext), _bucket, null); 1009 } 1010 ); 1011 } 1012 /// <summary> 1013 /// Test that specifying a task with no using task logs an error, but does not throw. 1014 /// </summary> 1015 [Fact] TestTaskResolutionFailureWithNoUsingTask()1016 public void TestTaskResolutionFailureWithNoUsingTask() 1017 { 1018 Dispose(); 1019 _host = new TaskExecutionHost(); 1020 TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); 1021 1022 ProjectInstance project = CreateTestProject(); 1023 _host.InitializeForTask 1024 ( 1025 this, 1026 tlc, 1027 project, 1028 "TaskWithNoUsingTask", 1029 ElementLocation.Create("none", 1, 1), 1030 this, 1031 false, 1032 #if FEATURE_APPDOMAIN 1033 null, 1034 #endif 1035 false, 1036 CancellationToken.None 1037 ); 1038 1039 _host.FindTask(null); 1040 _host.InitializeForBatch(new TaskLoggingContext(_loggingService, tlc.BuildEventContext), _bucket, null); 1041 _logger.AssertLogContains("MSB4036"); 1042 } 1043 1044 #endregion 1045 1046 #region ITestTaskHost Members 1047 1048 /// <summary> 1049 /// Records that a parameter was set on the task. 1050 /// </summary> ParameterSet(string parameterName, object valueSet)1051 public void ParameterSet(string parameterName, object valueSet) 1052 { 1053 _parametersSetOnTask[parameterName] = valueSet; 1054 } 1055 1056 /// <summary> 1057 /// Records that an output was read from the task. 1058 /// </summary> OutputRead(string parameterName, object actualValue)1059 public void OutputRead(string parameterName, object actualValue) 1060 { 1061 _outputsReadFromTask[parameterName] = actualValue; 1062 } 1063 1064 #endregion 1065 1066 #region IBuildEngine2 Members 1067 1068 /// <summary> 1069 /// Unused. 1070 /// </summary> BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs, string toolsVersion)1071 public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs, string toolsVersion) 1072 { 1073 throw new NotImplementedException(); 1074 } 1075 1076 /// <summary> 1077 /// Unused. 1078 /// </summary> BuildProjectFilesInParallel(string[] projectFileNames, string[] targetNames, IDictionary[] globalProperties, IDictionary[] targetOutputsPerProject, string[] toolsVersion, bool useResultsCache, bool unloadProjectsOnCompletion)1079 public bool BuildProjectFilesInParallel(string[] projectFileNames, string[] targetNames, IDictionary[] globalProperties, IDictionary[] targetOutputsPerProject, string[] toolsVersion, bool useResultsCache, bool unloadProjectsOnCompletion) 1080 { 1081 throw new NotImplementedException(); 1082 } 1083 1084 #endregion 1085 1086 #region IBuildEngine Members 1087 1088 /// <summary> 1089 /// Unused. 1090 /// </summary> LogErrorEvent(BuildErrorEventArgs e)1091 public void LogErrorEvent(BuildErrorEventArgs e) 1092 { 1093 throw new NotImplementedException(); 1094 } 1095 1096 /// <summary> 1097 /// Unused. 1098 /// </summary> LogWarningEvent(BuildWarningEventArgs e)1099 public void LogWarningEvent(BuildWarningEventArgs e) 1100 { 1101 throw new NotImplementedException(); 1102 } 1103 1104 /// <summary> 1105 /// Unused. 1106 /// </summary> LogMessageEvent(BuildMessageEventArgs e)1107 public void LogMessageEvent(BuildMessageEventArgs e) 1108 { 1109 throw new NotImplementedException(); 1110 } 1111 1112 /// <summary> 1113 /// Unused. 1114 /// </summary> LogCustomEvent(CustomBuildEventArgs e)1115 public void LogCustomEvent(CustomBuildEventArgs e) 1116 { 1117 throw new NotImplementedException(); 1118 } 1119 1120 /// <summary> 1121 /// Unused. 1122 /// </summary> BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs)1123 public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) 1124 { 1125 throw new NotImplementedException(); 1126 } 1127 1128 #endregion 1129 1130 #region Validation Routines 1131 1132 /// <summary> 1133 /// Is the class a task factory 1134 /// </summary> IsTaskFactoryClass(Type type, object unused)1135 private static bool IsTaskFactoryClass(Type type, object unused) 1136 { 1137 return (type.GetTypeInfo().IsClass && 1138 !type.GetTypeInfo().IsAbstract && 1139 #if FEATURE_TYPE_GETINTERFACE 1140 (type.GetInterface("Microsoft.Build.Framework.ITaskFactory") != null)); 1141 #else 1142 type.GetInterfaces().Any(interfaceType => interfaceType.FullName == "Microsoft.Build.Framework.ITaskFactory")); 1143 #endif 1144 } 1145 1146 /// <summary> 1147 /// Initialize the host object 1148 /// </summary> 1149 /// <param name="throwOnExecute">Should the task throw when executed</param> InitializeHost(bool throwOnExecute)1150 private void InitializeHost(bool throwOnExecute) 1151 { 1152 _loggingService = LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); 1153 _logger = new MockLogger(); 1154 _loggingService.RegisterLogger(_logger); 1155 _host = new TaskExecutionHost(); 1156 TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); 1157 1158 // Set up a temporary project and add some items to it. 1159 ProjectInstance project = CreateTestProject(); 1160 1161 TypeLoader typeLoader = new TypeLoader(IsTaskFactoryClass); 1162 #if FEATURE_ASSEMBLY_LOADFROM 1163 AssemblyLoadInfo loadInfo = AssemblyLoadInfo.Create(Assembly.GetAssembly(typeof(TaskBuilderTestTask.TaskBuilderTestTaskFactory)).FullName, null); 1164 #else 1165 AssemblyLoadInfo loadInfo = AssemblyLoadInfo.Create(typeof(TaskBuilderTestTask.TaskBuilderTestTaskFactory).GetTypeInfo().FullName, null); 1166 #endif 1167 LoadedType loadedType = new LoadedType(typeof(TaskBuilderTestTask.TaskBuilderTestTaskFactory), loadInfo); 1168 1169 TaskBuilderTestTask.TaskBuilderTestTaskFactory taskFactory = new TaskBuilderTestTask.TaskBuilderTestTaskFactory(); 1170 taskFactory.ThrowOnExecute = throwOnExecute; 1171 string taskName = "TaskBuilderTestTask"; 1172 (_host as TaskExecutionHost)._UNITTESTONLY_TaskFactoryWrapper = new TaskFactoryWrapper(taskFactory, loadedType, taskName, null); 1173 _host.InitializeForTask 1174 ( 1175 this, 1176 tlc, 1177 project, 1178 taskName, 1179 ElementLocation.Create("none", 1, 1), 1180 this, 1181 false, 1182 #if FEATURE_APPDOMAIN 1183 null, 1184 #endif 1185 false, 1186 CancellationToken.None 1187 ); 1188 1189 ProjectTaskInstance taskInstance = project.Targets["foo"].Tasks.First(); 1190 TaskLoggingContext talc = tlc.LogTaskBatchStarted(".", taskInstance); 1191 1192 ItemDictionary<ProjectItemInstance> itemsByName = new ItemDictionary<ProjectItemInstance>(); 1193 1194 ProjectItemInstance item = new ProjectItemInstance(project, "ItemListContainingOneItem", "a.cs", "."); 1195 item.SetMetadata("Culture", "fr-fr"); 1196 itemsByName.Add(item); 1197 _oneItem = new ITaskItem[] { new TaskItem(item) }; 1198 1199 item = new ProjectItemInstance(project, "ItemListContainingTwoItems", "b.cs", "."); 1200 ProjectItemInstance item2 = new ProjectItemInstance(project, "ItemListContainingTwoItems", "c.cs", "."); 1201 item.SetMetadata("HintPath", "c:\\foo"); 1202 item2.SetMetadata("HintPath", "c:\\bar"); 1203 itemsByName.Add(item); 1204 itemsByName.Add(item2); 1205 _twoItems = new ITaskItem[] { new TaskItem(item), new TaskItem(item2) }; 1206 1207 _bucket = new ItemBucket(new string[0], new Dictionary<string, string>(), new Lookup(itemsByName, new PropertyDictionary<ProjectPropertyInstance>(), null), 0); 1208 _host.FindTask(null); 1209 _host.InitializeForBatch(talc, _bucket, null); 1210 _parametersSetOnTask = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); 1211 _outputsReadFromTask = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); 1212 } 1213 1214 /// <summary> 1215 /// Helper method for tests 1216 /// </summary> ValidateOutputItem(string outputName, string value)1217 private void ValidateOutputItem(string outputName, string value) 1218 { 1219 Assert.True(_host.GatherTaskOutputs(outputName, ElementLocation.Create(".", 1, 1), true, "output")); 1220 Assert.True(_outputsReadFromTask.ContainsKey(outputName)); 1221 1222 Assert.Equal(1, _bucket.Lookup.GetItems("output").Count); 1223 Assert.Equal(value, _bucket.Lookup.GetItems("output").First().EvaluatedInclude); 1224 } 1225 1226 /// <summary> 1227 /// Helper method for tests 1228 /// </summary> ValidateOutputItem(string outputName, ITaskItem value)1229 private void ValidateOutputItem(string outputName, ITaskItem value) 1230 { 1231 Assert.True(_host.GatherTaskOutputs(outputName, ElementLocation.Create(".", 1, 1), true, "output")); 1232 Assert.True(_outputsReadFromTask.ContainsKey(outputName)); 1233 1234 Assert.Equal(1, _bucket.Lookup.GetItems("output").Count); 1235 Assert.Equal(0, TaskItemComparer.Instance.Compare(value, new TaskItem(_bucket.Lookup.GetItems("output").First()))); 1236 } 1237 1238 /// <summary> 1239 /// Helper method for tests 1240 /// </summary> ValidateOutputItems(string outputName, string[] values)1241 private void ValidateOutputItems(string outputName, string[] values) 1242 { 1243 Assert.True(_host.GatherTaskOutputs(outputName, ElementLocation.Create(".", 1, 1), true, "output")); 1244 Assert.True(_outputsReadFromTask.ContainsKey(outputName)); 1245 1246 Assert.Equal(values.Length, _bucket.Lookup.GetItems("output").Count); 1247 for (int i = 0; i < values.Length; i++) 1248 { 1249 Assert.Equal(values[i], _bucket.Lookup.GetItems("output").ElementAt(i).EvaluatedInclude); 1250 } 1251 } 1252 1253 /// <summary> 1254 /// Helper method for tests 1255 /// </summary> ValidateOutputItems(string outputName, ITaskItem[] values)1256 private void ValidateOutputItems(string outputName, ITaskItem[] values) 1257 { 1258 Assert.True(_host.GatherTaskOutputs(outputName, ElementLocation.Create(".", 1, 1), true, "output")); 1259 Assert.True(_outputsReadFromTask.ContainsKey(outputName)); 1260 1261 Assert.Equal(values.Length, _bucket.Lookup.GetItems("output").Count); 1262 for (int i = 0; i < values.Length; i++) 1263 { 1264 Assert.Equal(0, TaskItemComparer.Instance.Compare(values[i], new TaskItem(_bucket.Lookup.GetItems("output").ElementAt(i)))); 1265 } 1266 } 1267 1268 /// <summary> 1269 /// Helper method for tests 1270 /// </summary> ValidateOutputProperty(string outputName, string value)1271 private void ValidateOutputProperty(string outputName, string value) 1272 { 1273 Assert.True(_host.GatherTaskOutputs(outputName, ElementLocation.Create(".", 1, 1), false, "output")); 1274 Assert.True(_outputsReadFromTask.ContainsKey(outputName)); 1275 1276 Assert.NotNull(_bucket.Lookup.GetProperty("output")); 1277 Assert.Equal(value, _bucket.Lookup.GetProperty("output").EvaluatedValue); 1278 } 1279 1280 /// <summary> 1281 /// Helper method for tests 1282 /// </summary> ValidateTaskParameter(string parameterName, string value, object expectedValue)1283 private void ValidateTaskParameter(string parameterName, string value, object expectedValue) 1284 { 1285 SetTaskParameter(parameterName, value); 1286 1287 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1288 Assert.Equal(expectedValue, _parametersSetOnTask[parameterName]); 1289 } 1290 1291 /// <summary> 1292 /// Helper method for tests 1293 /// </summary> ValidateTaskParameterItem(string parameterName, string value)1294 private void ValidateTaskParameterItem(string parameterName, string value) 1295 { 1296 SetTaskParameter(parameterName, value); 1297 1298 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1299 1300 ITaskItem actualItem = _parametersSetOnTask[parameterName] as ITaskItem; 1301 Assert.Equal(value, actualItem.ItemSpec); 1302 Assert.Equal(BuiltInMetadata.MetadataCount, actualItem.MetadataCount); 1303 } 1304 1305 /// <summary> 1306 /// Helper method for tests 1307 /// </summary> ValidateTaskParameterItem(string parameterName, string value, ITaskItem expectedItem)1308 private void ValidateTaskParameterItem(string parameterName, string value, ITaskItem expectedItem) 1309 { 1310 SetTaskParameter(parameterName, value); 1311 1312 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1313 1314 ITaskItem actualItem = _parametersSetOnTask[parameterName] as ITaskItem; 1315 Assert.Equal(0, TaskItemComparer.Instance.Compare(expectedItem, actualItem)); 1316 } 1317 1318 /// <summary> 1319 /// Helper method for tests 1320 /// </summary> ValidateTaskParameterItems(string parameterName, string value)1321 private void ValidateTaskParameterItems(string parameterName, string value) 1322 { 1323 SetTaskParameter(parameterName, value); 1324 1325 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1326 1327 ITaskItem[] actualItems = _parametersSetOnTask[parameterName] as ITaskItem[]; 1328 Assert.Equal(1, actualItems.Length); 1329 Assert.Equal(value, actualItems[0].ItemSpec); 1330 } 1331 1332 /// <summary> 1333 /// Helper method for tests 1334 /// </summary> ValidateTaskParameterItems(string parameterName, string value, ITaskItem[] expectedItems)1335 private void ValidateTaskParameterItems(string parameterName, string value, ITaskItem[] expectedItems) 1336 { 1337 SetTaskParameter(parameterName, value); 1338 1339 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1340 1341 ITaskItem[] actualItems = _parametersSetOnTask[parameterName] as ITaskItem[]; 1342 Assert.Equal(expectedItems.Length, actualItems.Length); 1343 1344 for (int i = 0; i < expectedItems.Length; i++) 1345 { 1346 Assert.Equal(0, TaskItemComparer.Instance.Compare(expectedItems[i], actualItems[i])); 1347 } 1348 } 1349 1350 /// <summary> 1351 /// Helper method for tests 1352 /// </summary> ValidateTaskParameterItems(string parameterName, string value, string[] expectedItems)1353 private void ValidateTaskParameterItems(string parameterName, string value, string[] expectedItems) 1354 { 1355 SetTaskParameter(parameterName, value); 1356 1357 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1358 1359 ITaskItem[] actualItems = _parametersSetOnTask[parameterName] as ITaskItem[]; 1360 Assert.Equal(expectedItems.Length, actualItems.Length); 1361 1362 for (int i = 0; i < expectedItems.Length; i++) 1363 { 1364 Assert.Equal(expectedItems[i], actualItems[i].ItemSpec); 1365 } 1366 } 1367 1368 /// <summary> 1369 /// Helper method for tests 1370 /// </summary> ValidateTaskParameterArray(string parameterName, string value, object expectedValue)1371 private void ValidateTaskParameterArray(string parameterName, string value, object expectedValue) 1372 { 1373 SetTaskParameter(parameterName, value); 1374 1375 Assert.True(_parametersSetOnTask.ContainsKey(parameterName)); 1376 1377 Array expectedArray = expectedValue as Array; 1378 Array actualArray = _parametersSetOnTask[parameterName] as Array; 1379 1380 Assert.Equal(expectedArray.Length, actualArray.Length); 1381 for (int i = 0; i < expectedArray.Length; i++) 1382 { 1383 Assert.Equal(expectedArray.GetValue(i), actualArray.GetValue(i)); 1384 } 1385 } 1386 1387 /// <summary> 1388 /// Helper method for tests 1389 /// </summary> ValidateTaskParameterNotSet(string parameterName, string value)1390 private void ValidateTaskParameterNotSet(string parameterName, string value) 1391 { 1392 SetTaskParameter(parameterName, value); 1393 Assert.False(_parametersSetOnTask.ContainsKey(parameterName)); 1394 } 1395 1396 #endregion 1397 1398 /// <summary> 1399 /// Helper method for tests 1400 /// </summary> SetTaskParameter(string parameterName, string value)1401 private void SetTaskParameter(string parameterName, string value) 1402 { 1403 Dictionary<string, Tuple<string, ElementLocation>> parameters = GetStandardParametersDictionary(true); 1404 parameters[parameterName] = new Tuple<string, ElementLocation>(value, ElementLocation.Create("foo.proj")); 1405 bool success = _host.SetTaskParameters(parameters); 1406 Assert.True(success); 1407 } 1408 1409 /// <summary> 1410 /// Helper method for tests 1411 /// </summary> GetStandardParametersDictionary(bool returnParam)1412 private Dictionary<string, Tuple<string, ElementLocation>> GetStandardParametersDictionary(bool returnParam) 1413 { 1414 Dictionary<string, Tuple<string, ElementLocation>> parameters = new Dictionary<string, Tuple<string, ElementLocation>>(StringComparer.OrdinalIgnoreCase); 1415 parameters["ExecuteReturnParam"] = new Tuple<string, ElementLocation>(returnParam ? "true" : "false", ElementLocation.Create("foo.proj")); 1416 return parameters; 1417 } 1418 1419 /// <summary> 1420 /// Helper method for tests 1421 /// </summary> GetParameterLocation(string name)1422 private IElementLocation GetParameterLocation(string name) 1423 { 1424 return ElementLocation.Create(".", 1, 1); 1425 } 1426 1427 /// <summary> 1428 /// Creates a test project. 1429 /// </summary> 1430 /// <returns>The project.</returns> CreateTestProject()1431 private ProjectInstance CreateTestProject() 1432 { 1433 string projectFileContents = ObjectModelHelpers.CleanupFileContents(@" 1434 <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='msbuildnamespace'> 1435 <UsingTask TaskName='TaskWithMissingAssembly' AssemblyName='madeup' /> 1436 <ItemGroup> 1437 <Compile Include='b.cs' /> 1438 <Compile Include='c.cs' /> 1439 </ItemGroup> 1440 1441 <ItemGroup> 1442 <Reference Include='System' /> 1443 </ItemGroup> 1444 1445 <Target Name='Empty' /> 1446 1447 <Target Name='Skip' Inputs='testProject.proj' Outputs='testProject.proj' /> 1448 1449 <Target Name='Error' > 1450 <ErrorTask1 ContinueOnError='True'/> 1451 <ErrorTask2 ContinueOnError='False'/> 1452 <ErrorTask3 /> 1453 <OnError ExecuteTargets='Foo'/> 1454 <OnError ExecuteTargets='Bar'/> 1455 </Target> 1456 1457 <Target Name='Foo' Inputs='foo.cpp' Outputs='foo.o'> 1458 <FooTask1/> 1459 </Target> 1460 1461 <Target Name='Bar'> 1462 <BarTask1/> 1463 </Target> 1464 1465 <Target Name='Baz' DependsOnTargets='Bar'> 1466 <BazTask1/> 1467 <BazTask2/> 1468 </Target> 1469 1470 <Target Name='Baz2' DependsOnTargets='Bar;Foo'> 1471 <Baz2Task1/> 1472 <Baz2Task2/> 1473 <Baz2Task3/> 1474 </Target> 1475 1476 <Target Name='DepSkip' DependsOnTargets='Skip'> 1477 <DepSkipTask1/> 1478 <DepSkipTask2/> 1479 <DepSkipTask3/> 1480 </Target> 1481 1482 <Target Name='DepError' DependsOnTargets='Foo;Skip;Error'> 1483 <DepSkipTask1/> 1484 <DepSkipTask2/> 1485 <DepSkipTask3/> 1486 </Target> 1487 1488 </Project> 1489 "); 1490 1491 Project project = new Project(XmlReader.Create(new StringReader(projectFileContents))); 1492 return project.CreateProjectInstance(); 1493 } 1494 } 1495 } 1496