1
1
using System ;
2
+ using System . Diagnostics ;
3
+ using System . IO ;
4
+ using System . Linq ;
5
+ using System . Reflection ;
6
+ using System . Runtime . ExceptionServices ;
7
+ using System . Xml . Linq ;
2
8
using PublicApiGenerator ;
3
9
using Shouldly ;
4
10
using Xunit ;
@@ -22,17 +28,57 @@ public class ApiApprovalTests
22
28
[ InlineData ( typeof ( Server . Transports . WebSockets . WebSocketTransport ) ) ]
23
29
public void public_api_should_not_change_unintentionally ( Type type )
24
30
{
25
- string publicApi = type . Assembly . GeneratePublicApi ( new ApiGeneratorOptions
31
+ string baseDir = AppDomain . CurrentDomain . BaseDirectory ;
32
+ string projectName = type . Assembly . GetName ( ) . Name ! ;
33
+ string projectFolderName = projectName [ "GraphQL.Server." . Length ..] ;
34
+ string projectDir = Path . Combine ( baseDir , $ "..{ Path . DirectorySeparatorChar } ..{ Path . DirectorySeparatorChar } ..{ Path . DirectorySeparatorChar } ..{ Path . DirectorySeparatorChar } ..", "src" ) ;
35
+ string buildDir = Path . Combine ( projectDir , projectFolderName , "bin" , "Debug" ) ;
36
+ Debug . Assert ( Directory . Exists ( buildDir ) , $ "Directory '{ buildDir } ' doesn't exist") ;
37
+ string csProject = Path . Combine ( projectDir , projectFolderName , projectFolderName + ".csproj" ) ;
38
+ var project = XDocument . Load ( csProject ) ;
39
+ string [ ] tfms = project . Descendants ( "TargetFrameworks" ) . Union ( project . Descendants ( "TargetFramework" ) ) . First ( ) . Value . Split ( ";" , StringSplitOptions . RemoveEmptyEntries ) ;
40
+
41
+ // There may be old stuff from earlier builds like net45, netcoreapp3.0, etc. so filter it out
42
+ string [ ] actualTfmDirs = Directory . GetDirectories ( buildDir ) . Where ( dir => tfms . Any ( tfm => dir . EndsWith ( tfm ) ) ) . ToArray ( ) ;
43
+ Debug . Assert ( actualTfmDirs . Length > 0 , $ "Directory '{ buildDir } ' doesn't contain subdirectories matching { string . Join ( ";" , tfms ) } ") ;
44
+
45
+ ( string tfm , string content ) [ ] publicApi = actualTfmDirs . Select ( tfmDir => ( new DirectoryInfo ( tfmDir ) . Name . Replace ( "." , "" ) , Assembly . LoadFile ( Path . Combine ( tfmDir , projectName + ".dll" ) ) . GeneratePublicApi ( new ApiGeneratorOptions
26
46
{
27
47
IncludeAssemblyAttributes = false ,
28
- WhitelistedNamespacePrefixes = new [ ] { "Microsoft." }
29
- } ) ;
48
+ WhitelistedNamespacePrefixes = new [ ] { "Microsoft." } ,
49
+ ExcludeAttributes = new [ ] { "System.Diagnostics.DebuggerDisplayAttribute" , "System.Diagnostics.CodeAnalysis.AllowNullAttribute" }
50
+ } ) ) ) . ToArray ( ) ;
30
51
31
52
// See: https://shouldly.readthedocs.io/en/latest/assertions/shouldMatchApproved.html
32
53
// Note: If the AssemblyName.approved.txt file doesn't match the latest publicApi value,
33
54
// this call will try to launch a diff tool to help you out but that can fail on
34
55
// your machine if a diff tool isn't configured/setup.
35
- publicApi . ShouldMatchApproved ( options => options . WithFilenameGenerator ( ( testMethodInfo , discriminator , fileType , fileExtension ) => $ "{ type . Assembly . GetName ( ) . Name } .{ fileType } .{ fileExtension } ") ) ;
56
+ if ( publicApi . DistinctBy ( item => item . content ) . Count ( ) == 1 )
57
+ {
58
+ publicApi [ 0 ] . content . ShouldMatchApproved ( options => options . NoDiff ( ) . WithFilenameGenerator ( ( testMethodInfo , discriminator , fileType , fileExtension ) => $ "{ type . Assembly . GetName ( ) . Name } .{ fileType } .{ fileExtension } ") ) ;
59
+ }
60
+ else
61
+ {
62
+ // https://github.com/graphql-dotnet/server/pull/675#issuecomment-1001283947
63
+ ExceptionDispatchInfo ? error = null ;
64
+
65
+ var uniqueApi = publicApi . ToLookup ( item => item . content ) ;
66
+ foreach ( var item in uniqueApi )
67
+ {
68
+ try
69
+ {
70
+ item . Key . ShouldMatchApproved ( options => options . SubFolder ( string . Join ( "+" , item . Select ( x => x . tfm ) . OrderBy ( x => x ) ) ) . NoDiff ( ) . WithFilenameGenerator ( ( testMethodInfo , discriminator , fileType , fileExtension ) => $ "{ type . Assembly . GetName ( ) . Name } .{ fileType } .{ fileExtension } ") ) ;
71
+ }
72
+ catch ( Exception ex )
73
+ {
74
+ error = ExceptionDispatchInfo . Capture ( ex ) ;
75
+ }
76
+ }
77
+
78
+ // It's OK to throw any exception occurred.
79
+ if ( error != null )
80
+ error . Throw ( ) ;
81
+ }
36
82
}
37
83
}
38
84
}
0 commit comments