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