-
Notifications
You must be signed in to change notification settings - Fork 152
/
TestAssemblyLoadContext.cs
143 lines (118 loc) · 5.17 KB
/
TestAssemblyLoadContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
#if NETCOREAPP3_1_OR_GREATER
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.IO;
using System;
using System.Linq;
namespace NUnit.Engine.Internal
{
internal sealed class TestAssemblyLoadContext : AssemblyLoadContext
{
private static readonly Logger log = InternalTrace.GetLogger(typeof(TestAssemblyLoadContext));
private readonly string _basePath;
private readonly TestAssemblyResolver _resolver;
private readonly System.Runtime.Loader.AssemblyDependencyResolver _runtimeResolver;
public TestAssemblyLoadContext(string testAssemblyPath)
{
_resolver = new TestAssemblyResolver(this, testAssemblyPath);
_basePath = Path.GetDirectoryName(testAssemblyPath);
_runtimeResolver = new AssemblyDependencyResolver(testAssemblyPath);
#if NET8_0_OR_GREATER
AppContext.SetData("APP_CONTEXT_BASE_DIRECTORY", _basePath);
#endif
}
protected override Assembly Load(AssemblyName name)
{
log.Debug("Loading {0} assembly", name);
var loadedAssembly = base.Load(name);
if (loadedAssembly != null)
{
log.Info("Assembly {0} ({1}) is loaded using default base.Load()", name, GetAssemblyLocationInfo(loadedAssembly));
return loadedAssembly;
}
var runtimeResolverPath = _runtimeResolver.ResolveAssemblyToPath(name);
if (string.IsNullOrEmpty(runtimeResolverPath) == false &&
File.Exists(runtimeResolverPath))
{
loadedAssembly = LoadFromAssemblyPath(runtimeResolverPath);
}
if (loadedAssembly != null)
{
log.Info("Assembly {0} ({1}) is loaded using the deps.json info", name, GetAssemblyLocationInfo(loadedAssembly));
return loadedAssembly;
}
loadedAssembly = _resolver.Resolve(this, name);
if (loadedAssembly != null)
{
log.Info("Assembly {0} ({1}) is loaded using the TestAssembliesResolver", name, GetAssemblyLocationInfo(loadedAssembly));
return loadedAssembly;
}
// Load assemblies that are dependencies, and in the same folder as the test assembly,
// but are not fully specified in test assembly deps.json file. This happens when the
// dependencies reference in the csproj file has CopyLocal=false, and for example, the
// reference is a projectReference and has the same output directory as the parent.
foreach (var extension in new string[] { ".dll", ".exe" })
{
string assemblyPath = Path.Combine(_basePath, name.Name + extension);
if (File.Exists(assemblyPath))
{
loadedAssembly = LoadFromAssemblyPath(assemblyPath);
break;
}
}
if (loadedAssembly != null)
{
log.Info("Assembly {0} ({1}) is loaded using base path", name, GetAssemblyLocationInfo(loadedAssembly));
return loadedAssembly;
}
return loadedAssembly;
}
protected override IntPtr LoadUnmanagedDll(string name)
{
log.Debug("Loading {0} unmanaged dll", name);
IntPtr loadedDllHandle = base.LoadUnmanagedDll(name);
if (loadedDllHandle != IntPtr.Zero)
{
log.Info("Unmanaged DLL {0} is loaded using default base.LoadUnmanagedDll()", name);
return loadedDllHandle;
}
string runtimeResolverPath = _runtimeResolver.ResolveUnmanagedDllToPath(name);
if (string.IsNullOrEmpty(runtimeResolverPath) == false &&
File.Exists(runtimeResolverPath))
{
loadedDllHandle = LoadUnmanagedDllFromPath(runtimeResolverPath);
}
if (loadedDllHandle != IntPtr.Zero)
{
log.Info("Unmanaged DLL {0} ({1}) is loaded using the deps.json info", name, runtimeResolverPath);
return loadedDllHandle;
}
string unmanagedDllPath = Path.Combine(_basePath, name + ".dll");
if (File.Exists(unmanagedDllPath))
{
loadedDllHandle = LoadUnmanagedDllFromPath(unmanagedDllPath);
}
if (loadedDllHandle != IntPtr.Zero)
{
log.Info("Unmanaged DLL {0} ({1}) is loaded using base path", name, unmanagedDllPath);
return loadedDllHandle;
}
return IntPtr.Zero;
}
private static string GetAssemblyLocationInfo(Assembly assembly)
{
if (assembly.IsDynamic)
{
return $"Dynamic {assembly.FullName}";
}
if (string.IsNullOrEmpty(assembly.Location))
{
return $"No location for {assembly.FullName}";
}
return $"{assembly.FullName} from {assembly.Location}";
}
}
}
#endif