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>Tests for the ProjectUsingTaskElement class.</summary>
6 //-----------------------------------------------------------------------
7 
8 using System;
9 using System.Collections.Generic;
10 using System.IO;
11 using System.Reflection;
12 using System.Text;
13 using System.Xml;
14 
15 using Microsoft.Build.Construction;
16 using Microsoft.Build.Shared;
17 
18 using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
19 using Xunit;
20 
21 namespace Microsoft.Build.UnitTests.OM.Construction
22 {
23     /// <summary>
24     /// Tests for the ProjectUsingTaskElement class
25     /// </summary>
26     public class ProjectUsingTaskElement_Tests
27     {
28         /// <summary>
29         /// Read project with no usingtasks
30         /// </summary>
31         [Fact]
ReadNone()32         public void ReadNone()
33         {
34             ProjectRootElement project = ProjectRootElement.Create();
35 
36             Assert.Equal(null, project.UsingTasks.GetEnumerator().Current);
37         }
38 
39         /// <summary>
40         /// Read usingtask with no task name attribute
41         /// </summary>
42         [Fact]
ReadInvalidMissingTaskName()43         public void ReadInvalidMissingTaskName()
44         {
45             Assert.Throws<InvalidProjectFileException>(() =>
46             {
47                 string content = @"
48                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
49                         <UsingTask AssemblyFile='af'/>
50                     </Project>
51                 ";
52 
53                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
54             }
55            );
56         }
57         /// <summary>
58         /// Read usingtask with empty task name attribute
59         /// </summary>
60         [Fact]
ReadInvalidEmptyTaskName()61         public void ReadInvalidEmptyTaskName()
62         {
63             Assert.Throws<InvalidProjectFileException>(() =>
64             {
65                 string content = @"
66                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
67                         <UsingTask TaskName='' AssemblyFile='af'/>
68                     </Project>
69                 ";
70 
71                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
72             }
73            );
74         }
75         /// <summary>
76         /// Read usingtask with unexpected attribute
77         /// </summary>
78         [Fact]
ReadInvalidAttribute()79         public void ReadInvalidAttribute()
80         {
81             Assert.Throws<InvalidProjectFileException>(() =>
82             {
83                 string content = @"
84                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
85                         <UsingTask TaskName='t' AssemblyFile='af' X='Y'/>
86                     </Project>
87                 ";
88 
89                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
90             }
91            );
92         }
93         /// <summary>
94         /// Read usingtask with neither AssemblyFile nor AssemblyName attributes
95         /// </summary>
96         [Fact]
ReadInvalidMissingAssemblyFileAssemblyName()97         public void ReadInvalidMissingAssemblyFileAssemblyName()
98         {
99             Assert.Throws<InvalidProjectFileException>(() =>
100             {
101                 string content = @"
102                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
103                         <UsingTask TaskName='t'/>
104                     </Project>
105                 ";
106 
107                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
108             }
109            );
110         }
111         /// <summary>
112         /// Read usingtask with only empty AssemblyFile attribute
113         /// </summary>
114         [Fact]
ReadInvalidEmptyAssemblyFile()115         public void ReadInvalidEmptyAssemblyFile()
116         {
117             Assert.Throws<InvalidProjectFileException>(() =>
118             {
119                 string content = @"
120                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
121                         <UsingTask TaskName='t' AssemblyFile=''/>
122                     </Project>
123                 ";
124 
125                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
126             }
127            );
128         }
129         /// <summary>
130         /// Read usingtask with empty AssemblyFile attribute but AssemblyName present
131         /// </summary>
132         [Fact]
ReadInvalidEmptyAssemblyFileAndAssemblyNameNotEmpty()133         public void ReadInvalidEmptyAssemblyFileAndAssemblyNameNotEmpty()
134         {
135             Assert.Throws<InvalidProjectFileException>(() =>
136             {
137                 string content = @"
138                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
139                         <UsingTask TaskName='t' AssemblyFile='' AssemblyName='n'/>
140                     </Project>
141                 ";
142 
143                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
144             }
145            );
146         }
147         /// <summary>
148         /// Read usingtask with only empty AssemblyName attribute but AssemblyFile present
149         /// </summary>
150         [Fact]
ReadInvalidEmptyAssemblyNameAndAssemblyFileNotEmpty()151         public void ReadInvalidEmptyAssemblyNameAndAssemblyFileNotEmpty()
152         {
153             Assert.Throws<InvalidProjectFileException>(() =>
154             {
155                 string content = @"
156                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
157                         <UsingTask TaskName='t' AssemblyName='' AssemblyFile='f'/>
158                     </Project>
159                 ";
160 
161                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
162             }
163            );
164         }
165         /// <summary>
166         /// Read usingtask with both AssemblyName and AssemblyFile attributes
167         /// </summary>
168         [Fact]
ReadInvalidBothAssemblyFileAssemblyName()169         public void ReadInvalidBothAssemblyFileAssemblyName()
170         {
171             Assert.Throws<InvalidProjectFileException>(() =>
172             {
173                 string content = @"
174                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
175                         <UsingTask TaskName='t' AssemblyName='an' AssemblyFile='af'/>
176                     </Project>
177                 ";
178 
179                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
180             }
181            );
182         }
183         /// <summary>
184         /// Read usingtask with both AssemblyName and AssemblyFile attributes but both are empty
185         /// </summary>
186         [Fact]
ReadInvalidBothEmptyAssemblyFileEmptyAssemblyNameBoth()187         public void ReadInvalidBothEmptyAssemblyFileEmptyAssemblyNameBoth()
188         {
189             Assert.Throws<InvalidProjectFileException>(() =>
190             {
191                 string content = @"
192                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
193                         <UsingTask TaskName='t' AssemblyName='' AssemblyFile=''/>
194                     </Project>
195                 ";
196 
197                 ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
198             }
199            );
200         }
201         /// <summary>
202         /// Read usingtask with assembly file
203         /// </summary>
204         [Fact]
ReadBasicUsingTaskAssemblyFile()205         public void ReadBasicUsingTaskAssemblyFile()
206         {
207             ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyFile();
208 
209             Assert.Equal("t1", usingTask.TaskName);
210             Assert.Equal("af", usingTask.AssemblyFile);
211             Assert.Equal(String.Empty, usingTask.AssemblyName);
212             Assert.Equal(String.Empty, usingTask.Condition);
213         }
214 
215         /// <summary>
216         /// Read usingtask with assembly name
217         /// </summary>
218         [Fact]
ReadBasicUsingTaskAssemblyName()219         public void ReadBasicUsingTaskAssemblyName()
220         {
221             ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyName();
222 
223             Assert.Equal("t2", usingTask.TaskName);
224             Assert.Equal(String.Empty, usingTask.AssemblyFile);
225             Assert.Equal("an", usingTask.AssemblyName);
226             Assert.Equal("c", usingTask.Condition);
227         }
228 
229         /// <summary>
230         /// Read usingtask with task factory, required runtime and required platform
231         /// </summary>
232         [Fact]
ReadBasicUsingTaskFactoryRuntimeAndPlatform()233         public void ReadBasicUsingTaskFactoryRuntimeAndPlatform()
234         {
235             ProjectUsingTaskElement usingTask = GetUsingTaskFactoryRuntimeAndPlatform();
236 
237             Assert.Equal("t2", usingTask.TaskName);
238             Assert.Equal(String.Empty, usingTask.AssemblyFile);
239             Assert.Equal("an", usingTask.AssemblyName);
240             Assert.Equal("c", usingTask.Condition);
241             Assert.Equal("AssemblyFactory", usingTask.TaskFactory);
242         }
243 
244         /// <summary>
245         /// Verify that passing in string.empty or null for TaskFactory will remove the element from the xml.
246         /// </summary>
247         [Fact]
RemoveUsingTaskFactoryRuntimeAndPlatform()248         public void RemoveUsingTaskFactoryRuntimeAndPlatform()
249         {
250             ProjectUsingTaskElement usingTask = GetUsingTaskFactoryRuntimeAndPlatform();
251 
252             string value = null;
253             VerifyAttributesRemoved(usingTask, value);
254 
255             usingTask = GetUsingTaskFactoryRuntimeAndPlatform();
256             value = String.Empty;
257             VerifyAttributesRemoved(usingTask, value);
258         }
259 
260         /// <summary>
261         /// Set assembly file on a usingtask that already has assembly file
262         /// </summary>
263         [Fact]
SetUsingTaskAssemblyFileOnUsingTaskAssemblyFile()264         public void SetUsingTaskAssemblyFileOnUsingTaskAssemblyFile()
265         {
266             ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyFile();
267             Helpers.ClearDirtyFlag(usingTask.ContainingProject);
268 
269             usingTask.AssemblyFile = "afb";
270             Assert.Equal("afb", usingTask.AssemblyFile);
271             Assert.Equal(true, usingTask.ContainingProject.HasUnsavedChanges);
272         }
273 
274         /// <summary>
275         /// Set assembly name on a usingtask that already has assembly name
276         /// </summary>
277         [Fact]
SetUsingTaskAssemblyNameOnUsingTaskAssemblyName()278         public void SetUsingTaskAssemblyNameOnUsingTaskAssemblyName()
279         {
280             ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyName();
281             Helpers.ClearDirtyFlag(usingTask.ContainingProject);
282 
283             usingTask.AssemblyName = "anb";
284             Assert.Equal("anb", usingTask.AssemblyName);
285             Assert.Equal(true, usingTask.ContainingProject.HasUnsavedChanges);
286         }
287 
288         /// <summary>
289         /// Set assembly file on a usingtask that already has assembly name
290         /// </summary>
291         [Fact]
SetUsingTaskAssemblyFileOnUsingTaskAssemblyName()292         public void SetUsingTaskAssemblyFileOnUsingTaskAssemblyName()
293         {
294             Assert.Throws<InvalidOperationException>(() =>
295             {
296                 ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyName();
297 
298                 usingTask.AssemblyFile = "afb";
299             }
300            );
301         }
302         /// <summary>
303         /// Set assembly name on a usingtask that already has assembly file
304         /// </summary>
305         [Fact]
SetUsingTaskAssemblyNameOnUsingTaskAssemblyFile()306         public void SetUsingTaskAssemblyNameOnUsingTaskAssemblyFile()
307         {
308             Assert.Throws<InvalidOperationException>(() =>
309             {
310                 ProjectUsingTaskElement usingTask = GetUsingTaskAssemblyFile();
311 
312                 usingTask.AssemblyName = "anb";
313             }
314            );
315         }
316         /// <summary>
317         /// Set task name
318         /// </summary>
319         [Fact]
SetTaskName()320         public void SetTaskName()
321         {
322             ProjectRootElement project = ProjectRootElement.Create();
323             ProjectUsingTaskElement usingTask = project.AddUsingTask("t", "af", null);
324             Helpers.ClearDirtyFlag(usingTask.ContainingProject);
325 
326             usingTask.TaskName = "tt";
327             Assert.Equal("tt", usingTask.TaskName);
328             Assert.Equal(true, usingTask.ContainingProject.HasUnsavedChanges);
329         }
330 
331         /// <summary>
332         /// Set condition
333         /// </summary>
334         [Fact]
SetCondition()335         public void SetCondition()
336         {
337             ProjectRootElement project = ProjectRootElement.Create();
338             ProjectUsingTaskElement usingTask = project.AddUsingTask("t", "af", null);
339             Helpers.ClearDirtyFlag(usingTask.ContainingProject);
340 
341             usingTask.Condition = "c";
342             Assert.Equal("c", usingTask.Condition);
343             Assert.Equal(true, usingTask.ContainingProject.HasUnsavedChanges);
344         }
345 
346         /// <summary>
347         /// Set task factory
348         /// </summary>
349         [Fact]
SetTaskFactory()350         public void SetTaskFactory()
351         {
352             ProjectRootElement project = ProjectRootElement.Create();
353             ProjectUsingTaskElement usingTask = project.AddUsingTask("t", "af", null);
354             Helpers.ClearDirtyFlag(usingTask.ContainingProject);
355 
356             usingTask.TaskFactory = "AssemblyFactory";
357             Assert.Equal("AssemblyFactory", usingTask.TaskFactory);
358             Assert.Equal(true, usingTask.ContainingProject.HasUnsavedChanges);
359         }
360 
361         /// <summary>
362         /// Make sure there is an exception when there are multiple parameter groups in the using task tag.
363         /// </summary>
364         [Fact]
DuplicateParameterGroup()365         public void DuplicateParameterGroup()
366         {
367             Assert.Throws<InvalidProjectFileException>(() =>
368             {
369                 string content = @"
370                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
371                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c' TaskFactory='AssemblyFactory'>
372                             <ParameterGroup/>
373                             <ParameterGroup/>
374                         </UsingTask>
375                     </Project>
376                 ";
377                 ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
378                 Assert.True(false);
379             }
380            );
381         }
382         /// <summary>
383         /// Make sure there is an exception when there are multiple task groups in the using task tag.
384         /// </summary>
385         [Fact]
DuplicateTaskGroup()386         public void DuplicateTaskGroup()
387         {
388             Assert.Throws<InvalidProjectFileException>(() =>
389             {
390                 string content = @"
391                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
392                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c' TaskFactory='AssemblyFactory'>
393                             <Task/>
394                             <Task/>
395                         </UsingTask>
396                     </Project>
397                 ";
398                 ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
399                 Assert.True(false);
400             }
401            );
402         }
403         /// <summary>
404         /// Make sure there is an exception when there is an unknown child
405         /// </summary>
406         [Fact]
UnknownChild()407         public void UnknownChild()
408         {
409             Assert.Throws<InvalidProjectFileException>(() =>
410             {
411                 string content = @"
412                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
413                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c' TaskFactory='AssemblyFactory'>
414                             <IAMUNKNOWN/>
415                         </UsingTask>
416                     </Project>
417                 ";
418                 ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
419                 Assert.True(false);
420             }
421            );
422         }
423         /// <summary>
424         /// Make sure there is an no exception when there are children in the using task
425         /// </summary>
426         [Fact]
WorksWithChildren()427         public void WorksWithChildren()
428         {
429             string content = @"
430                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
431                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c' TaskFactory='AssemblyFactory'>
432                             <ParameterGroup>
433                                <MyParameter/>
434                             </ParameterGroup>
435                             <Task>
436                                 RANDOM GOO
437                             </Task>
438                         </UsingTask>
439                     </Project>
440                 ";
441 
442             ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
443             ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
444             Assert.NotNull(usingTask);
445             Assert.Equal(2, usingTask.Count);
446         }
447 
448         /// <summary>
449         /// Make sure there is an exception when a parameter group is added but no task factory attribute is on the using task
450         /// </summary>
451         [Fact]
ExceptionWhenNoTaskFactoryAndHavePG()452         public void ExceptionWhenNoTaskFactoryAndHavePG()
453         {
454             Assert.Throws<InvalidProjectFileException>(() =>
455             {
456                 string content = @"
457                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
458                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c'>
459                             <ParameterGroup>
460                                <MyParameter/>
461                             </ParameterGroup>
462                         </UsingTask>
463                     </Project>
464                 ";
465 
466                 ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
467                 ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
468                 Assert.True(false);
469             }
470            );
471         }
472         /// <summary>
473         /// Make sure there is an exception when a parameter group is added but no task factory attribute is on the using task
474         /// </summary>
475         [Fact]
ExceptionWhenNoTaskFactoryAndHaveTask()476         public void ExceptionWhenNoTaskFactoryAndHaveTask()
477         {
478             Assert.Throws<InvalidProjectFileException>(() =>
479             {
480                 string content = @"
481                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
482                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c'>
483                             <Task/>
484                         </UsingTask>
485                     </Project>
486                 ";
487 
488                 ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
489                 ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
490                 Assert.True(false);
491             }
492            );
493         }
494         /// <summary>
495         /// Helper to get a ProjectUsingTaskElement with a task factory, required runtime and required platform
496         /// </summary>
GetUsingTaskFactoryRuntimeAndPlatform()497         private static ProjectUsingTaskElement GetUsingTaskFactoryRuntimeAndPlatform()
498         {
499             string content = @"
500                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
501                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c' TaskFactory='AssemblyFactory' />
502                     </Project>
503                 ";
504 
505             ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
506             ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
507             return usingTask;
508         }
509 
510         /// <summary>
511         /// Helper to get a ProjectUsingTaskElement with an assembly file set
512         /// </summary>
GetUsingTaskAssemblyFile()513         private static ProjectUsingTaskElement GetUsingTaskAssemblyFile()
514         {
515             string content = @"
516                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
517                         <UsingTask TaskName='t1' AssemblyFile='af' />
518                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c'/>
519                     </Project>
520                 ";
521 
522             ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
523             ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
524             return usingTask;
525         }
526 
527         /// <summary>
528         /// Helper to get a ProjectUsingTaskElement with an assembly name set
529         /// </summary>
GetUsingTaskAssemblyName()530         private static ProjectUsingTaskElement GetUsingTaskAssemblyName()
531         {
532             string content = @"
533                     <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
534                         <UsingTask TaskName='t2' AssemblyName='an' Condition='c'/>
535                     </Project>
536                 ";
537 
538             ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
539             ProjectUsingTaskElement usingTask = (ProjectUsingTaskElement)Helpers.GetFirst(project.Children);
540             return usingTask;
541         }
542 
543         /// <summary>
544         /// Verify the attributes are removed from the xml when string.empty and null are passed in
545         /// </summary>
VerifyAttributesRemoved(ProjectUsingTaskElement usingTask, string value)546         private static void VerifyAttributesRemoved(ProjectUsingTaskElement usingTask, string value)
547         {
548             Assert.True(usingTask.ContainingProject.RawXml.Contains("TaskFactory"));
549             usingTask.TaskFactory = value;
550             Assert.False(usingTask.ContainingProject.RawXml.Contains("TaskFactory"));
551         }
552     }
553 }
554