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