1
1
#nullable enable
2
2
using System ;
3
+ using System . Diagnostics ;
4
+ using System . Diagnostics . CodeAnalysis ;
3
5
using System . IO ;
4
6
using System . Linq ;
5
7
using System . Reflection ;
@@ -25,40 +27,69 @@ public static InMemorySinkAssertions Should(this InMemorySink instance)
25
27
throw new Exception ( $ "Unable to determine path to load assemblies from") ;
26
28
}
27
29
28
- var fluentAssertionsAssembly = AppDomain
29
- . CurrentDomain
30
- . GetAssemblies ( )
31
- . FirstOrDefault ( assembly => assembly . GetName ( ) . Name . Equals ( "FluentAssertions" ) ) ;
30
+ string ? adapterName = null ;
31
+ int ? majorVersion = null ;
32
+ Assembly ? versionedAssembly = null ;
33
+
34
+ // Order is important here, first check the loaded assemblies before
35
+ // looking on disk because otherwise we might load FluentAssertions from disk
36
+ // while Shouldly is already loaded into the AppDomain and that's the one we
37
+ // should be using.
38
+ // That's also a guess but hey, if you mix and match assertion frameworks you
39
+ // can deal with the fall out.
40
+ if ( IsFluentAssertionsAlreadyLoadedIntoDomain ( out var fluentAssertionsAssembly ) )
41
+ {
42
+ adapterName = "FluentAssertions" ;
43
+ majorVersion = fluentAssertionsAssembly . GetName ( ) . Version . Major ;
44
+ }
45
+ else if ( IsAwesomeAssertionsAlreadyLoadedIntoDomain ( out var awesomeAssertionsAssembly ) )
46
+ {
47
+ adapterName = "AwesomeAssertions" ;
48
+ majorVersion = awesomeAssertionsAssembly . GetName ( ) . Version . Major ;
49
+ }
50
+ else if ( IsShouldlyAlreadyLoadedIntoDomain ( out var shouldlyAssembly ) )
51
+ {
52
+ adapterName = "Shouldly" ;
53
+ majorVersion = shouldlyAssembly . GetName ( ) . Version . Major ;
54
+ }
55
+ else if ( IsFluentAssertionsAvailableOnDisk ( assemblyLocation ,
56
+ out var fluentAssertionsOnDiskAssembly ) )
57
+ {
58
+ adapterName = "FluentAssertions" ;
59
+ majorVersion = fluentAssertionsOnDiskAssembly . GetName ( ) . Version . Major ;
60
+ }
61
+ else if ( IsAwesomeAssertionsAvailableOnDisk ( assemblyLocation ,
62
+ out var awesomeAssertionsOnDiskAssembly ) )
63
+ {
64
+ adapterName = "AwesomeAssertions" ;
65
+ majorVersion = awesomeAssertionsOnDiskAssembly . GetName ( ) . Version . Major ;
66
+ }
67
+ else if ( IsShouldlyAvailableOnDisk ( assemblyLocation , out var shouldlyOnDiskAssembly ) )
68
+ {
69
+ adapterName = "Shouldly" ;
70
+ majorVersion = shouldlyOnDiskAssembly . GetName ( ) . Version . Major ;
71
+ }
32
72
33
- if ( fluentAssertionsAssembly = = null )
73
+ if ( adapterName != null && majorVersion ! = null )
34
74
{
35
- var fluentAssertionsAssemblyPath = Path . Combine ( assemblyLocation , "FluentAssertions.dll" ) ;
75
+ var versionedLocation = Path . Combine (
76
+ assemblyLocation ,
77
+ $ "Serilog.Sinks.InMemory.{ adapterName } { majorVersion } .dll") ;
36
78
37
- try
79
+ if ( ! File . Exists ( versionedLocation ) )
38
80
{
39
- fluentAssertionsAssembly = Assembly . LoadFile ( fluentAssertionsAssemblyPath ) ;
40
- }
41
- catch ( FileNotFoundException e )
42
- {
43
- throw new Exception ( $ "Could not find assembly '{ fluentAssertionsAssemblyPath } '", e ) ;
81
+ throw new InvalidOperationException ( $ "Detected { adapterName } version { majorVersion } but the assertions adapter wasn't found on disk") ;
44
82
}
83
+
84
+ versionedAssembly = Assembly . LoadFile ( versionedLocation ) ;
45
85
}
46
86
47
- var assertionLibrary = IsAwesomeAssertions ( fluentAssertionsAssembly )
48
- ? "AwesomeAssertions"
49
- : "FluentAssertions" ;
50
-
51
- var fluentAssertionsMajorVersion = fluentAssertionsAssembly . GetName ( ) . Version . Major ;
52
-
53
- var versionedLocation = Path . Combine (
54
- assemblyLocation ,
55
- $ "Serilog.Sinks.InMemory.{ assertionLibrary } { fluentAssertionsMajorVersion } .dll") ;
56
-
57
- var versionedAssembly = Assembly . LoadFile ( versionedLocation ) ;
58
-
59
- _assertionsType = versionedAssembly
60
- . GetTypes ( )
61
- . SingleOrDefault ( t => t . Name == "InMemorySinkAssertionsImpl" ) ;
87
+ if ( versionedAssembly != null )
88
+ {
89
+ _assertionsType = versionedAssembly
90
+ . GetTypes ( )
91
+ . SingleOrDefault ( t => t . Name == "InMemorySinkAssertionsImpl" ) ;
92
+ }
62
93
}
63
94
}
64
95
@@ -68,17 +99,114 @@ public static InMemorySinkAssertions Should(this InMemorySink instance)
68
99
}
69
100
70
101
var snapshotInstance = SnapshotOf ( instance ) ;
71
-
102
+
72
103
return ( InMemorySinkAssertions ) Activator . CreateInstance (
73
104
_assertionsType , snapshotInstance ) ;
74
105
}
75
106
76
- private static bool IsAwesomeAssertions ( Assembly fluentAssertionsAssembly )
107
+ private static bool IsFluentAssertionsAlreadyLoadedIntoDomain (
108
+ [ NotNullWhen ( true ) ] out Assembly ? fluentAssertionsAssembly )
109
+ {
110
+ fluentAssertionsAssembly = AppDomain
111
+ . CurrentDomain
112
+ . GetAssemblies ( )
113
+ . FirstOrDefault ( assembly =>
114
+ {
115
+ if ( assembly . GetName ( ) . Name . Equals ( "FluentAssertions" ) )
116
+ {
117
+ var metadataAttributes = assembly . GetCustomAttributes < AssemblyMetadataAttribute > ( ) . ToArray ( ) ;
118
+
119
+ return ! metadataAttributes . Any ( ) ||
120
+ metadataAttributes . Any ( metadata => metadata . Value . Contains ( "FluentAssertions" , StringComparison . OrdinalIgnoreCase ) ) ;
121
+ }
122
+
123
+ return false ;
124
+ } ) ;
125
+
126
+ return fluentAssertionsAssembly != null ;
127
+ }
128
+
129
+ private static bool IsAwesomeAssertionsAlreadyLoadedIntoDomain (
130
+ [ NotNullWhen ( true ) ] out Assembly ? awesomeAssertionsAssembly )
77
131
{
78
- var assemblyMetadata = fluentAssertionsAssembly . GetCustomAttributes < AssemblyMetadataAttribute > ( ) ;
132
+ awesomeAssertionsAssembly = AppDomain
133
+ . CurrentDomain
134
+ . GetAssemblies ( )
135
+ . FirstOrDefault ( assembly =>
136
+ assembly . GetName ( ) . Name . Equals ( "FluentAssertions" ) &&
137
+ assembly . GetCustomAttributes < AssemblyMetadataAttribute > ( )
138
+ . Any ( metadata => metadata . Value . Contains ( "AwesomeAssertions" , StringComparison . OrdinalIgnoreCase ) ) ) ;
139
+
140
+ return awesomeAssertionsAssembly != null ;
141
+ }
142
+
143
+ private static bool IsShouldlyAlreadyLoadedIntoDomain ( [ NotNullWhen ( true ) ] out Assembly ? shouldlyAssembly )
144
+ {
145
+ shouldlyAssembly = AppDomain
146
+ . CurrentDomain
147
+ . GetAssemblies ( )
148
+ . FirstOrDefault ( assembly => assembly . GetName ( ) . Name . Equals ( "Shouldly" ) ) ;
149
+
150
+ return shouldlyAssembly != null ;
151
+ }
152
+
153
+ private static bool IsFluentAssertionsAvailableOnDisk (
154
+ string assemblyLocation ,
155
+ [ NotNullWhen ( true ) ] out Assembly ? assembly )
156
+ {
157
+ var assemblyPath = Path . Combine ( assemblyLocation , "FluentAssertions.dll" ) ;
158
+
159
+ if ( File . Exists ( assemblyPath ) )
160
+ {
161
+ assembly = Assembly . LoadFile ( assemblyPath ) ;
162
+
163
+ var metadataAttributes = assembly . GetCustomAttributes < AssemblyMetadataAttribute > ( ) . ToList ( ) ;
164
+
165
+ if ( ! metadataAttributes . Any ( ) || metadataAttributes . Any ( metadata => metadata . Value . Contains ( "FluentAssertions" , StringComparison . OrdinalIgnoreCase ) ) )
166
+ {
167
+ return true ;
168
+ }
169
+ }
170
+
171
+ assembly = null ;
172
+ return false ;
173
+ }
174
+
175
+ private static bool IsAwesomeAssertionsAvailableOnDisk (
176
+ string assemblyLocation ,
177
+ [ NotNullWhen ( true ) ] out Assembly ? assembly )
178
+ {
179
+ var assemblyPath = Path . Combine ( assemblyLocation , "FluentAssertions.dll" ) ;
180
+
181
+ if ( File . Exists ( assemblyPath ) )
182
+ {
183
+ assembly = Assembly . LoadFile ( assemblyPath ) ;
184
+
185
+ if ( assembly . GetCustomAttributes < AssemblyMetadataAttribute > ( )
186
+ . Any ( metadata => metadata . Value . Contains ( "AwesomeAssertions" , StringComparison . OrdinalIgnoreCase ) ) )
187
+ {
188
+ return true ;
189
+ }
190
+ }
191
+
192
+ assembly = null ;
193
+ return false ;
194
+ }
195
+
196
+ private static bool IsShouldlyAvailableOnDisk (
197
+ string assemblyLocation ,
198
+ [ NotNullWhen ( true ) ] out Assembly ? assembly )
199
+ {
200
+ var assemblyPath = Path . Combine ( assemblyLocation , "Shouldly.dll" ) ;
201
+
202
+ if ( File . Exists ( assemblyPath ) )
203
+ {
204
+ assembly = Assembly . LoadFile ( assemblyPath ) ;
205
+ return true ;
206
+ }
79
207
80
- // Yuck yuck yuck
81
- return assemblyMetadata . Any ( metadata => metadata . Value . Contains ( "AwesomeAssertions" ) ) ;
208
+ assembly = null ;
209
+ return false ;
82
210
}
83
211
84
212
/*
0 commit comments