5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
7
using System . IO ;
8
+ using System . Linq ;
8
9
using System . Reflection ;
9
10
using System . Runtime . CompilerServices ;
10
11
using System . Runtime . InteropServices ;
12
+ using System . Text ;
11
13
using Microsoft . Extensions . DependencyInjection ;
12
14
using Serilog ;
13
15
using Serilog . Extensions . Logging ;
@@ -20,6 +22,14 @@ public class AssemblyTestLog : IDisposable
20
22
public static readonly string OutputDirectoryEnvironmentVariableName = "ASPNETCORE_TEST_LOG_DIR" ;
21
23
private static readonly string LogFileExtension = ".log" ;
22
24
private static readonly int MaxPathLength = 245 ;
25
+ private static char [ ] InvalidFileChars = new char [ ]
26
+ {
27
+ '\" ' , '<' , '>' , '|' , '\0 ' ,
28
+ ( char ) 1 , ( char ) 2 , ( char ) 3 , ( char ) 4 , ( char ) 5 , ( char ) 6 , ( char ) 7 , ( char ) 8 , ( char ) 9 , ( char ) 10 ,
29
+ ( char ) 11 , ( char ) 12 , ( char ) 13 , ( char ) 14 , ( char ) 15 , ( char ) 16 , ( char ) 17 , ( char ) 18 , ( char ) 19 , ( char ) 20 ,
30
+ ( char ) 21 , ( char ) 22 , ( char ) 23 , ( char ) 24 , ( char ) 25 , ( char ) 26 , ( char ) 27 , ( char ) 28 , ( char ) 29 , ( char ) 30 ,
31
+ ( char ) 31 , ':' , '*' , '?' , '\\ ' , '/' , ' ' , ( char ) 127
32
+ } ;
23
33
24
34
private static readonly object _lock = new object ( ) ;
25
35
private static readonly Dictionary < Assembly , AssemblyTestLog > _logs = new Dictionary < Assembly , AssemblyTestLog > ( ) ;
@@ -42,9 +52,12 @@ private AssemblyTestLog(ILoggerFactory globalLoggerFactory, ILogger globalLogger
42
52
public IDisposable StartTestLog ( ITestOutputHelper output , string className , out ILoggerFactory loggerFactory , [ CallerMemberName ] string testName = null ) =>
43
53
StartTestLog ( output , className , out loggerFactory , LogLevel . Debug , testName ) ;
44
54
45
- public IDisposable StartTestLog ( ITestOutputHelper output , string className , out ILoggerFactory loggerFactory , LogLevel minLogLevel , [ CallerMemberName ] string testName = null )
55
+ public IDisposable StartTestLog ( ITestOutputHelper output , string className , out ILoggerFactory loggerFactory , LogLevel minLogLevel , [ CallerMemberName ] string testName = null ) =>
56
+ StartTestLog ( output , className , out loggerFactory , minLogLevel , out var _ , testName ) ;
57
+
58
+ internal IDisposable StartTestLog ( ITestOutputHelper output , string className , out ILoggerFactory loggerFactory , LogLevel minLogLevel , out string resolvedTestName , [ CallerMemberName ] string testName = null )
46
59
{
47
- var serviceProvider = CreateLoggerServices ( output , className , minLogLevel , testName ) ;
60
+ var serviceProvider = CreateLoggerServices ( output , className , minLogLevel , out resolvedTestName , testName ) ;
48
61
var factory = serviceProvider . GetRequiredService < ILoggerFactory > ( ) ;
49
62
loggerFactory = factory ;
50
63
var logger = loggerFactory . CreateLogger ( "TestLifetime" ) ;
@@ -72,11 +85,13 @@ public ILoggerFactory CreateLoggerFactory(ITestOutputHelper output, string class
72
85
73
86
public ILoggerFactory CreateLoggerFactory ( ITestOutputHelper output , string className , LogLevel minLogLevel , [ CallerMemberName ] string testName = null )
74
87
{
75
- return CreateLoggerServices ( output , className , minLogLevel , testName ) . GetRequiredService < ILoggerFactory > ( ) ;
88
+ return CreateLoggerServices ( output , className , minLogLevel , out var _ , testName ) . GetRequiredService < ILoggerFactory > ( ) ;
76
89
}
77
90
78
- public IServiceProvider CreateLoggerServices ( ITestOutputHelper output , string className , LogLevel minLogLevel , [ CallerMemberName ] string testName = null )
91
+ public IServiceProvider CreateLoggerServices ( ITestOutputHelper output , string className , LogLevel minLogLevel , out string normalizedTestName , [ CallerMemberName ] string testName = null )
79
92
{
93
+ normalizedTestName = string . Empty ;
94
+
80
95
// Try to shorten the class name using the assembly name
81
96
if ( className . StartsWith ( _assemblyName + "." ) )
82
97
{
@@ -87,6 +102,7 @@ public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string cl
87
102
if ( ! string . IsNullOrEmpty ( _baseDirectory ) )
88
103
{
89
104
var testOutputDirectory = Path . Combine ( GetAssemblyBaseDirectory ( _assemblyName , _baseDirectory ) , className ) ;
105
+ testName = RemoveIllegalFileChars ( testName ) ;
90
106
91
107
if ( testOutputDirectory . Length + testName . Length + LogFileExtension . Length >= MaxPathLength )
92
108
{
@@ -118,11 +134,13 @@ public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string cl
118
134
if ( ! File . Exists ( testOutputFile ) )
119
135
{
120
136
_globalLogger . LogWarning ( $ "To resolve log file collision, the enumerated file { testOutputFile } will be used.") ;
137
+ testName = $ "{ testName } .{ i } ";
121
138
break ;
122
139
}
123
140
}
124
141
}
125
142
143
+ normalizedTestName = testName ;
126
144
serilogLoggerProvider = ConfigureFileLogging ( testOutputFile ) ;
127
145
}
128
146
@@ -234,6 +252,17 @@ private static SerilogLoggerProvider ConfigureFileLogging(string fileName)
234
252
return new SerilogLoggerProvider ( serilogger , dispose : true ) ;
235
253
}
236
254
255
+ private static string RemoveIllegalFileChars ( string s )
256
+ {
257
+ var sb = new StringBuilder ( ) ;
258
+
259
+ foreach ( var c in s )
260
+ {
261
+ sb . Append ( InvalidFileChars . Contains ( c ) ? '_' : c ) ;
262
+ }
263
+ return sb . ToString ( ) ;
264
+ }
265
+
237
266
public void Dispose ( )
238
267
{
239
268
( _serviceProvider as IDisposable ) ? . Dispose ( ) ;
0 commit comments