1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 using Microsoft.Build.Framework;
6 using Microsoft.Build.Shared;
7 using Microsoft.Build.Tasks;
8 using Microsoft.Build.Utilities;
9 using Xunit;
10 using SystemProcessorArchitecture = System.Reflection.ProcessorArchitecture;
11 
12 namespace Microsoft.Build.UnitTests.ResolveAssemblyReference_Tests
13 {
14     /// <summary>
15     /// Unit tests for the ResolveAssemblyReference GlobalAssemblyCache.
16     /// </summary>
17     public sealed class GlobalAssemblyCacheTests : ResolveAssemblyReferenceTestFixture
18     {
19         private const string system4 = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
20         private const string system2 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
21         private const string system1 = "System, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
22         private const string systemNotStrong = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null";
23 
24         private const string system4Path = "c:\\clr4\\System.dll";
25         private const string system2Path = "c:\\clr2\\System.dll";
26         private const string system1Path = "c:\\clr2\\System1.dll";
27 
28         private GetAssemblyRuntimeVersion _runtimeVersion = new GetAssemblyRuntimeVersion(MockGetRuntimeVersion);
29         private GetPathFromFusionName _getPathFromFusionName = new GetPathFromFusionName(MockGetPathFromFusionName);
30         private GetGacEnumerator _gacEnumerator = new GetGacEnumerator(MockAssemblyCacheEnumerator);
31 
32         /// <summary>
33         /// Verify when the GAC enumerator returns
34         ///
35         /// System, Version=4.0.0.0  Runtime=4.0xxxx
36         /// System, Version=2.0.0.0  Runtime=2.0xxxx
37         /// System, Version=1.0.0.0  Runtime=2.0xxxx
38         ///
39         /// And we target 2.0 runtime that we get the Version 2.0.0.0 system.
40         ///
41         /// This test two aspects. First that we get the correct runtime, second that we get the highest version for that assembly in the runtime.
42         /// </summary>
43         [Fact]
VerifySimpleNamev2057020()44         public void VerifySimpleNamev2057020()
45         {
46             // We want to pass a very generic name to get the correct gac entries.
47             AssemblyNameExtension fusionName = new AssemblyNameExtension("System");
48 
49 
50             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("2.0.57027"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, false);
51             Assert.NotNull(path);
52             Assert.True(path.Equals(system2Path, StringComparison.OrdinalIgnoreCase));
53         }
54 
55 
56         /// <summary>
57         /// Verify when the GAC enumerator returns
58         ///
59         /// System, Version=4.0.0.0  Runtime=4.0xxxx
60         /// System, Version=2.0.0.0  Runtime=2.0xxxx
61         /// System, Version=1.0.0.0  Runtime=2.0xxxx
62         ///
63         /// And we target 2.0 runtime that we get the Version 2.0.0.0 system.
64         ///
65         /// Verify that by setting the wants specific version to true that we will return the highest version when only the simple name is used.
66         /// Essentially specific version for the gac resolver means do not filter by runtime.
67         /// </summary>
68         [Fact]
VerifySimpleNamev2057020SpecificVersion()69         public void VerifySimpleNamev2057020SpecificVersion()
70         {
71             // We want to pass a very generic name to get the correct gac entries.
72             AssemblyNameExtension fusionName = new AssemblyNameExtension("System");
73 
74 
75             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("2.0.0"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
76             Assert.NotNull(path);
77             Assert.True(path.Equals(system4Path, StringComparison.OrdinalIgnoreCase));
78         }
79 
80         /// <summary>
81         /// Verify when the GAC enumerator returns
82         ///
83         /// System, Version=2.0.0.0  Runtime=2.0xxxx
84         /// System, Version=1.0.0.0  Runtime=2.0xxxx
85         ///
86         /// And we target 2.0 runtime that we get the Version 2.0.0.0 system.
87         ///
88         /// Verify that by setting the wants specific version to true that we will return the highest version when only the simple name is used.
89         /// Essentially specific version for the gac resolver means do not filter by runtime.
90         /// </summary>
91         [Fact]
VerifyFusionNamev2057020SpecificVersion()92         public void VerifyFusionNamev2057020SpecificVersion()
93         {
94             // We want to pass a very generic name to get the correct gac entries.
95             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, Version=2.0.0.0");
96 
97 
98             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("2.0.0"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
99             Assert.NotNull(path);
100             Assert.True(path.Equals(system2Path, StringComparison.OrdinalIgnoreCase));
101         }
102 
103         /// <summary>
104         /// Verify when the GAC enumerator returns
105         ///
106         /// System, Version=4.0.0.0  Runtime=4.0xxxx
107         /// System, Version=2.0.0.0  Runtime=2.0xxxx
108         /// System, Version=1.0.0.0  Runtime=2.0xxxx
109         ///
110         /// And we target 4.0 runtime that we get the Version 4.0.0.0 system.
111         ///
112         /// This test two aspects. First that we get the correct runtime, second that we get the highest version for that assembly in the runtime.
113         /// </summary>
114         [Fact]
VerifySimpleNamev40()115         public void VerifySimpleNamev40()
116         {
117             // We want to pass a very generic name to get the correct gac entries.
118             AssemblyNameExtension fusionName = new AssemblyNameExtension("System");
119 
120 
121             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("4.0.0"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, false);
122             Assert.NotNull(path);
123             Assert.True(path.Equals(system4Path, StringComparison.OrdinalIgnoreCase));
124         }
125 
126         /// <summary>
127         /// Verify when the GAC enumerator returns
128         ///
129         /// System, Version=4.0.0.0  Runtime=4.0xxxx
130         /// System, Version=2.0.0.0  Runtime=2.0xxxx
131         /// System, Version=1.0.0.0  Runtime=2.0xxxx
132         ///
133         /// And we target 4.0 runtime that we get the Version 4.0.0.0 system.
134         ///
135         /// Verify that by setting the wants specific version to true that we will return the highest version when only the simple name is used.
136         /// Essentially specific version for the gac resolver means do not filter by runtime.
137         /// </summary>
138         [Fact]
VerifySimpleNamev40SpecificVersion()139         public void VerifySimpleNamev40SpecificVersion()
140         {
141             // We want to pass a very generic name to get the correct gac entries.
142             AssemblyNameExtension fusionName = new AssemblyNameExtension("System");
143 
144 
145             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("4.0.0"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
146             Assert.NotNull(path);
147             Assert.True(path.Equals(system4Path, StringComparison.OrdinalIgnoreCase));
148         }
149 
150         /// <summary>
151         /// Verify when the GAC enumerator returns
152         ///
153         /// System, Version=4.0.0.0  Runtime=4.0xxxx
154         ///
155         ///
156         /// Verify that by setting the wants specific version to true that we will return the highest version when only the simple name is used.
157         /// Essentially specific version for the gac resolver means do not filter by runtime.
158         /// </summary>
159         [Fact]
VerifyFusionNamev40SpecificVersion()160         public void VerifyFusionNamev40SpecificVersion()
161         {
162             // We want to pass a very generic name to get the correct gac entries.
163             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, Version=4.0.0.0");
164 
165 
166             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, _runtimeVersion, new Version("4.0.0.0"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
167             Assert.NotNull(path);
168             Assert.True(path.Equals(system4Path, StringComparison.OrdinalIgnoreCase));
169         }
170 
171         /// <summary>
172         /// Verify when a assembly name is passed in which has the public key explicitly set to null that we return null as the assembly cannot be in the gac.
173         /// </summary>
174         [Fact]
VerifyEmptyPublicKeyspecificVersion()175         public void VerifyEmptyPublicKeyspecificVersion()
176         {
177             Assert.Throws<FileLoadException>(() =>
178             {
179                 AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=");
180                 string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, getRuntimeVersion, new Version("2.0.50727"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
181             }
182            );
183         }
184 
185         /// <summary>
186         /// Verify when a assembly name is passed in which has the public key explicitly set to null that we return null as the assembly cannot be in the gac.
187         /// </summary>
188         [Fact]
VerifyNullPublicKey()189         public void VerifyNullPublicKey()
190         {
191             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=null");
192             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, getRuntimeVersion, new Version("2.0.50727"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, false);
193             Assert.Null(path);
194         }
195 
196         /// <summary>
197         /// Verify when a assembly name is passed in which has the public key explicitly set to null that we return null as the assembly cannot be in the gac.
198         /// </summary>
199         [Fact]
VerifyNullPublicKeyspecificVersion()200         public void VerifyNullPublicKeyspecificVersion()
201         {
202             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=null");
203             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.None, getRuntimeVersion, new Version("2.0.50727"), false, new FileExists(MockFileExists), _getPathFromFusionName, _gacEnumerator, true);
204             Assert.Null(path);
205         }
206 
207 
208         /// <summary>
209         /// When a processor architecture is on the end of a fusion name we were appending another processor architecture onto the end causing an invalid fusion name
210         /// this was causing the GAC (api's) to crash.
211         /// </summary>
212         [Fact]
213         [Trait("Category", "mono-osx-failing")]
VerifyProcessorArchitectureDoesNotCrash()214         public void VerifyProcessorArchitectureDoesNotCrash()
215         {
216             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=b77a5c561934e089, ProcessorArchitecture=MSIL");
217             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.MSIL, getRuntimeVersion, new Version("2.0.50727"), false, new FileExists(MockFileExists), _getPathFromFusionName, null /* use the real gac enumerator*/, false);
218             Assert.Null(path);
219         }
220 
221         /// <summary>
222         /// When a processor architecture is on the end of a fusion name we were appending another processor architecture onto the end causing an invalid fusion name
223         /// this was causing the GAC (api's) to crash.
224         /// </summary>
225         [Fact]
226         [Trait("Category", "mono-osx-failing")]
VerifyProcessorArchitectureDoesNotCrashSpecificVersion()227         public void VerifyProcessorArchitectureDoesNotCrashSpecificVersion()
228         {
229             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=b77a5c561934e089, ProcessorArchitecture=MSIL");
230             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.MSIL, getRuntimeVersion, new Version("2.0.50727"), false, new FileExists(MockFileExists), _getPathFromFusionName, null /* use the real gac enumerator*/, true);
231             Assert.Null(path);
232         }
233 
234         /// <summary>
235         /// See bug 648678,  when a processor architecture is on the end of a fusion name we were appending another processor architecture onto the end causing an invalid fusion name
236         /// this was causing the GAC (api's) to crash.
237         /// </summary>
238         [Fact]
VerifyProcessorArchitectureDoesNotCrashFullFusionName()239         public void VerifyProcessorArchitectureDoesNotCrashFullFusionName()
240         {
241             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=b77a5c561934e089, ProcessorArchitecture=MSIL");
242             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.MSIL, getRuntimeVersion, new Version("2.0.50727"), true, new FileExists(MockFileExists), _getPathFromFusionName, null /* use the real gac enumerator*/, false);
243             Assert.Null(path);
244         }
245 
246         /// <summary>
247         /// When a processor architecture is on the end of a fusion name we were appending another processor architecture onto the end causing an invalid fusion name
248         /// this was causing the GAC (api's) to crash.
249         /// </summary>
250         [Fact]
VerifyProcessorArchitectureDoesNotCrashFullFusionNameSpecificVersion()251         public void VerifyProcessorArchitectureDoesNotCrashFullFusionNameSpecificVersion()
252         {
253             AssemblyNameExtension fusionName = new AssemblyNameExtension("System, PublicKeyToken=b77a5c561934e089, ProcessorArchitecture=MSIL");
254             string path = GlobalAssemblyCache.GetLocation(fusionName, SystemProcessorArchitecture.MSIL, getRuntimeVersion, new Version("2.0.50727"), true, new FileExists(MockFileExists), _getPathFromFusionName, null /* use the real gac enumerator*/, true);
255             Assert.Null(path);
256         }
257 
258 
259         // System.Runtime dependency calculation tests
260 
261         // No dependency
262         [Fact]
SystemRuntimeDepends_No_Build()263         public void SystemRuntimeDepends_No_Build()
264         {
265             ResolveAssemblyReference t = new ResolveAssemblyReference();
266 
267             t.BuildEngine = new MockEngine();
268 
269             t.Assemblies = new ITaskItem[]
270             {
271                 new TaskItem("Regular"),
272             };
273 
274             t.Assemblies[0].SetMetadata("HintPath", @"C:\SystemRuntime\Regular.dll");
275 
276             t.SearchPaths = DefaultPaths;
277 
278             // build mode
279             t.FindDependencies = true;
280             Assert.True(
281                 t.Execute
282                 (
283                     fileExists,
284                     directoryExists,
285                     getDirectories,
286                     getAssemblyName,
287                     getAssemblyMetadata,
288 #if FEATURE_WIN32_REGISTRY
289                     getRegistrySubKeyNames,
290                     getRegistrySubKeyDefaultValue,
291 #endif
292                     getLastWriteTime,
293                     getRuntimeVersion,
294 #if FEATURE_WIN32_REGISTRY
295                     openBaseKey,
296 #endif
297                     checkIfAssemblyIsInGac,
298                     isWinMDFile,
299                     readMachineTypeFromPEHeader
300                 )
301             );
302 
303             Assert.True(string.Equals(t.DependsOnSystemRuntime, "false", StringComparison.OrdinalIgnoreCase)); //                 "Expected no System.Runtime dependency found during build."
304             Assert.True(string.Equals(t.DependsOnNETStandard, "false", StringComparison.OrdinalIgnoreCase)); //                   "Expected no netstandard dependency found during build."
305 
306             // intelli build mode
307             t.FindDependencies = false;
308             Assert.True(
309                 t.Execute
310                 (
311                     fileExists,
312                     directoryExists,
313                     getDirectories,
314                     getAssemblyName,
315                     getAssemblyMetadata,
316 #if FEATURE_WIN32_REGISTRY
317                     getRegistrySubKeyNames,
318                     getRegistrySubKeyDefaultValue,
319 #endif
320                     getLastWriteTime,
321                     getRuntimeVersion,
322 #if FEATURE_WIN32_REGISTRY
323                     openBaseKey,
324 #endif
325                     checkIfAssemblyIsInGac,
326                     isWinMDFile,
327                     readMachineTypeFromPEHeader
328                 )
329             );
330 
331             Assert.True(string.Equals(t.DependsOnSystemRuntime, "false", StringComparison.OrdinalIgnoreCase)); //                 "Expected no System.Runtime dependency found during intellibuild."
332             Assert.True(string.Equals(t.DependsOnNETStandard, "false", StringComparison.OrdinalIgnoreCase)); //                   "Expected no netstandard dependency found during intellibuild."
333         }
334 
335 
336         // Direct dependency
337         [Fact]
SystemRuntimeDepends_Yes()338         public void SystemRuntimeDepends_Yes()
339         {
340             ResolveAssemblyReference t = new ResolveAssemblyReference();
341 
342             t.BuildEngine = new MockEngine();
343 
344             t.Assemblies = new ITaskItem[]
345             {
346                 new TaskItem("System.Runtime"),
347             };
348 
349             t.Assemblies[0].SetMetadata("HintPath", @"C:\SystemRuntime\System.Runtime.dll");
350 
351             t.SearchPaths = DefaultPaths;
352 
353             // build mode
354             t.FindDependencies = true;
355 
356             Assert.True(
357                 t.Execute
358                 (
359                     fileExists,
360                     directoryExists,
361                     getDirectories,
362                     getAssemblyName,
363                     getAssemblyMetadata,
364 #if FEATURE_WIN32_REGISTRY
365                     getRegistrySubKeyNames,
366                     getRegistrySubKeyDefaultValue,
367 #endif
368                     getLastWriteTime,
369                     getRuntimeVersion,
370 #if FEATURE_WIN32_REGISTRY
371                     openBaseKey,
372 #endif
373                     checkIfAssemblyIsInGac,
374                     isWinMDFile,
375                     readMachineTypeFromPEHeader
376                 )
377             );
378 
379             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
380 
381             // intelli build mode
382             t.FindDependencies = false;
383             Assert.True(
384                 t.Execute
385                 (
386                     fileExists,
387                     directoryExists,
388                     getDirectories,
389                     getAssemblyName,
390                     getAssemblyMetadata,
391 #if FEATURE_WIN32_REGISTRY
392                     getRegistrySubKeyNames,
393                     getRegistrySubKeyDefaultValue,
394 #endif
395                     getLastWriteTime,
396                     getRuntimeVersion,
397 #if FEATURE_WIN32_REGISTRY
398                     openBaseKey,
399 #endif
400                     checkIfAssemblyIsInGac,
401                     isWinMDFile,
402                     readMachineTypeFromPEHeader
403                 )
404             );
405 
406             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
407         }
408 
409         // Indirect dependency
410         [Fact]
411         [Trait("Category", "mono-osx-failing")]
SystemRuntimeDepends_Yes_Indirect()412         public void SystemRuntimeDepends_Yes_Indirect()
413         {
414             ResolveAssemblyReference t = new ResolveAssemblyReference();
415 
416             t.BuildEngine = new MockEngine();
417 
418             t.Assemblies = new ITaskItem[]
419             {
420                 new TaskItem("Portable"),
421             };
422 
423             t.Assemblies[0].SetMetadata("HintPath", @"C:\SystemRuntime\Portable.dll");
424 
425             t.SearchPaths = DefaultPaths;
426 
427             // build mode
428             t.FindDependencies = true;
429 
430             Assert.True(
431                 t.Execute
432                 (
433                     fileExists,
434                     directoryExists,
435                     getDirectories,
436                     getAssemblyName,
437                     getAssemblyMetadata,
438 #if FEATURE_WIN32_REGISTRY
439                     getRegistrySubKeyNames,
440                     getRegistrySubKeyDefaultValue,
441 #endif
442                     getLastWriteTime,
443                     getRuntimeVersion,
444 #if FEATURE_WIN32_REGISTRY
445                     openBaseKey,
446 #endif
447                     checkIfAssemblyIsInGac,
448                     isWinMDFile,
449                     readMachineTypeFromPEHeader
450                 )
451             );
452 
453             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
454 
455             // intelli build mode
456             t.FindDependencies = false;
457             Assert.True(
458                 t.Execute
459                 (
460                     fileExists,
461                     directoryExists,
462                     getDirectories,
463                     getAssemblyName,
464                     getAssemblyMetadata,
465 #if FEATURE_WIN32_REGISTRY
466                     getRegistrySubKeyNames,
467                     getRegistrySubKeyDefaultValue,
468 #endif
469                     getLastWriteTime,
470                     getRuntimeVersion,
471 #if FEATURE_WIN32_REGISTRY
472                     openBaseKey,
473 #endif
474                     checkIfAssemblyIsInGac,
475                     isWinMDFile,
476                     readMachineTypeFromPEHeader
477                 )
478             );
479 
480             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
481         }
482 
483         [Fact]
SystemRuntimeDepends_Yes_Indirect_ExternallyResolved()484         public void SystemRuntimeDepends_Yes_Indirect_ExternallyResolved()
485         {
486             ResolveAssemblyReference t = new ResolveAssemblyReference();
487 
488             t.BuildEngine = new MockEngine();
489 
490             t.Assemblies = new ITaskItem[]
491             {
492                 new TaskItem("Portable"),
493             };
494 
495             t.Assemblies[0].SetMetadata("ExternallyResolved", "true");
496             t.Assemblies[0].SetMetadata("HintPath", s_portableDllPath);
497 
498             t.SearchPaths = DefaultPaths;
499 
500             // build mode
501             t.FindDependencies = true;
502 
503             Assert.True(t.Execute(
504                 fileExists,
505                 directoryExists,
506                 getDirectories,
507                 getAssemblyName,
508                 getAssemblyMetadata,
509 #if FEATURE_WIN32_REGISTRY
510                 getRegistrySubKeyNames,
511                 getRegistrySubKeyDefaultValue,
512 #endif
513                 getLastWriteTime,
514                 getRuntimeVersion,
515 #if FEATURE_WIN32_REGISTRY
516                 openBaseKey,
517 #endif
518                 checkIfAssemblyIsInGac,
519                 isWinMDFile,
520                 readMachineTypeFromPEHeader));
521 
522             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
523 
524             // intelli build mode
525             t.FindDependencies = false;
526             Assert.True(t.Execute(
527                 fileExists,
528                 directoryExists,
529                 getDirectories,
530                 getAssemblyName,
531                 getAssemblyMetadata,
532 #if FEATURE_WIN32_REGISTRY
533                 getRegistrySubKeyNames,
534                 getRegistrySubKeyDefaultValue,
535 #endif
536                 getLastWriteTime,
537                 getRuntimeVersion,
538 #if FEATURE_WIN32_REGISTRY
539                 openBaseKey,
540 #endif
541                 checkIfAssemblyIsInGac, isWinMDFile,
542                 readMachineTypeFromPEHeader));
543 
544             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
545         }
546 
547         [Fact]
NETStandardDepends_Yes()548         public void NETStandardDepends_Yes()
549         {
550             ResolveAssemblyReference t = new ResolveAssemblyReference();
551 
552             t.BuildEngine = new MockEngine();
553 
554             t.Assemblies = new ITaskItem[]
555             {
556                 new TaskItem("netstandard"),
557             };
558 
559             t.Assemblies[0].SetMetadata("HintPath", @"C:\NetStandard\netstandard.dll");
560 
561             t.SearchPaths = DefaultPaths;
562 
563             // build mode
564             t.FindDependencies = true;
565 
566             Assert.True(t.Execute(
567                 fileExists,
568                 directoryExists,
569                 getDirectories,
570                 getAssemblyName,
571                 getAssemblyMetadata,
572 #if FEATURE_WIN32_REGISTRY
573                 getRegistrySubKeyNames,
574                 getRegistrySubKeyDefaultValue,
575 #endif
576                 getLastWriteTime,
577                 getRuntimeVersion,
578 #if FEATURE_WIN32_REGISTRY
579                 openBaseKey,
580 #endif
581                 checkIfAssemblyIsInGac,
582                 isWinMDFile,
583                 readMachineTypeFromPEHeader));
584 
585             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
586 
587             // intelli build mode
588             t.FindDependencies = false;
589             Assert.True(t.Execute(
590                 fileExists,
591                 directoryExists,
592                 getDirectories,
593                 getAssemblyName,
594                 getAssemblyMetadata,
595 #if FEATURE_WIN32_REGISTRY
596                 getRegistrySubKeyNames,
597                 getRegistrySubKeyDefaultValue,
598 #endif
599                 getLastWriteTime,
600                 getRuntimeVersion,
601 #if FEATURE_WIN32_REGISTRY
602                 openBaseKey,
603 #endif
604                 checkIfAssemblyIsInGac,
605                 isWinMDFile,
606                 readMachineTypeFromPEHeader));
607 
608             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
609         }
610 
611         [Fact]
NETStandardDepends_Yes_Indirect()612         public void NETStandardDepends_Yes_Indirect()
613         {
614             ResolveAssemblyReference t = new ResolveAssemblyReference();
615 
616             t.BuildEngine = new MockEngine();
617 
618             t.Assemblies = new ITaskItem[]
619             {
620                 new TaskItem("netstandardlibrary"),
621             };
622 
623             t.Assemblies[0].SetMetadata("HintPath", s_netstandardLibraryDllPath);
624 
625             t.SearchPaths = DefaultPaths;
626 
627             // build mode
628             t.FindDependencies = true;
629 
630             Assert.True(t.Execute(
631                 fileExists,
632                 directoryExists,
633                 getDirectories,
634                 getAssemblyName,
635                 getAssemblyMetadata,
636 #if FEATURE_WIN32_REGISTRY
637                 getRegistrySubKeyNames,
638                 getRegistrySubKeyDefaultValue,
639 #endif
640                 getLastWriteTime,
641                 getRuntimeVersion,
642 #if FEATURE_WIN32_REGISTRY
643                 openBaseKey,
644 #endif
645                 checkIfAssemblyIsInGac,
646                 isWinMDFile,
647                 readMachineTypeFromPEHeader));
648 
649             Console.WriteLine (((MockEngine)t.BuildEngine).Log);
650             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected netstandard dependency found during build."
651 
652             // intelli build mode
653             t.FindDependencies = false;
654             Assert.True(t.Execute(
655                 fileExists,
656                 directoryExists,
657                 getDirectories,
658                 getAssemblyName,
659                 getAssemblyMetadata,
660 #if FEATURE_WIN32_REGISTRY
661                 getRegistrySubKeyNames,
662                 getRegistrySubKeyDefaultValue,
663 #endif
664                 getLastWriteTime,
665                 getRuntimeVersion,
666 #if FEATURE_WIN32_REGISTRY
667                 openBaseKey,
668 #endif
669                 checkIfAssemblyIsInGac,
670                 isWinMDFile,
671                 readMachineTypeFromPEHeader));
672 
673             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected netstandard dependency found during intellibuild."
674         }
675 
676 
677         [Fact]
NETStandardDepends_Yes_Indirect_ExternallyResolved()678         public void NETStandardDepends_Yes_Indirect_ExternallyResolved()
679         {
680             ResolveAssemblyReference t = new ResolveAssemblyReference();
681 
682             t.BuildEngine = new MockEngine();
683 
684             t.Assemblies = new ITaskItem[]
685             {
686                 new TaskItem("netstandardlibrary"),
687             };
688 
689             t.Assemblies[0].SetMetadata("ExternallyResolved", "true");
690             t.Assemblies[0].SetMetadata("HintPath", s_netstandardLibraryDllPath);
691 
692             t.SearchPaths = DefaultPaths;
693 
694             // build mode
695             t.FindDependencies = true;
696 
697             Assert.True(t.Execute(
698                 fileExists,
699                 directoryExists,
700                 getDirectories,
701                 getAssemblyName,
702                 getAssemblyMetadata,
703 #if FEATURE_WIN32_REGISTRY
704                 getRegistrySubKeyNames,
705                 getRegistrySubKeyDefaultValue,
706 #endif
707                 getLastWriteTime,
708                 getRuntimeVersion,
709 #if FEATURE_WIN32_REGISTRY
710                 openBaseKey,
711 #endif
712                 checkIfAssemblyIsInGac,
713                 isWinMDFile,
714                 readMachineTypeFromPEHeader));
715 
716             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected netstandard dependency found during build."
717 
718             // intelli build mode
719             t.FindDependencies = false;
720             Assert.True(t.Execute(
721                 fileExists,
722                 directoryExists,
723                 getDirectories,
724                 getAssemblyName,
725                 getAssemblyMetadata,
726 #if FEATURE_WIN32_REGISTRY
727                 getRegistrySubKeyNames,
728                 getRegistrySubKeyDefaultValue,
729 #endif
730                 getLastWriteTime,
731                 getRuntimeVersion,
732 #if FEATURE_WIN32_REGISTRY
733                 openBaseKey,
734 #endif
735                 checkIfAssemblyIsInGac,
736                 isWinMDFile,
737                 readMachineTypeFromPEHeader));
738 
739             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected netstandard dependency found during intellibuild."
740         }
741 
742         [Fact]
DependsOn_NETStandard_and_SystemRuntime()743         public void DependsOn_NETStandard_and_SystemRuntime()
744         {
745             ResolveAssemblyReference t = new ResolveAssemblyReference();
746 
747             t.BuildEngine = new MockEngine();
748 
749             t.Assemblies = new ITaskItem[]
750             {
751                 new TaskItem("netstandardlibrary"),
752                 new TaskItem("Portable"),
753             };
754 
755             t.Assemblies[0].SetMetadata("HintPath", s_netstandardLibraryDllPath);
756             t.Assemblies[1].SetMetadata("HintPath", s_portableDllPath);
757 
758             t.SearchPaths = DefaultPaths;
759 
760             // build mode
761             t.FindDependencies = true;
762 
763             Assert.True(t.Execute(
764                 fileExists,
765                 directoryExists,
766                 getDirectories,
767                 getAssemblyName,
768                 getAssemblyMetadata,
769 #if FEATURE_WIN32_REGISTRY
770                 getRegistrySubKeyNames,
771                 getRegistrySubKeyDefaultValue,
772 #endif
773                 getLastWriteTime,
774                 getRuntimeVersion,
775 #if FEATURE_WIN32_REGISTRY
776                 openBaseKey,
777 #endif
778                 checkIfAssemblyIsInGac,
779                 isWinMDFile,
780                 readMachineTypeFromPEHeader));
781 
782             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
783             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                   "Expected netstandard dependency found during build."
784 
785             // intelli build mode
786             t.FindDependencies = false;
787             Assert.True(t.Execute(
788                 fileExists,
789                 directoryExists,
790                 getDirectories,
791                 getAssemblyName,
792                 getAssemblyMetadata,
793 #if FEATURE_WIN32_REGISTRY
794                 getRegistrySubKeyNames,
795                 getRegistrySubKeyDefaultValue,
796 #endif
797                 getLastWriteTime,
798                 getRuntimeVersion,
799 #if FEATURE_WIN32_REGISTRY
800                 openBaseKey,
801 #endif
802                 checkIfAssemblyIsInGac,
803                 isWinMDFile,
804                 readMachineTypeFromPEHeader));
805 
806             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
807             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                   "Expected netstandard dependency found during intellibuild."
808         }
809 
810         [Fact]
DependsOn_NETStandard_and_SystemRuntime_ExternallyResolved()811         public void DependsOn_NETStandard_and_SystemRuntime_ExternallyResolved()
812         {
813             ResolveAssemblyReference t = new ResolveAssemblyReference();
814 
815             t.BuildEngine = new MockEngine();
816 
817             t.Assemblies = new ITaskItem[]
818             {
819                 new TaskItem("netstandardlibrary"),
820                 new TaskItem("Portable"),
821             };
822 
823             t.Assemblies[0].SetMetadata("ExternallyResolved", "true");
824             t.Assemblies[0].SetMetadata("HintPath", s_netstandardLibraryDllPath);
825             t.Assemblies[1].SetMetadata("ExternallyResolved", "true");
826             t.Assemblies[1].SetMetadata("HintPath", s_portableDllPath);
827 
828             t.SearchPaths = DefaultPaths;
829 
830             // build mode
831             t.FindDependencies = true;
832 
833             Assert.True(t.Execute(
834                 fileExists,
835                 directoryExists,
836                 getDirectories,
837                 getAssemblyName,
838                 getAssemblyMetadata,
839 #if FEATURE_WIN32_REGISTRY
840                 getRegistrySubKeyNames,
841                 getRegistrySubKeyDefaultValue,
842 #endif
843                 getLastWriteTime,
844                 getRuntimeVersion,
845 #if FEATURE_WIN32_REGISTRY
846                 openBaseKey,
847 #endif
848                 checkIfAssemblyIsInGac,
849                 isWinMDFile,
850                 readMachineTypeFromPEHeader));
851 
852             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during build."
853             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                   "Expected netstandard dependency found during build."
854 
855             // intelli build mode
856             t.FindDependencies = false;
857             Assert.True(t.Execute(
858                 fileExists,
859                 directoryExists,
860                 getDirectories,
861                 getAssemblyName,
862                 getAssemblyMetadata,
863 #if FEATURE_WIN32_REGISTRY
864                 getRegistrySubKeyNames,
865                 getRegistrySubKeyDefaultValue,
866 #endif
867                 getLastWriteTime,
868                 getRuntimeVersion,
869 #if FEATURE_WIN32_REGISTRY
870                 openBaseKey,
871 #endif
872                 checkIfAssemblyIsInGac,
873                 isWinMDFile,
874                 readMachineTypeFromPEHeader));
875 
876             Assert.True(string.Equals(t.DependsOnSystemRuntime, "true", StringComparison.OrdinalIgnoreCase)); //                 "Expected System.Runtime dependency found during intellibuild."
877             Assert.True(string.Equals(t.DependsOnNETStandard, "true", StringComparison.OrdinalIgnoreCase)); //                   "Expected netstandard dependency found during intellibuild."
878         }
879 
880         #region HelperDelegates
881 
MockGetRuntimeVersion(string path)882         private static string MockGetRuntimeVersion(string path)
883         {
884             if (path.Equals(system1Path, StringComparison.OrdinalIgnoreCase))
885             {
886                 return "v2.0.50727";
887             }
888 
889             if (path.Equals(system4Path, StringComparison.OrdinalIgnoreCase))
890             {
891                 return "v4.0.0";
892             }
893 
894             if (path.Equals(system2Path, StringComparison.OrdinalIgnoreCase))
895             {
896                 return "v2.0.50727";
897             }
898 
899             return String.Empty;
900         }
901 
MockFileExists(string path)902         private bool MockFileExists(string path)
903         {
904             return true;
905         }
906 
MockGetPathFromFusionName(string strongName)907         private static string MockGetPathFromFusionName(string strongName)
908         {
909             if (strongName.Equals(system1, StringComparison.OrdinalIgnoreCase))
910             {
911                 return system1Path;
912             }
913 
914             if (strongName.Equals(system2, StringComparison.OrdinalIgnoreCase))
915             {
916                 return system2Path;
917             }
918 
919             if (strongName.Equals(systemNotStrong, StringComparison.OrdinalIgnoreCase))
920             {
921                 return system2Path;
922             }
923 
924             if (strongName.Equals(system4, StringComparison.OrdinalIgnoreCase))
925             {
926                 return system4Path;
927             }
928 
929             return String.Empty;
930         }
931 
MockAssemblyCacheEnumerator(string strongName)932         private static IEnumerable<AssemblyNameExtension> MockAssemblyCacheEnumerator(string strongName)
933         {
934             List<string> listOfAssemblies = new List<string>();
935 
936             if (strongName.StartsWith("System, Version=2.0.0.0", StringComparison.OrdinalIgnoreCase))
937             {
938                 listOfAssemblies.Add(system2);
939             }
940             else if (strongName.StartsWith("System, Version=4.0.0.0", StringComparison.OrdinalIgnoreCase))
941             {
942                 listOfAssemblies.Add(system4);
943             }
944             else
945             {
946                 listOfAssemblies.Add(system1);
947                 listOfAssemblies.Add(system2);
948                 listOfAssemblies.Add(system4);
949             }
950             return new MockEnumerator(listOfAssemblies);
951         }
952 
953         internal class MockEnumerator : IEnumerable<AssemblyNameExtension>
954         {
955             private List<string> _assembliesToEnumerate = null;
956             private List<string>.Enumerator _enumerator;
957 
MockEnumerator(List<string> assembliesToEnumerate)958             public MockEnumerator(List<string> assembliesToEnumerate)
959             {
960                 _assembliesToEnumerate = assembliesToEnumerate;
961 
962                 _enumerator = assembliesToEnumerate.GetEnumerator();
963             }
964 
965 
GetEnumerator()966             public IEnumerator<AssemblyNameExtension> GetEnumerator()
967             {
968                 foreach (string assembly in _assembliesToEnumerate)
969                 {
970                     yield return new AssemblyNameExtension(assembly);
971                 }
972             }
973 
IEnumerable.GetEnumerator()974             IEnumerator IEnumerable.GetEnumerator()
975             {
976                 return (IEnumerator)GetEnumerator();
977             }
978         }
979 
980         #endregion
981     }
982 }
983