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 #if FEATURE_APPDOMAIN
5 
6 using System;
7 using System.Collections;
8 using System.Runtime.InteropServices;
9 using System.Runtime.InteropServices.ComTypes;
10 using System.Collections.Generic;
11 
12 
13 // TYPELIBATTR clashes with the one in InteropServices.
14 using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR;
15 
16 using Microsoft.Build.Framework;
17 using Microsoft.Build.Utilities;
18 using Microsoft.Build.Tasks;
19 using Microsoft.Build.Shared;
20 using Xunit;
21 using ItemMetadataNames = Microsoft.Build.Tasks.ItemMetadataNames;
22 
23 namespace Microsoft.Build.UnitTests
24 {
25     /*
26      * Class:   ResolveComReference_Tests
27      *
28      * Test the ResolveComReference task in various ways.
29      *
30      */
31     sealed public class ResolveComReference_Tests
32     {
33         /*
34          * Method:  SetupTaskItem
35          *
36          * Creates a valid task item that's modified later
37          */
SetupTaskItem()38         private TaskItem SetupTaskItem()
39         {
40             TaskItem item = new TaskItem();
41 
42             item.SetMetadata(ComReferenceItemMetadataNames.guid, "{5C6D0C4D-D530-4B08-B22F-307CA6BFCB65}");
43             item.SetMetadata(ComReferenceItemMetadataNames.versionMajor, "1");
44             item.SetMetadata(ComReferenceItemMetadataNames.versionMinor, "0");
45             item.SetMetadata(ComReferenceItemMetadataNames.lcid, "0");
46             item.SetMetadata(ComReferenceItemMetadataNames.wrapperTool, "tlbimp");
47 
48             return item;
49         }
50 
AssertReference(ITaskItem item, bool valid, string attribute)51         private void AssertReference(ITaskItem item, bool valid, string attribute)
52         {
53             string missingOrInvalidAttribute = null;
54             Assert.Equal(ResolveComReference.VerifyReferenceMetadataForNameItem(item, out missingOrInvalidAttribute), valid);
55             Assert.Equal(missingOrInvalidAttribute, attribute);
56         }
57 
AssertMetadataInitialized(ITaskItem item, string metadataName, string metadataValue)58         private void AssertMetadataInitialized(ITaskItem item, string metadataName, string metadataValue)
59         {
60             Assert.Equal(item.GetMetadata(metadataName), metadataValue);
61         }
62 
63         /// <summary>
64         /// Issue in this bug was an ArgumentNullException when ResolvedAssemblyReferences was null
65         /// </summary>
66         [Fact]
GetResolvedASsemblyReferenceSpecNotNull()67         public void GetResolvedASsemblyReferenceSpecNotNull()
68         {
69             var task = new ResolveComReference();
70             Assert.NotNull(task.GetResolvedAssemblyReferenceItemSpecs());
71         }
72 
73         /*
74          * Method:  CheckComReferenceAttributeVerificationForNameItems
75          *
76          * Checks if verification of Com reference item metadata works properly
77          */
78         [Fact]
CheckComReferenceMetadataVerificationForNameItems()79         public void CheckComReferenceMetadataVerificationForNameItems()
80         {
81             // valid item
82             TaskItem item = SetupTaskItem();
83             AssertReference(item, true, "");
84 
85             // invalid guid
86             item = SetupTaskItem();
87             item.SetMetadata(ComReferenceItemMetadataNames.guid, "{I'm pretty sure this is not a valid guid}");
88             AssertReference(item, false, ComReferenceItemMetadataNames.guid);
89 
90             // missing guid
91             item = SetupTaskItem();
92             item.RemoveMetadata(ComReferenceItemMetadataNames.guid);
93             AssertReference(item, false, ComReferenceItemMetadataNames.guid);
94 
95             // invalid verMajor
96             item = SetupTaskItem();
97             item.SetMetadata(ComReferenceItemMetadataNames.versionMajor, "eleventy one");
98             AssertReference(item, false, ComReferenceItemMetadataNames.versionMajor);
99 
100             // missing verMajor
101             item = SetupTaskItem();
102             item.RemoveMetadata(ComReferenceItemMetadataNames.versionMajor);
103             AssertReference(item, false, ComReferenceItemMetadataNames.versionMajor);
104 
105             // invalid verMinor
106             item = SetupTaskItem();
107             item.SetMetadata(ComReferenceItemMetadataNames.versionMinor, "eleventy one");
108             AssertReference(item, false, ComReferenceItemMetadataNames.versionMinor);
109 
110             // missing verMinor
111             item = SetupTaskItem();
112             item.RemoveMetadata(ComReferenceItemMetadataNames.versionMinor);
113             AssertReference(item, false, ComReferenceItemMetadataNames.versionMinor);
114 
115             // invalid lcid
116             item = SetupTaskItem();
117             item.SetMetadata(ComReferenceItemMetadataNames.lcid, "Mars-us");
118             AssertReference(item, false, ComReferenceItemMetadataNames.lcid);
119 
120             // missing lcid - it's optional, so this should work ok
121             item = SetupTaskItem();
122             item.RemoveMetadata(ComReferenceItemMetadataNames.lcid);
123             AssertReference(item, true, String.Empty);
124 
125             // invalid tool
126             item = SetupTaskItem();
127             item.SetMetadata(ComReferenceItemMetadataNames.wrapperTool, "crowbar");
128             AssertReference(item, false, ComReferenceItemMetadataNames.wrapperTool);
129 
130             // missing tool - it's optional, so this should work ok
131             item = SetupTaskItem();
132             item.RemoveMetadata(ComReferenceItemMetadataNames.wrapperTool);
133             AssertReference(item, true, String.Empty);
134         }
135 
136         /*
137          * Method:  CheckComReferenceAttributeInitializationForNameItems
138          *
139          * Checks if missing optional attributes for COM name references get initialized correctly
140          */
141         [Fact]
CheckComReferenceMetadataInitializationForNameItems()142         public void CheckComReferenceMetadataInitializationForNameItems()
143         {
144             // missing lcid - should get initialized to 0
145             TaskItem item = SetupTaskItem();
146             item.RemoveMetadata(ComReferenceItemMetadataNames.lcid);
147             ResolveComReference.InitializeDefaultMetadataForNameItem(item);
148             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.lcid, "0");
149 
150             // existing lcid - should not get modified
151             item = SetupTaskItem();
152             item.SetMetadata(ComReferenceItemMetadataNames.lcid, "1033");
153             ResolveComReference.InitializeDefaultMetadataForNameItem(item);
154             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.lcid, "1033");
155 
156             // missing wrapperTool - should get initialized to tlbimp
157             item = SetupTaskItem();
158             item.RemoveMetadata(ComReferenceItemMetadataNames.wrapperTool);
159             ResolveComReference.InitializeDefaultMetadataForNameItem(item);
160             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.tlbimp);
161 
162             // existing wrapperTool - should not get modified
163             item = SetupTaskItem();
164             item.SetMetadata(ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.aximp);
165             ResolveComReference.InitializeDefaultMetadataForNameItem(item);
166             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.aximp);
167         }
168 
169         /*
170          * Method:  CheckComReferenceAttributeInitializationForFileItems
171          *
172          * Checks if missing optional attributes for COM file references get initialized correctly
173          */
174         [Fact]
CheckComReferenceMetadataInitializationForFileItems()175         public void CheckComReferenceMetadataInitializationForFileItems()
176         {
177             // missing wrapperTool - should get initialized to tlbimp
178             TaskItem item = SetupTaskItem();
179             item.RemoveMetadata(ComReferenceItemMetadataNames.wrapperTool);
180             ResolveComReference.InitializeDefaultMetadataForFileItem(item);
181             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.tlbimp);
182 
183             // existing wrapperTool - should not get modified
184             item = SetupTaskItem();
185             item.SetMetadata(ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.aximp);
186             ResolveComReference.InitializeDefaultMetadataForFileItem(item);
187             AssertMetadataInitialized(item, ComReferenceItemMetadataNames.wrapperTool, ComReferenceTypes.aximp);
188         }
189 
190         /// <summary>
191         /// Helper function for creating a COM reference task item instance
192         /// </summary>
CreateComReferenceTaskItem(string itemSpec, string guid, string vMajor, string vMinor, string lcid, string wrapperType, string embedInteropTypes)193         private TaskItem CreateComReferenceTaskItem(string itemSpec, string guid, string vMajor, string vMinor, string lcid, string wrapperType, string embedInteropTypes)
194         {
195             TaskItem item = new TaskItem(itemSpec);
196 
197             item.SetMetadata(ComReferenceItemMetadataNames.guid, guid);
198             item.SetMetadata(ComReferenceItemMetadataNames.versionMajor, vMajor);
199             item.SetMetadata(ComReferenceItemMetadataNames.versionMinor, vMinor);
200             item.SetMetadata(ComReferenceItemMetadataNames.lcid, lcid);
201             item.SetMetadata(ComReferenceItemMetadataNames.wrapperTool, wrapperType);
202             item.SetMetadata(ItemMetadataNames.embedInteropTypes, embedInteropTypes);
203 
204             return item;
205         }
206 
207         /// <summary>
208         /// Helper function for creating a COM reference task item instance
209         /// </summary>
CreateComReferenceTaskItem(string itemSpec, string guid, string vMajor, string vMinor, string lcid, string wrapperType)210         private TaskItem CreateComReferenceTaskItem(string itemSpec, string guid, string vMajor, string vMinor, string lcid, string wrapperType)
211         {
212             return CreateComReferenceTaskItem(itemSpec, guid, vMajor, vMinor, lcid, wrapperType, String.Empty);
213         }
214 
215         /// <summary>
216         /// Test the ResolveComReference.TaskItemToTypeLibAttr method
217         /// </summary>
218         [Fact]
CheckTaskItemToTypeLibAttr()219         public void CheckTaskItemToTypeLibAttr()
220         {
221             Guid refGuid = Guid.NewGuid();
222 
223             TaskItem reference = CreateComReferenceTaskItem("ref", refGuid.ToString(), "11", "0", "1033", ComReferenceTypes.tlbimp);
224             TYPELIBATTR refAttr = ResolveComReference.TaskItemToTypeLibAttr(reference);
225 
226             Assert.Equal(refGuid, refAttr.guid); // "incorrect guid"
227             Assert.Equal(11, refAttr.wMajorVerNum); // "incorrect version major"
228             Assert.Equal(0, refAttr.wMinorVerNum); // "incorrect version minor"
229             Assert.Equal(1033, refAttr.lcid); // "incorrect lcid"
230         }
231 
232         /// <summary>
233         /// Helper function for creating a ComReferenceInfo object using an existing TaskInfo object and
234         /// typelib name/path. The type lib pointer will obviously not be initialized, so this object cannot
235         /// be used in any code that uses it.
236         /// </summary>
CreateComReferenceInfo(ITaskItem taskItem, string typeLibName, string typeLibPath)237         private ComReferenceInfo CreateComReferenceInfo(ITaskItem taskItem, string typeLibName, string typeLibPath)
238         {
239             ComReferenceInfo referenceInfo = new ComReferenceInfo();
240 
241             referenceInfo.taskItem = taskItem;
242             referenceInfo.attr = ResolveComReference.TaskItemToTypeLibAttr(taskItem);
243             referenceInfo.typeLibName = typeLibName;
244             referenceInfo.fullTypeLibPath = typeLibPath;
245             referenceInfo.strippedTypeLibPath = typeLibPath;
246             referenceInfo.typeLibPointer = null;
247 
248             return referenceInfo;
249         }
250 
251         /// <summary>
252         /// Create a few test references for unit tests
253         /// </summary>
CreateTestReferences( out ComReferenceInfo axRefInfo, out ComReferenceInfo tlbRefInfo, out ComReferenceInfo piaRefInfo, out TYPELIBATTR axAttr, out TYPELIBATTR tlbAttr, out TYPELIBATTR piaAttr, out TYPELIBATTR notInProjectAttr)254         private void CreateTestReferences(
255             out ComReferenceInfo axRefInfo, out ComReferenceInfo tlbRefInfo, out ComReferenceInfo piaRefInfo,
256             out TYPELIBATTR axAttr, out TYPELIBATTR tlbAttr, out TYPELIBATTR piaAttr, out TYPELIBATTR notInProjectAttr)
257         {
258             // doing my part to deplete the worldwide guid reserves...
259             Guid axGuid = Guid.NewGuid();
260             Guid tlbGuid = Guid.NewGuid();
261             Guid piaGuid = Guid.NewGuid();
262 
263             // create reference task items
264             TaskItem axTaskItem = CreateComReferenceTaskItem("axref", axGuid.ToString(), "1", "0", "1033", ComReferenceTypes.aximp);
265             TaskItem tlbTaskItem = CreateComReferenceTaskItem("tlbref", tlbGuid.ToString(), "5", "1", "0", ComReferenceTypes.tlbimp);
266             TaskItem piaTaskItem = CreateComReferenceTaskItem("piaref", piaGuid.ToString(), "999", "444", "123", ComReferenceTypes.primary);
267 
268             // create reference infos
269             axRefInfo = CreateComReferenceInfo(axTaskItem, "AxRefLibName", "AxRefLibPath");
270             tlbRefInfo = CreateComReferenceInfo(tlbTaskItem, "TlbRefLibName", "TlbRefLibPath");
271             piaRefInfo = CreateComReferenceInfo(piaTaskItem, "PiaRefLibName", "PiaRefLibPath");
272 
273             // get the references' typelib attributes
274             axAttr = ResolveComReference.TaskItemToTypeLibAttr(axTaskItem);
275             tlbAttr = ResolveComReference.TaskItemToTypeLibAttr(tlbTaskItem);
276             piaAttr = ResolveComReference.TaskItemToTypeLibAttr(piaTaskItem);
277 
278             // create typelib attributes not matching any of the project refs
279             notInProjectAttr = new TYPELIBATTR();
280             notInProjectAttr.guid = tlbGuid;
281             notInProjectAttr.wMajorVerNum = 5;
282             notInProjectAttr.wMinorVerNum = 1;
283             notInProjectAttr.lcid = 1033;
284         }
285 
286         /// <summary>
287         /// Unit test for the ResolveComReference.IsExistingProjectReference() method
288         /// </summary>
289         [Fact]
CheckIsExistingProjectReference()290         public void CheckIsExistingProjectReference()
291         {
292             TYPELIBATTR axAttr, tlbAttr, piaAttr, notInProjectAttr;
293             ComReferenceInfo axRefInfo, tlbRefInfo, piaRefInfo;
294 
295             CreateTestReferences(out axRefInfo, out tlbRefInfo, out piaRefInfo,
296                 out axAttr, out tlbAttr, out piaAttr, out notInProjectAttr);
297 
298             ResolveComReference rcr = new ResolveComReference();
299 
300             // populate the ResolveComReference's list of project references
301             rcr.allProjectRefs = new List<ComReferenceInfo>();
302             rcr.allProjectRefs.Add(axRefInfo);
303             rcr.allProjectRefs.Add(tlbRefInfo);
304             rcr.allProjectRefs.Add(piaRefInfo);
305 
306             ComReferenceInfo referenceInfo;
307 
308             // find the Ax ref, matching with any type of reference - should NOT find it
309             bool retValue = rcr.IsExistingProjectReference(axAttr, null, out referenceInfo);
310             Assert.True(retValue == false && referenceInfo == null); // "ActiveX ref should NOT be found for any type of ref"
311 
312             // find the Ax ref, matching with aximp types - should find it
313             retValue = rcr.IsExistingProjectReference(axAttr, ComReferenceTypes.aximp, out referenceInfo);
314             Assert.True(retValue == true && referenceInfo == axRefInfo); // "ActiveX ref should be found for aximp ref types"
315 
316             // find the Ax ref, matching with tlbimp types - should NOT find it
317             retValue = rcr.IsExistingProjectReference(axAttr, ComReferenceTypes.tlbimp, out referenceInfo);
318             Assert.True(retValue == false && referenceInfo == null); // "ActiveX ref should NOT be found for tlbimp ref types"
319 
320 
321             // find the Tlb ref, matching with any type of reference - should find it
322             retValue = rcr.IsExistingProjectReference(tlbAttr, null, out referenceInfo);
323             Assert.True(retValue == true && referenceInfo == tlbRefInfo); // "Tlb ref should be found for any type of ref"
324 
325             // find the Tlb ref, matching with tlbimp types - should find it
326             retValue = rcr.IsExistingProjectReference(tlbAttr, ComReferenceTypes.tlbimp, out referenceInfo);
327             Assert.True(retValue == true && referenceInfo == tlbRefInfo); // "Tlb ref should be found for tlbimp ref types"
328 
329             // find the Tlb ref, matching with pia types - should NOT find it
330             retValue = rcr.IsExistingProjectReference(tlbAttr, ComReferenceTypes.primary, out referenceInfo);
331             Assert.True(retValue == false && referenceInfo == null); // "Tlb ref should NOT be found for primary ref types"
332 
333 
334             // find the Pia ref, matching with any type of reference - should find it
335             retValue = rcr.IsExistingProjectReference(piaAttr, null, out referenceInfo);
336             Assert.True(retValue == true && referenceInfo == piaRefInfo); // "Pia ref should be found for any type of ref"
337 
338             // find the Pia ref, matching with pia types - should find it
339             retValue = rcr.IsExistingProjectReference(piaAttr, ComReferenceTypes.primary, out referenceInfo);
340             Assert.True(retValue == true && referenceInfo == piaRefInfo); // "Pia ref should be found for pia ref types"
341 
342             // find the Pia ref, matching with pia types - should NOT find it
343             retValue = rcr.IsExistingProjectReference(piaAttr, ComReferenceTypes.aximp, out referenceInfo);
344             Assert.True(retValue == false && referenceInfo == null); // "Pia ref should NOT be found for aximp ref types"
345 
346 
347             // try to find a non existing reference
348             retValue = rcr.IsExistingProjectReference(notInProjectAttr, null, out referenceInfo);
349             Assert.True(retValue == false && referenceInfo == null); // "not in project ref should not be found"
350         }
351 
352         /// <summary>
353         /// Unit test for the ResolveComReference.IsExistingDependencyReference() method
354         /// </summary>
355         [Fact]
CheckIsExistingDependencyReference()356         public void CheckIsExistingDependencyReference()
357         {
358             TYPELIBATTR axAttr, tlbAttr, piaAttr, notInProjectAttr;
359             ComReferenceInfo axRefInfo, tlbRefInfo, piaRefInfo;
360 
361             CreateTestReferences(out axRefInfo, out tlbRefInfo, out piaRefInfo,
362                 out axAttr, out tlbAttr, out piaAttr, out notInProjectAttr);
363 
364             ResolveComReference rcr = new ResolveComReference();
365 
366             // populate the ResolveComReference's list of project references
367             rcr.allDependencyRefs = new List<ComReferenceInfo>();
368             rcr.allDependencyRefs.Add(axRefInfo);
369             rcr.allDependencyRefs.Add(tlbRefInfo);
370             rcr.allDependencyRefs.Add(piaRefInfo);
371 
372             ComReferenceInfo referenceInfo;
373 
374             // find the Ax ref - should find it
375             bool retValue = rcr.IsExistingDependencyReference(axAttr, out referenceInfo);
376             Assert.True(retValue == true && referenceInfo == axRefInfo); // "ActiveX ref should be found"
377 
378             // find the Tlb ref - should find it
379             retValue = rcr.IsExistingDependencyReference(tlbAttr, out referenceInfo);
380             Assert.True(retValue == true && referenceInfo == tlbRefInfo); // "Tlb ref should be found"
381 
382             // find the Pia ref - should find it
383             retValue = rcr.IsExistingDependencyReference(piaAttr, out referenceInfo);
384             Assert.True(retValue == true && referenceInfo == piaRefInfo); // "Pia ref should be found"
385 
386             // try to find a non existing reference - should not find it
387             retValue = rcr.IsExistingDependencyReference(notInProjectAttr, out referenceInfo);
388             Assert.True(retValue == false && referenceInfo == null); // "not in project ref should not be found"
389 
390             // Now, try to resolve a non-existent ComAssemblyReference.
391             string path;
392             IComReferenceResolver resolver = (IComReferenceResolver)rcr;
393             Assert.False(resolver.ResolveComAssemblyReference("MyAssembly", out path));
394             Assert.Equal(null, path);
395         }
396 
397         /// <summary>
398         /// ResolveComReference automatically adds missing tlbimp references for aximp references.
399         /// This test verifies we actually create the missing references.
400         /// </summary>
401         [Fact]
CheckAddMissingTlbReference()402         public void CheckAddMissingTlbReference()
403         {
404             TYPELIBATTR axAttr, tlbAttr, piaAttr, notInProjectAttr;
405             ComReferenceInfo axRefInfo, tlbRefInfo, piaRefInfo;
406 
407             CreateTestReferences(out axRefInfo, out tlbRefInfo, out piaRefInfo,
408                 out axAttr, out tlbAttr, out piaAttr, out notInProjectAttr);
409 
410             ResolveComReference rcr = new ResolveComReference();
411             rcr.BuildEngine = new MockEngine();
412 
413             // populate the ResolveComReference's list of project references
414             rcr.allProjectRefs = new List<ComReferenceInfo>();
415             rcr.allProjectRefs.Add(axRefInfo);
416             rcr.allProjectRefs.Add(tlbRefInfo);
417             rcr.allProjectRefs.Add(piaRefInfo);
418 
419             rcr.AddMissingTlbReferences();
420 
421             Assert.Equal(4, rcr.allProjectRefs.Count); // "There should be four references now"
422 
423             ComReferenceInfo newTlbInfo = (ComReferenceInfo)rcr.allProjectRefs[3];
424             Assert.Equal(axRefInfo.primaryOfAxImpRef, newTlbInfo); // "axRefInfo should hold back reference to tlbRefInfo"
425             Assert.True(ComReference.AreTypeLibAttrEqual(newTlbInfo.attr, axRefInfo.attr)); // "The added reference should have the same attributes as the Ax reference"
426             Assert.Equal(newTlbInfo.typeLibName, axRefInfo.typeLibName); // "The added reference should have the same type lib name as the Ax reference"
427             Assert.Equal(newTlbInfo.strippedTypeLibPath, axRefInfo.strippedTypeLibPath); // "The added reference should have the same type lib path as the Ax reference"
428 
429             Assert.Equal(newTlbInfo.taskItem.ItemSpec, axRefInfo.taskItem.ItemSpec); // "The added reference should have the same task item spec as the Ax reference"
430             Assert.Equal(newTlbInfo.taskItem.GetMetadata(ComReferenceItemMetadataNames.wrapperTool), ComReferenceTypes.primaryortlbimp); // "The added reference should have the tlbimp/primary wrapper tool"
431 
432             rcr.AddMissingTlbReferences();
433             Assert.Equal(4, rcr.allProjectRefs.Count); // "There should still be four references"
434         }
435 
436         [Fact]
BothKeyFileAndKeyContainer()437         public void BothKeyFileAndKeyContainer()
438         {
439             ResolveComReference rcr = new ResolveComReference();
440             MockEngine e = new MockEngine();
441             rcr.BuildEngine = e;
442 
443             rcr.KeyFile = "foo";
444             rcr.KeyContainer = "bar";
445 
446             Assert.False(rcr.Execute());
447 
448             e.AssertLogContains("MSB3300");
449         }
450 
451         [Fact]
DelaySignWithoutEitherKeyFileOrKeyContainer()452         public void DelaySignWithoutEitherKeyFileOrKeyContainer()
453         {
454             ResolveComReference rcr = new ResolveComReference();
455             MockEngine e = new MockEngine();
456             rcr.BuildEngine = e;
457 
458             rcr.DelaySign = true;
459             Assert.False(rcr.Execute());
460 
461             e.AssertLogContains("MSB3301");
462         }
463 
464         /// <summary>
465         /// Test if assemblies located in the gac get their CopyLocal attribute set to False
466         /// </summary>
467         [Fact]
468         [Trait("Category", "mono-osx-failing")]
CheckSetCopyLocalToFalseOnEmbedInteropTypesAssemblies()469         public void CheckSetCopyLocalToFalseOnEmbedInteropTypesAssemblies()
470         {
471             string gacPath = @"C:\windows\gac";
472 
473             ResolveComReference rcr = new ResolveComReference();
474             rcr.BuildEngine = new MockEngine();
475 
476             // the matrix of TargetFrameworkVersion values we are testing
477             string[] fxVersions =
478             {
479                 "v2.0",
480                 "v3.0",
481                 "v3.5",
482                 "v4.0"
483             };
484 
485             for (int i = 0; i < fxVersions.Length; i++)
486             {
487                 string fxVersion = fxVersions[i];
488 
489                 ArrayList taskItems = new ArrayList();
490 
491                 TaskItem nonGacNoPrivate = new TaskItem(@"C:\windows\gar\test1.dll");
492                 nonGacNoPrivate.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
493 
494                 TaskItem gacNoPrivate = new TaskItem(@"C:\windows\gac\assembly1.dll");
495                 gacNoPrivate.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
496 
497                 TaskItem nonGacPrivateFalse = new TaskItem(@"C:\windows\gar\test1.dll");
498                 nonGacPrivateFalse.SetMetadata(ItemMetadataNames.privateMetadata, "false");
499                 nonGacPrivateFalse.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
500 
501                 TaskItem gacPrivateFalse = new TaskItem(@"C:\windows\gac\assembly1.dll");
502                 gacPrivateFalse.SetMetadata(ItemMetadataNames.privateMetadata, "false");
503                 gacPrivateFalse.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
504 
505                 TaskItem nonGacPrivateTrue = new TaskItem(@"C:\windows\gar\test1.dll");
506                 nonGacPrivateTrue.SetMetadata(ItemMetadataNames.privateMetadata, "true");
507                 nonGacPrivateTrue.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
508 
509                 TaskItem gacPrivateTrue = new TaskItem(@"C:\windows\gac\assembly1.dll");
510                 gacPrivateTrue.SetMetadata(ItemMetadataNames.privateMetadata, "true");
511                 gacPrivateTrue.SetMetadata(ItemMetadataNames.embedInteropTypes, "true");
512 
513                 taskItems.Add(nonGacNoPrivate);
514                 taskItems.Add(gacNoPrivate);
515 
516                 taskItems.Add(nonGacPrivateFalse);
517                 taskItems.Add(gacPrivateFalse);
518 
519                 taskItems.Add(nonGacPrivateTrue);
520                 taskItems.Add(gacPrivateTrue);
521 
522                 rcr.TargetFrameworkVersion = fxVersion;
523                 rcr.SetFrameworkVersionFromString(rcr.TargetFrameworkVersion);
524 
525                 rcr.SetCopyLocalToFalseOnGacOrNoPIAAssemblies(taskItems, gacPath);
526 
527                 bool enabledNoPIA = false;
528                 switch (fxVersion)
529                 {
530                     case "v4.0":
531                         enabledNoPIA = true;
532                         break;
533                     default:
534                         break;
535                 }
536 
537                 // if Private is missing, by default GAC items are CopyLocal=false, non GAC CopyLocal=true
538                 Assert.Equal(nonGacNoPrivate.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "true"));
539 
540                 Assert.Equal(gacNoPrivate.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "false"));
541 
542                 // if Private is set, it takes precedence
543                 Assert.Equal(nonGacPrivateFalse.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "false"));
544 
545                 Assert.Equal(gacPrivateFalse.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "false"));
546 
547                 Assert.Equal(nonGacPrivateTrue.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "true"));
548 
549                 Assert.Equal(gacPrivateTrue.GetMetadata(ItemMetadataNames.copyLocal), (enabledNoPIA ? "false" : "true"));
550             }
551         }
552 
553         /// <summary>
554         /// Test if assemblies located in the gac get their CopyLocal attribute set to False
555         /// </summary>
556         [Fact]
557         [Trait("Category", "mono-osx-failing")]
CheckSetCopyLocalToFalseOnGacAssemblies()558         public void CheckSetCopyLocalToFalseOnGacAssemblies()
559         {
560             string gacPath = @"C:\windows\gac";
561 
562             ResolveComReference rcr = new ResolveComReference();
563             rcr.BuildEngine = new MockEngine();
564 
565             ArrayList taskItems = new ArrayList();
566             TaskItem nonGacNoPrivate = new TaskItem(@"C:\windows\gar\test1.dll");
567             TaskItem gacNoPrivate = new TaskItem(@"C:\windows\gac\assembly1.dll");
568 
569             TaskItem nonGacPrivateFalse = new TaskItem(@"C:\windows\gar\test1.dll");
570             nonGacPrivateFalse.SetMetadata(ItemMetadataNames.privateMetadata, "false");
571             TaskItem gacPrivateFalse = new TaskItem(@"C:\windows\gac\assembly1.dll");
572             gacPrivateFalse.SetMetadata(ItemMetadataNames.privateMetadata, "false");
573 
574             TaskItem nonGacPrivateTrue = new TaskItem(@"C:\windows\gar\test1.dll");
575             nonGacPrivateTrue.SetMetadata(ItemMetadataNames.privateMetadata, "true");
576             TaskItem gacPrivateTrue = new TaskItem(@"C:\windows\gac\assembly1.dll");
577             gacPrivateTrue.SetMetadata(ItemMetadataNames.privateMetadata, "true");
578 
579             taskItems.Add(nonGacNoPrivate);
580             taskItems.Add(gacNoPrivate);
581 
582             taskItems.Add(nonGacPrivateFalse);
583             taskItems.Add(gacPrivateFalse);
584 
585             taskItems.Add(nonGacPrivateTrue);
586             taskItems.Add(gacPrivateTrue);
587 
588             rcr.SetCopyLocalToFalseOnGacOrNoPIAAssemblies(taskItems, gacPath);
589 
590             // if Private is missing, by default GAC items are CopyLocal=false, non GAC CopyLocal=true
591             Assert.Equal(nonGacNoPrivate.GetMetadata(ItemMetadataNames.copyLocal), "true"); // "Non Gac assembly, missing Private, should be TRUE"
592 
593             Assert.Equal(gacNoPrivate.GetMetadata(ItemMetadataNames.copyLocal), "false"); // "Gac assembly, missing Private, should be FALSE"
594 
595             // if Private is set, it takes precedence
596             Assert.Equal(nonGacPrivateFalse.GetMetadata(ItemMetadataNames.copyLocal), "false"); // "Non Gac assembly, Private false, should be FALSE"
597 
598             Assert.Equal(gacPrivateFalse.GetMetadata(ItemMetadataNames.copyLocal), "false"); // "Gac assembly, Private false, should be FALSE"
599 
600             Assert.Equal(nonGacPrivateTrue.GetMetadata(ItemMetadataNames.copyLocal), "true"); // "Non Gac assembly, Private true, should be TRUE"
601 
602             Assert.Equal(gacPrivateTrue.GetMetadata(ItemMetadataNames.copyLocal), "true"); // "Gac assembly, Private true, should be TRUE"
603         }
604 
605         /// <summary>
606         /// Make sure the conflicting references are detected correctly
607         /// </summary>
608         [Fact]
TestCheckForConflictingReferences()609         public void TestCheckForConflictingReferences()
610         {
611             TYPELIBATTR axAttr, tlbAttr, piaAttr, notInProjectAttr;
612             ComReferenceInfo axRefInfo, tlbRefInfo, piaRefInfo;
613 
614             CreateTestReferences(out axRefInfo, out tlbRefInfo, out piaRefInfo,
615                 out axAttr, out tlbAttr, out piaAttr, out notInProjectAttr);
616 
617             ResolveComReference rcr = new ResolveComReference();
618             rcr.BuildEngine = new MockEngine();
619 
620             // populate the ResolveComReference's list of project references
621             rcr.allProjectRefs = new List<ComReferenceInfo>();
622             rcr.allProjectRefs.Add(axRefInfo);
623             rcr.allProjectRefs.Add(tlbRefInfo);
624             rcr.allProjectRefs.Add(piaRefInfo);
625 
626             // no conflicts should be found with just the three initial refs
627             Assert.True(rcr.CheckForConflictingReferences());
628             Assert.Equal(3, rcr.allProjectRefs.Count);
629 
630             ComReferenceInfo referenceInfo;
631 
632             // duplicate refs should not be treated as conflicts
633             referenceInfo = new ComReferenceInfo(tlbRefInfo);
634             rcr.allProjectRefs.Add(referenceInfo);
635             referenceInfo = new ComReferenceInfo(axRefInfo);
636             rcr.allProjectRefs.Add(referenceInfo);
637             referenceInfo = new ComReferenceInfo(piaRefInfo);
638             rcr.allProjectRefs.Add(referenceInfo);
639 
640             Assert.True(rcr.CheckForConflictingReferences());
641             Assert.Equal(6, rcr.allProjectRefs.Count);
642 
643             // tlb and ax refs with same lib name but different attributes should be considered conflicting
644             // We don't care about typelib name conflicts for PIA refs, because we don't have to create wrappers for them
645             ComReferenceInfo conflictTlb = new ComReferenceInfo(tlbRefInfo);
646             conflictTlb.attr = notInProjectAttr;
647             rcr.allProjectRefs.Add(conflictTlb);
648             ComReferenceInfo conflictAx = new ComReferenceInfo(axRefInfo);
649             conflictAx.attr = notInProjectAttr;
650             rcr.allProjectRefs.Add(conflictAx);
651             ComReferenceInfo piaRef = new ComReferenceInfo(piaRefInfo);
652             piaRef.attr = notInProjectAttr;
653             rcr.allProjectRefs.Add(piaRef);
654 
655             Assert.False(rcr.CheckForConflictingReferences());
656 
657             // ... and conflicting references should have been removed
658             Assert.Equal(7, rcr.allProjectRefs.Count);
659             Assert.False(rcr.allProjectRefs.Contains(conflictTlb));
660             Assert.False(rcr.allProjectRefs.Contains(conflictAx));
661             Assert.True(rcr.allProjectRefs.Contains(piaRef));
662         }
663 
664         /// <summary>
665         /// In order to make ResolveComReferences multitargetable, two properties, ExecuteAsTool
666         /// and SdkToolsPath were added.  In order to have correct behavior when using pre-4.0
667         /// toolsversions, ExecuteAsTool must default to true, and the paths to the tools will be the
668         /// v3.5 path.  It is difficult to verify the tool paths in a unit test, however, so
669         /// this was done by ad hoc testing and will be maintained by the dev suites.
670         /// </summary>
671         [Fact]
MultiTargetingDefaultSetCorrectly()672         public void MultiTargetingDefaultSetCorrectly()
673         {
674             ResolveComReference t = new ResolveComReference();
675 
676             Assert.True(t.ExecuteAsTool); // "ExecuteAsTool should default to true"
677         }
678 
679         /// <summary>
680         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
681         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
682         /// its corresponding TLB wrapper.
683         /// </summary>
684         [Fact]
AxReferenceKnowsItsRCWCreateTlb()685         public void AxReferenceKnowsItsRCWCreateTlb()
686         {
687             CheckAxReferenceRCWTlbExists(RcwStyle.GenerateTlb /* have RCR create the TLB reference */, false /* don't include TLB version in the interop name */);
688         }
689 
690         /// <summary>
691         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
692         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
693         /// its corresponding TLB wrapper.
694         /// </summary>
695         [Fact]
AxReferenceKnowsItsRCWCreateTlb_IncludeVersion()696         public void AxReferenceKnowsItsRCWCreateTlb_IncludeVersion()
697         {
698             CheckAxReferenceRCWTlbExists(RcwStyle.GenerateTlb /* have RCR create the TLB reference */, true /* include TLB version in the interop name */);
699         }
700 
701         /// <summary>
702         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
703         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
704         /// its corresponding TLB wrapper.
705         /// </summary>
706         [Fact]
AxReferenceKnowsItsRCWTlbExists()707         public void AxReferenceKnowsItsRCWTlbExists()
708         {
709             CheckAxReferenceRCWTlbExists(RcwStyle.PreexistingTlb /* pass in the TLB reference */, false /* don't include TLB version in the interop name */);
710         }
711 
712         /// <summary>
713         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
714         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
715         /// its corresponding TLB wrapper.
716         ///
717         /// Tests that still works when IncludeVersionInInteropName = true
718         /// </summary>
719         [Fact]
AxReferenceKnowsItsRCWTlbExists_IncludeVersion()720         public void AxReferenceKnowsItsRCWTlbExists_IncludeVersion()
721         {
722             CheckAxReferenceRCWTlbExists(RcwStyle.PreexistingTlb /* pass in the TLB reference */, true /* include TLB version in the interop name */);
723         }
724 
725         /// <summary>
726         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
727         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
728         /// its corresponding TLB wrapper.
729         /// </summary>
730         [Fact]
AxReferenceKnowsItsRCWPiaExists()731         public void AxReferenceKnowsItsRCWPiaExists()
732         {
733             CheckAxReferenceRCWTlbExists(RcwStyle.PreexistingPia /* pass in the TLB reference */, false /* don't include version in the interop name */);
734         }
735 
736         /// <summary>
737         /// When calling AxImp.exe directly, the runtime-callable wrapper needs to be
738         /// passed via the /rcw switch, so RCR needs to make sure that the ax reference knows about
739         /// its corresponding TLB wrapper.
740         ///
741         /// Tests that still works when IncludeVersionInInteropName = true
742         /// </summary>
743         [Fact]
AxReferenceKnowsItsRCWPiaExists_IncludeVersion()744         public void AxReferenceKnowsItsRCWPiaExists_IncludeVersion()
745         {
746             CheckAxReferenceRCWTlbExists(RcwStyle.PreexistingPia /* pass in the PIA reference */, true /* include version in the interop name */);
747         }
748 
749         private enum RcwStyle { GenerateTlb, PreexistingTlb, PreexistingPia };
750 
751         /// <summary>
752         /// Helper method that will new up an AX and matching TLB reference, and verify that the AX reference
753         /// sets its RCW appropriately.
754         /// </summary>
CheckAxReferenceRCWTlbExists(RcwStyle rcwStyle, bool includeVersionInInteropName)755         private void CheckAxReferenceRCWTlbExists(RcwStyle rcwStyle, bool includeVersionInInteropName)
756         {
757             Guid axGuid = Guid.NewGuid();
758             ComReferenceInfo tlbRefInfo;
759 
760             ResolveComReference rcr = new ResolveComReference();
761             rcr.BuildEngine = new MockEngine();
762             rcr.IncludeVersionInInteropName = includeVersionInInteropName;
763 
764             rcr.allProjectRefs = new List<ComReferenceInfo>();
765 
766             TaskItem axTaskItem = CreateComReferenceTaskItem("ref", axGuid.ToString(), "1", "2", "1033", ComReferenceTypes.aximp);
767             ComReferenceInfo axRefInfo = CreateComReferenceInfo(axTaskItem, "RefLibName", "RefLibPath");
768             rcr.allProjectRefs.Add(axRefInfo);
769 
770             switch (rcwStyle)
771             {
772                 case RcwStyle.GenerateTlb: break;
773                 case RcwStyle.PreexistingTlb:
774                     {
775                         TaskItem tlbTaskItem = CreateComReferenceTaskItem("ref", axGuid.ToString(), "1", "2", "1033", ComReferenceTypes.tlbimp, "true");
776                         tlbRefInfo = CreateComReferenceInfo(tlbTaskItem, "RefLibName", "RefLibPath");
777                         rcr.allProjectRefs.Add(tlbRefInfo);
778                         break;
779                     }
780                 case RcwStyle.PreexistingPia:
781                     {
782                         TaskItem tlbTaskItem = CreateComReferenceTaskItem("ref", axGuid.ToString(), "1", "2", "1033", ComReferenceTypes.primary, "true");
783                         tlbRefInfo = CreateComReferenceInfo(tlbTaskItem, "RefLibName", "RefLibPath");
784                         rcr.allProjectRefs.Add(tlbRefInfo);
785                         break;
786                     }
787             }
788 
789             rcr.AddMissingTlbReferences();
790 
791             Assert.Equal(2, rcr.allProjectRefs.Count); // "Should be two references"
792 
793             tlbRefInfo = (ComReferenceInfo)rcr.allProjectRefs[1];
794             var embedInteropTypes = tlbRefInfo.taskItem.GetMetadata(ItemMetadataNames.embedInteropTypes);
795             Assert.Equal("false", embedInteropTypes); // "The tlb wrapper for the activex control should have EmbedInteropTypes=false not " + embedInteropTypes);
796             Assert.True(ComReference.AreTypeLibAttrEqual(tlbRefInfo.attr, axRefInfo.attr)); // "reference information should be the same"
797             Assert.Equal(TlbReference.GetWrapperFileName
798                         (
799                         axRefInfo.taskItem.GetMetadata(ComReferenceItemMetadataNames.tlbReferenceName),
800                         includeVersionInInteropName,
801                         axRefInfo.attr.wMajorVerNum,
802                         axRefInfo.attr.wMinorVerNum
803                         ),
804                     TlbReference.GetWrapperFileName
805                         (
806                         tlbRefInfo.typeLibName,
807                         includeVersionInInteropName,
808                         tlbRefInfo.attr.wMajorVerNum,
809                         tlbRefInfo.attr.wMinorVerNum
810                         )); //                     "Expected Ax reference's RCW name to match the new TLB"
811         }
812     }
813 }
814 
815 #endif
816