1515using System . Runtime . Loader ;
1616using NUnit . Common ;
1717using TestCentric . Metadata ;
18+ using System . Runtime . CompilerServices ;
1819
1920namespace NUnit . Engine . Internal
2021{
@@ -59,17 +60,17 @@ private void InitializeResolutionStrategies(AssemblyLoadContext loadContext, str
5960 ResolutionStrategies = new List < ResolutionStrategy > ( ) ;
6061
6162 if ( tryWindowsDesktopFirst )
62- ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
63+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( false ) ) ;
6364 if ( tryAspNetCoreFirst )
64- ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
65+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( false ) ) ;
6566
6667 ResolutionStrategies . Add ( new TrustedPlatformAssembliesStrategy ( ) ) ;
6768 ResolutionStrategies . Add ( new RuntimeLibrariesStrategy ( loadContext , testAssemblyPath ) ) ;
6869
6970 if ( ! tryWindowsDesktopFirst )
70- ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
71+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( false ) ) ;
7172 if ( ! tryAspNetCoreFirst )
72- ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
73+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( false ) ) ;
7374 }
7475
7576 public void Dispose ( )
@@ -93,173 +94,162 @@ public void Dispose()
9394 log . Info ( "Cannot resolve assembly '{0}'" , assemblyName ) ;
9495 return null ;
9596 }
97+ }
9698
97- #region Nested ResolutionStrategy Classes
99+ #region ResolutionStrategy Classes
98100
99- public abstract class ResolutionStrategy
101+ public abstract class ResolutionStrategy
102+ {
103+ public abstract bool TryToResolve (
104+ AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly ) ;
105+ }
106+
107+ public class TrustedPlatformAssembliesStrategy : ResolutionStrategy
108+ {
109+ private static readonly Logger log = InternalTrace . GetLogger ( typeof ( TrustedPlatformAssembliesStrategy ) ) ;
110+ public override bool TryToResolve (
111+ AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
100112 {
101- public abstract bool TryToResolve (
102- AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly ) ;
113+ return TryLoadFromTrustedPlatformAssemblies ( loadContext , assemblyName , out loadedAssembly ) ;
103114 }
104115
105- public class TrustedPlatformAssembliesStrategy : ResolutionStrategy
116+ private static bool TryLoadFromTrustedPlatformAssemblies (
117+ AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
106118 {
107- public override bool TryToResolve (
108- AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
119+ // https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing
120+ loadedAssembly = null ;
121+ var trustedAssemblies = System . AppContext . GetData ( "TRUSTED_PLATFORM_ASSEMBLIES" ) as string ;
122+ if ( string . IsNullOrEmpty ( trustedAssemblies ) )
109123 {
110- return TryLoadFromTrustedPlatformAssemblies ( loadContext , assemblyName , out loadedAssembly ) ;
124+ return false ;
111125 }
112126
113- private static bool TryLoadFromTrustedPlatformAssemblies (
114- AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
127+ var separator = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ? ";" : ":" ;
128+ foreach ( var assemblyPath in trustedAssemblies . Split ( separator ) )
115129 {
116- // https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing
117- loadedAssembly = null ;
118- var trustedAssemblies = System . AppContext . GetData ( "TRUSTED_PLATFORM_ASSEMBLIES" ) as string ;
119- if ( string . IsNullOrEmpty ( trustedAssemblies ) )
120- {
121- return false ;
122- }
123-
124- var separator = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ? ";" : ":" ;
125- foreach ( var assemblyPath in trustedAssemblies . Split ( separator ) )
130+ var fileName = Path . GetFileNameWithoutExtension ( assemblyPath ) ;
131+ if ( FileMatchesAssembly ( fileName ) && File . Exists ( assemblyPath ) )
126132 {
127- var fileName = Path . GetFileNameWithoutExtension ( assemblyPath ) ;
128- if ( FileMatchesAssembly ( fileName ) && File . Exists ( assemblyPath ) )
129- {
130- loadedAssembly = loadContext . LoadFromAssemblyPath ( assemblyPath ) ;
131- log . Info ( "'{0}' assembly is loaded from trusted path '{1}'" , assemblyPath , loadedAssembly . Location ) ;
133+ loadedAssembly = loadContext . LoadFromAssemblyPath ( assemblyPath ) ;
134+ log . Info ( "'{0}' assembly is loaded from trusted path '{1}'" , assemblyPath , loadedAssembly . Location ) ;
132135
133- return true ;
134- }
136+ return true ;
135137 }
138+ }
136139
137- return false ;
140+ return false ;
138141
139- bool FileMatchesAssembly ( string fileName ) =>
140- string . Equals ( fileName , assemblyName . Name , StringComparison . InvariantCultureIgnoreCase ) ;
141- }
142+ bool FileMatchesAssembly ( string fileName ) =>
143+ string . Equals ( fileName , assemblyName . Name , StringComparison . InvariantCultureIgnoreCase ) ;
142144 }
145+ }
143146
144- public class RuntimeLibrariesStrategy : ResolutionStrategy
147+ public class RuntimeLibrariesStrategy : ResolutionStrategy
148+ {
149+ private static readonly Logger log = InternalTrace . GetLogger ( typeof ( RuntimeLibrariesStrategy ) ) ;
150+
151+ private DependencyContext ? _dependencyContext ;
152+ private readonly CompositeCompilationAssemblyResolver _assemblyResolver ;
153+
154+ public RuntimeLibrariesStrategy ( AssemblyLoadContext loadContext , string testAssemblyPath )
145155 {
146- private DependencyContext ? _dependencyContext ;
147- private readonly CompositeCompilationAssemblyResolver _assemblyResolver ;
156+ _dependencyContext = DependencyContext . Load ( loadContext . LoadFromAssemblyPath ( testAssemblyPath ) ) ;
157+
158+ _assemblyResolver = new CompositeCompilationAssemblyResolver (
159+ [
160+ new AppBaseCompilationAssemblyResolver ( Path . GetDirectoryName ( testAssemblyPath ) ! ) ,
161+ new ReferenceAssemblyPathResolver ( ) ,
162+ new PackageCompilationAssemblyResolver ( )
163+ ] ) ;
164+ }
148165
149- public RuntimeLibrariesStrategy ( AssemblyLoadContext loadContext , string testAssemblyPath )
166+ public override bool TryToResolve (
167+ AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
168+ {
169+ if ( _dependencyContext is null )
150170 {
151- _dependencyContext = DependencyContext . Load ( loadContext . LoadFromAssemblyPath ( testAssemblyPath ) ) ;
152-
153- _assemblyResolver = new CompositeCompilationAssemblyResolver ( new ICompilationAssemblyResolver [ ]
154- {
155- new AppBaseCompilationAssemblyResolver ( Path . GetDirectoryName ( testAssemblyPath ) ! ) ,
156- new ReferenceAssemblyPathResolver ( ) ,
157- new PackageCompilationAssemblyResolver ( )
158- } ) ;
171+ // TODO: Is this the intended behavior?
172+ loadedAssembly = null ;
173+ return false ;
159174 }
160175
161- public override bool TryToResolve (
162- AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
176+ foreach ( var library in _dependencyContext . RuntimeLibraries )
163177 {
164- if ( _dependencyContext is null )
178+ var wrapper = new CompilationLibrary (
179+ library . Type ,
180+ library . Name ,
181+ library . Version ,
182+ library . Hash ,
183+ library . RuntimeAssemblyGroups . SelectMany ( g => g . AssetPaths ) ,
184+ library . Dependencies ,
185+ library . Serviceable ) ;
186+
187+ var assemblies = new List < string > ( ) ;
188+ _assemblyResolver . TryResolveAssemblyPaths ( wrapper , assemblies ) ;
189+
190+ foreach ( var assemblyPath in assemblies )
165191 {
166- // TODO: Is this the intended behavior?
167- loadedAssembly = null ;
168- return false ;
169- }
170-
171- foreach ( var library in _dependencyContext . RuntimeLibraries )
172- {
173- var wrapper = new CompilationLibrary (
174- library . Type ,
175- library . Name ,
176- library . Version ,
177- library . Hash ,
178- library . RuntimeAssemblyGroups . SelectMany ( g => g . AssetPaths ) ,
179- library . Dependencies ,
180- library . Serviceable ) ;
181-
182- var assemblies = new List < string > ( ) ;
183- _assemblyResolver . TryResolveAssemblyPaths ( wrapper , assemblies ) ;
184-
185- foreach ( var assemblyPath in assemblies )
192+ if ( assemblyName . Name == Path . GetFileNameWithoutExtension ( assemblyPath ) )
186193 {
187- if ( assemblyName . Name == Path . GetFileNameWithoutExtension ( assemblyPath ) )
188- {
189- loadedAssembly = loadContext . LoadFromAssemblyPath ( assemblyPath ) ;
190- log . Info ( "'{0}' ({1}) assembly is loaded from runtime libraries {2} dependencies" ,
191- assemblyName ,
192- loadedAssembly . Location ,
193- library . Name ) ;
194-
195- return true ;
196- }
194+ loadedAssembly = loadContext . LoadFromAssemblyPath ( assemblyPath ) ;
195+ log . Info ( "'{0}' ({1}) assembly is loaded from runtime libraries {2} dependencies" ,
196+ assemblyName ,
197+ loadedAssembly . Location ,
198+ library . Name ) ;
199+
200+ return true ;
197201 }
198202 }
199-
200- loadedAssembly = null ;
201- return false ;
202203 }
203- }
204204
205- public class AdditionalRuntimesStrategy : ResolutionStrategy
206- {
207- private readonly IEnumerable < DotNet . RuntimeInfo > _additionalRuntimes ;
208-
209- public AdditionalRuntimesStrategy ( string runtimeName )
210- {
211- _additionalRuntimes = DotNet . GetRuntimes ( runtimeName , ! Environment . Is64BitProcess ) ;
212- }
213-
214- public override bool TryToResolve ( AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
215- {
216- loadedAssembly = null ;
217-
218- if ( ! FindBestRuntime ( assemblyName , out DotNet . RuntimeInfo ? runtime ) )
219- return false ;
205+ loadedAssembly = null ;
206+ return false ;
207+ }
208+ }
220209
221- string candidate = Path . Combine ( runtime . Path , runtime . Version . ToString ( ) , assemblyName . Name + ".dll" ) ;
222- if ( ! File . Exists ( candidate ) )
223- return false ;
210+ public class AdditionalRuntimesStrategy : ResolutionStrategy
211+ {
212+ private string _runtimeName ;
213+ private bool _x86 ;
224214
225- loadedAssembly = loadContext . LoadFromAssemblyPath ( candidate ) ;
226- return true ;
227- }
215+ public AdditionalRuntimesStrategy ( string runtimeName , bool x86 )
216+ {
217+ _runtimeName = runtimeName ;
218+ _x86 = x86 ;
219+ }
228220
229- private bool FindBestRuntime ( AssemblyName assemblyName , [ NotNullWhen ( true ) ] out DotNet . RuntimeInfo ? bestRuntime )
230- {
231- bestRuntime = null ;
232- var targetVersion = assemblyName . Version ;
221+ public override bool TryToResolve ( AssemblyLoadContext loadContext , AssemblyName assemblyName , [ NotNullWhen ( true ) ] out Assembly ? loadedAssembly )
222+ {
223+ loadedAssembly = null ;
224+ if ( assemblyName . Version is null )
225+ return false ;
233226
234- if ( targetVersion is null )
235- return false ;
227+ if ( ! DotNet . FindBestRuntime ( assemblyName . Version , _runtimeName , _x86 , out DotNet . RuntimeInfo ? runtime ) )
228+ return false ;
236229
237- foreach ( var candidate in _additionalRuntimes )
238- {
239- if ( candidate . Version >= targetVersion )
240- if ( bestRuntime is null || bestRuntime . Version > candidate . Version )
241- bestRuntime = candidate ;
242- }
230+ string candidate = Path . Combine ( runtime . Path , runtime . Version . ToString ( ) , assemblyName . Name + ".dll" ) ;
231+ if ( ! File . Exists ( candidate ) )
232+ return false ;
243233
244- return bestRuntime is not null ;
245- }
234+ loadedAssembly = loadContext . LoadFromAssemblyPath ( candidate ) ;
235+ return true ;
246236 }
237+ }
247238
248- public class WindowsDesktopStrategy : AdditionalRuntimesStrategy
239+ public class WindowsDesktopStrategy : AdditionalRuntimesStrategy
240+ {
241+ public WindowsDesktopStrategy ( bool x86 ) : base ( "Microsoft.WindowsDesktop.App" , x86 )
249242 {
250- public WindowsDesktopStrategy ( ) : base ( "Microsoft.WindowsDesktop.App" )
251- {
252- }
253243 }
244+ }
254245
255- public class AspNetCoreStrategy : AdditionalRuntimesStrategy
246+ public class AspNetCoreStrategy : AdditionalRuntimesStrategy
247+ {
248+ public AspNetCoreStrategy ( bool x86 ) : base ( "Microsoft.AspNetCore.App" , x86 )
256249 {
257- public AspNetCoreStrategy ( ) : base ( "Microsoft.AspNetCore.App" )
258- {
259- }
260250 }
251+ }
261252
262253 #endregion
263- }
264254}
265255#endif
0 commit comments