@@ -24,6 +24,49 @@ import { TsConfigStore } from './tsconfig-store';
24
24
25
25
const diagnosticCollection = vscode . languages . createDiagnosticCollection ( 'ext-test-duplicates' ) ;
26
26
27
+ type TestNodeCountKind = '+' | '~' | '-' ;
28
+ class TestNodeCounter {
29
+ private counts : Map < NodeKind , Map < TestNodeCountKind , number > > = new Map ( ) ;
30
+
31
+ public add ( kind : NodeKind ) {
32
+ this . increment ( kind , '+' ) ;
33
+ }
34
+
35
+ public update ( kind : NodeKind ) {
36
+ this . increment ( kind , '~' ) ;
37
+ }
38
+
39
+ public remove ( kind : NodeKind ) {
40
+ this . increment ( kind , '-' ) ;
41
+ }
42
+
43
+ increment ( nodeKind : NodeKind , countKind : TestNodeCountKind ) {
44
+ let counts = this . counts . get ( nodeKind ) ;
45
+ if ( ! counts ) {
46
+ counts = new Map ( [
47
+ [ '+' , 0 ] ,
48
+ [ '~' , 0 ] ,
49
+ [ '-' , 0 ] ,
50
+ ] ) ;
51
+ this . counts . set ( nodeKind , counts ) ;
52
+ }
53
+ counts . set ( countKind , ( counts . get ( countKind ) ?? 0 ) + 1 ) ;
54
+ }
55
+
56
+ toString ( ) {
57
+ const s = [ ] ;
58
+ for ( const [ nodeKind , nodeKindV ] of this . counts ) {
59
+ const prefix = `${ NodeKind [ nodeKind ] } :` ;
60
+ const values = [ ] ;
61
+ for ( const [ countKind , count ] of nodeKindV ) {
62
+ values . push ( `${ countKind } ${ count } ` ) ;
63
+ }
64
+ s . push ( `${ prefix } ${ values . join ( ' ' ) } ` ) ;
65
+ }
66
+ return s . join ( '; ' ) ;
67
+ }
68
+ }
69
+
27
70
export class Controller {
28
71
private readonly disposables = new DisposableStore ( ) ;
29
72
public readonly configFile : ConfigurationFile ;
@@ -82,20 +125,21 @@ export class Controller {
82
125
configFileUri . fsPath ,
83
126
) ;
84
127
this . disposables . add ( ctrl ) ;
85
- this . configFile = this . disposables . add ( new ConfigurationFile ( configFileUri , wf ) ) ;
128
+ this . configFile = this . disposables . add ( new ConfigurationFile ( logChannel , configFileUri , wf ) ) ;
86
129
this . onDidDelete = this . configFile . onDidDelete ;
87
130
88
131
this . recreateDiscoverer ( ) ;
89
132
90
- const rescan = ( ) => {
133
+ const rescan = ( reason : string ) => {
134
+ logChannel . info ( `Rescan of tests triggered (${ reason } )` ) ;
91
135
this . recreateDiscoverer ( ) ;
92
136
this . scanFiles ( ) ;
93
137
} ;
94
- this . disposables . add ( this . configFile . onDidChange ( rescan ) ) ;
95
- this . disposables . add ( this . settings . onDidChange ( rescan ) ) ;
138
+ this . disposables . add ( this . configFile . onDidChange ( ( ) => rescan ( 'mocharc changed' ) ) ) ;
139
+ this . disposables . add ( this . settings . onDidChange ( ( ) => rescan ( 'settings changed' ) ) ) ;
96
140
ctrl . refreshHandler = ( ) => {
97
141
this . configFile . forget ( ) ;
98
- rescan ( ) ;
142
+ rescan ( 'user' ) ;
99
143
} ;
100
144
this . scanFiles ( ) ;
101
145
}
@@ -167,12 +211,15 @@ export class Controller {
167
211
}
168
212
169
213
if ( ! tree . length ) {
214
+ this . logChannel . info ( `No tests found in '${ uri . fsPath } '` ) ;
170
215
this . deleteFileTests ( uri . toString ( ) ) ;
171
216
return ;
172
217
}
173
218
174
219
const smMaintainer = previous ?. sourceMap ?? this . smStore . maintain ( uri ) ;
175
220
const sourceMap = await smMaintainer . refresh ( contents ) ;
221
+
222
+ const counter = new TestNodeCounter ( ) ;
176
223
const add = (
177
224
parent : vscode . TestItem ,
178
225
node : IParsedNode ,
@@ -182,10 +229,13 @@ export class Controller {
182
229
let item = parent . children . get ( node . name ) ;
183
230
if ( ! item ) {
184
231
item = this . ctrl . createTestItem ( node . name , node . name , start . uri ) ;
232
+ counter . add ( node . kind ) ;
185
233
testMetadata . set ( item , {
186
234
type : node . kind === NodeKind . Suite ? ItemType . Suite : ItemType . Test ,
187
235
} ) ;
188
236
parent . children . add ( item ) ;
237
+ } else {
238
+ counter . update ( node . kind ) ;
189
239
}
190
240
item . range = new vscode . Range ( start . range . start , end . range . end ) ;
191
241
item . error = node . error ;
@@ -206,9 +256,15 @@ export class Controller {
206
256
seen . set ( child . name , add ( item , child , start , end ) ) ;
207
257
}
208
258
209
- for ( const [ id ] of item . children ) {
259
+ for ( const [ id , child ] of item . children ) {
210
260
if ( ! seen . has ( id ) ) {
261
+ const meta = testMetadata . get ( child ) ;
211
262
item . children . delete ( id ) ;
263
+ if ( meta ?. type === ItemType . Test ) {
264
+ counter . remove ( NodeKind . Test ) ;
265
+ } else if ( meta ?. type === ItemType . Suite ) {
266
+ counter . remove ( NodeKind . Suite ) ;
267
+ }
212
268
}
213
269
}
214
270
@@ -234,11 +290,19 @@ export class Controller {
234
290
if ( previous ) {
235
291
for ( const [ id , test ] of previous . items ) {
236
292
if ( ! newTestsInFile . has ( id ) ) {
293
+ const meta = testMetadata . get ( test ) ;
237
294
( test . parent ?. children ?? this . ctrl . items ) . delete ( id ) ;
295
+ if ( meta ?. type === ItemType . Test ) {
296
+ counter . remove ( NodeKind . Test ) ;
297
+ } else if ( meta ?. type === ItemType . Suite ) {
298
+ counter . remove ( NodeKind . Suite ) ;
299
+ }
238
300
}
239
301
}
240
302
}
241
303
304
+ this . logChannel . info ( `Reloaded tests from '${ uri . fsPath } ' ${ counter } ` ) ;
305
+
242
306
this . testsInFiles . set ( uri . toString ( ) , { items : newTestsInFile , hash, sourceMap : smMaintainer } ) ;
243
307
this . didChangeEmitter . fire ( ) ;
244
308
}
@@ -353,7 +417,8 @@ export class Controller {
353
417
let configs : ConfigurationList ;
354
418
try {
355
419
configs = await this . configFile . read ( ) ;
356
- } catch {
420
+ } catch ( e ) {
421
+ this . logChannel . error ( e as Error , 'Failed to read config file' ) ;
357
422
this . handleScanError ( ) ;
358
423
return ;
359
424
}
0 commit comments