@@ -22,11 +22,15 @@ import { execFile, getErrorDescription } from "../utilities/utilities";
22
22
import { createSwiftTask } from "../tasks/SwiftTaskProvider" ;
23
23
import configuration from "../configuration" ;
24
24
import { WorkspaceContext } from "../WorkspaceContext" ;
25
- import { XCTestOutputParser } from "./TestParsers/XCTestOutputParser" ;
25
+ import {
26
+ IXCTestOutputParser ,
27
+ ParallelXCTestOutputParser ,
28
+ XCTestOutputParser ,
29
+ } from "./TestParsers/XCTestOutputParser" ;
26
30
import { SwiftTestingOutputParser } from "./TestParsers/SwiftTestingOutputParser" ;
27
31
import { LoggingDebugAdapterTracker } from "../debugger/logTracker" ;
28
32
import { TaskOperation } from "../tasks/TaskQueue" ;
29
- import { TestXUnitParser , iXUnitTestState } from "./TestXUnitParser" ;
33
+ import { TestXUnitParser } from "./TestXUnitParser" ;
30
34
import { ITestRunState } from "./TestParsers/TestRunState" ;
31
35
import { TestRunArguments } from "./TestRunArguments" ;
32
36
import { TemporaryFolder } from "../utilities/tempFolder" ;
@@ -68,7 +72,10 @@ export class TestRunProxy {
68
72
69
73
// Allows for introspection on the state of TestItems after a test run.
70
74
public runState = {
71
- failed : [ ] as vscode . TestItem [ ] ,
75
+ failed : [ ] as {
76
+ test : vscode . TestItem ;
77
+ message : vscode . TestMessage | readonly vscode . TestMessage [ ] ;
78
+ } [ ] ,
72
79
passed : [ ] as vscode . TestItem [ ] ,
73
80
skipped : [ ] as vscode . TestItem [ ] ,
74
81
errored : [ ] as vscode . TestItem [ ] ,
@@ -179,7 +186,7 @@ export class TestRunProxy {
179
186
message : vscode . TestMessage | readonly vscode . TestMessage [ ] ,
180
187
duration ?: number
181
188
) {
182
- this . runState . failed . push ( test ) ;
189
+ this . runState . failed . push ( { test, message } ) ;
183
190
this . testRun ?. failed ( test , message , duration ) ;
184
191
}
185
192
@@ -218,7 +225,7 @@ export class TestRunProxy {
218
225
export class TestRunner {
219
226
private testRun : TestRunProxy ;
220
227
private testArgs : TestRunArguments ;
221
- private xcTestOutputParser : XCTestOutputParser ;
228
+ private xcTestOutputParser : IXCTestOutputParser ;
222
229
private swiftTestOutputParser : SwiftTestingOutputParser ;
223
230
224
231
/**
@@ -228,13 +235,19 @@ export class TestRunner {
228
235
* @param controller Test controller
229
236
*/
230
237
constructor (
238
+ private testKind : TestKind ,
231
239
private request : vscode . TestRunRequest ,
232
240
private folderContext : FolderContext ,
233
241
private controller : vscode . TestController
234
242
) {
235
243
this . testArgs = new TestRunArguments ( this . ensureRequestIncludesTests ( this . request ) ) ;
236
244
this . testRun = new TestRunProxy ( request , controller , this . testArgs , folderContext ) ;
237
- this . xcTestOutputParser = new XCTestOutputParser ( ) ;
245
+ this . xcTestOutputParser =
246
+ testKind === TestKind . parallel
247
+ ? new ParallelXCTestOutputParser (
248
+ this . folderContext . workspaceContext . toolchain . hasMultiLineParallelTestOutput
249
+ )
250
+ : new XCTestOutputParser ( ) ;
238
251
this . swiftTestOutputParser = new SwiftTestingOutputParser (
239
252
this . testRun . testRunStarted ,
240
253
this . testRun . addParameterizedTestCase
@@ -274,9 +287,14 @@ export class TestRunner {
274
287
RunProfileName . run ,
275
288
vscode . TestRunProfileKind . Run ,
276
289
async ( request , token ) => {
277
- const runner = new TestRunner ( request , folderContext , controller ) ;
290
+ const runner = new TestRunner (
291
+ TestKind . standard ,
292
+ request ,
293
+ folderContext ,
294
+ controller
295
+ ) ;
278
296
onCreateTestRun . fire ( runner . testRun ) ;
279
- await runner . runHandler ( false , TestKind . standard , token ) ;
297
+ await runner . runHandler ( token ) ;
280
298
} ,
281
299
true ,
282
300
runnableTag
@@ -286,9 +304,14 @@ export class TestRunner {
286
304
RunProfileName . runParallel ,
287
305
vscode . TestRunProfileKind . Run ,
288
306
async ( request , token ) => {
289
- const runner = new TestRunner ( request , folderContext , controller ) ;
307
+ const runner = new TestRunner (
308
+ TestKind . parallel ,
309
+ request ,
310
+ folderContext ,
311
+ controller
312
+ ) ;
290
313
onCreateTestRun . fire ( runner . testRun ) ;
291
- await runner . runHandler ( false , TestKind . parallel , token ) ;
314
+ await runner . runHandler ( token ) ;
292
315
} ,
293
316
false ,
294
317
runnableTag
@@ -298,14 +321,19 @@ export class TestRunner {
298
321
RunProfileName . coverage ,
299
322
vscode . TestRunProfileKind . Coverage ,
300
323
async ( request , token ) => {
301
- const runner = new TestRunner ( request , folderContext , controller ) ;
324
+ const runner = new TestRunner (
325
+ TestKind . coverage ,
326
+ request ,
327
+ folderContext ,
328
+ controller
329
+ ) ;
302
330
onCreateTestRun . fire ( runner . testRun ) ;
303
331
if ( request . profile ) {
304
332
request . profile . loadDetailedCoverage = async ( testRun , fileCoverage ) => {
305
333
return runner . testRun . coverage . loadDetailedCoverage ( fileCoverage . uri ) ;
306
334
} ;
307
335
}
308
- await runner . runHandler ( false , TestKind . coverage , token ) ;
336
+ await runner . runHandler ( token ) ;
309
337
await runner . testRun . computeCoverage ( ) ;
310
338
} ,
311
339
false ,
@@ -316,9 +344,14 @@ export class TestRunner {
316
344
RunProfileName . debug ,
317
345
vscode . TestRunProfileKind . Debug ,
318
346
async ( request , token ) => {
319
- const runner = new TestRunner ( request , folderContext , controller ) ;
347
+ const runner = new TestRunner (
348
+ TestKind . debug ,
349
+ request ,
350
+ folderContext ,
351
+ controller
352
+ ) ;
320
353
onCreateTestRun . fire ( runner . testRun ) ;
321
- await runner . runHandler ( true , TestKind . debug , token ) ;
354
+ await runner . runHandler ( token ) ;
322
355
await vscode . commands . executeCommand ( "testing.openCoverage" ) ;
323
356
} ,
324
357
false ,
@@ -333,13 +366,13 @@ export class TestRunner {
333
366
* @param token Cancellation token
334
367
* @returns When complete
335
368
*/
336
- async runHandler ( shouldDebug : boolean , testKind : TestKind , token : vscode . CancellationToken ) {
369
+ async runHandler ( token : vscode . CancellationToken ) {
337
370
const runState = new TestRunnerTestRunState ( this . testRun ) ;
338
371
try {
339
- if ( shouldDebug ) {
372
+ if ( this . testKind === TestKind . debug ) {
340
373
await this . debugSession ( token , runState ) ;
341
374
} else {
342
- await this . runSession ( token , testKind , runState ) ;
375
+ await this . runSession ( token , runState ) ;
343
376
}
344
377
} catch ( error ) {
345
378
this . workspaceContext . outputChannel . log ( `Error: ${ getErrorDescription ( error ) } ` ) ;
@@ -350,11 +383,7 @@ export class TestRunner {
350
383
}
351
384
352
385
/** Run test session without attaching to a debugger */
353
- async runSession (
354
- token : vscode . CancellationToken ,
355
- testKind : TestKind ,
356
- runState : TestRunnerTestRunState
357
- ) {
386
+ async runSession ( token : vscode . CancellationToken , runState : TestRunnerTestRunState ) {
358
387
// Run swift-testing first, then XCTest.
359
388
// swift-testing being parallel by default should help these run faster.
360
389
if ( this . testArgs . hasSwiftTestingTests ) {
@@ -373,7 +402,7 @@ export class TestRunner {
373
402
const testBuildConfig = TestingDebugConfigurationFactory . swiftTestingConfig (
374
403
this . folderContext ,
375
404
fifoPipePath ,
376
- testKind ,
405
+ this . testKind ,
377
406
this . testArgs . swiftTestArgs ,
378
407
true
379
408
) ;
@@ -401,7 +430,8 @@ export class TestRunner {
401
430
await this . swiftTestOutputParser . watch ( fifoPipePath , runState ) ;
402
431
403
432
await this . launchTests (
404
- testKind === TestKind . parallel ? TestKind . standard : testKind ,
433
+ runState ,
434
+ this . testKind === TestKind . parallel ? TestKind . standard : this . testKind ,
405
435
token ,
406
436
outputStream ,
407
437
testBuildConfig ,
@@ -413,7 +443,7 @@ export class TestRunner {
413
443
if ( this . testArgs . hasXCTests ) {
414
444
const testBuildConfig = TestingDebugConfigurationFactory . xcTestConfig (
415
445
this . folderContext ,
416
- testKind ,
446
+ this . testKind ,
417
447
this . testArgs . xcTestArgs ,
418
448
true
419
449
) ;
@@ -425,13 +455,7 @@ export class TestRunner {
425
455
write : ( chunk , encoding , next ) => {
426
456
const text = chunk . toString ( ) ;
427
457
this . testRun . appendOutput ( text . replace ( / \n / g, "\r\n" ) ) ;
428
-
429
- // If a test fails in a parallel run the XCTest output is printed.
430
- // Since we get all results from the xunit xml we don't parse here
431
- // to prevent parsing twice.
432
- if ( testKind !== TestKind . parallel ) {
433
- this . xcTestOutputParser . parseResult ( text , runState ) ;
434
- }
458
+ this . xcTestOutputParser . parseResult ( text , runState ) ;
435
459
next ( ) ;
436
460
} ,
437
461
} ) ;
@@ -445,7 +469,8 @@ export class TestRunner {
445
469
this . testRun . testRunStarted ( ) ;
446
470
447
471
await this . launchTests (
448
- testKind ,
472
+ runState ,
473
+ this . testKind ,
449
474
token ,
450
475
parsedOutputStream ,
451
476
testBuildConfig ,
@@ -455,6 +480,7 @@ export class TestRunner {
455
480
}
456
481
457
482
private async launchTests (
483
+ runState : TestRunnerTestRunState ,
458
484
testKind : TestKind ,
459
485
token : vscode . CancellationToken ,
460
486
outputStream : stream . Writable ,
@@ -472,7 +498,7 @@ export class TestRunner {
472
498
) ;
473
499
break ;
474
500
case TestKind . parallel :
475
- await this . runParallelSession ( token , outputStream , testBuildConfig ) ;
501
+ await this . runParallelSession ( token , outputStream , testBuildConfig , runState ) ;
476
502
break ;
477
503
default :
478
504
await this . runStandardSession ( token , outputStream , testBuildConfig , testKind ) ;
@@ -581,7 +607,8 @@ export class TestRunner {
581
607
async runParallelSession (
582
608
token : vscode . CancellationToken ,
583
609
outputStream : stream . Writable ,
584
- testBuildConfig : vscode . DebugConfiguration
610
+ testBuildConfig : vscode . DebugConfiguration ,
611
+ runState : TestRunnerTestRunState
585
612
) {
586
613
await this . workspaceContext . tempFolder . withTemporaryFile ( "xml" , async filename => {
587
614
const args = [ ...( testBuildConfig . args ?? [ ] ) , "--xunit-output" , filename ] ;
@@ -602,12 +629,12 @@ export class TestRunner {
602
629
throw error ;
603
630
}
604
631
}
632
+
605
633
const buffer = await asyncfs . readFile ( filename , "utf8" ) ;
606
- const xUnitParser = new TestXUnitParser ( ) ;
607
- const results = await xUnitParser . parse (
608
- buffer ,
609
- new TestRunnerXUnitTestState ( this . testItemFinder , this . testRun )
634
+ const xUnitParser = new TestXUnitParser (
635
+ this . folderContext . workspaceContext . toolchain . hasMultiLineParallelTestOutput
610
636
) ;
637
+ const results = await xUnitParser . parse ( buffer , runState ) ;
611
638
if ( results ) {
612
639
this . testRun . appendOutput (
613
640
`\r\nExecuted ${ results . tests } tests, with ${ results . failures } failures and ${ results . errors } errors.\r\n`
@@ -863,7 +890,7 @@ class NonDarwinTestItemFinder implements TestItemFinder {
863
890
/**
864
891
* Store state of current test run output parse
865
892
*/
866
- class TestRunnerTestRunState implements ITestRunState {
893
+ export class TestRunnerTestRunState implements ITestRunState {
867
894
constructor ( private testRun : TestRunProxy ) { }
868
895
869
896
public currentTestItem ?: vscode . TestItem ;
@@ -953,30 +980,3 @@ class TestRunnerTestRunState implements ITestRunState {
953
980
// Nothing to do here
954
981
}
955
982
}
956
-
957
- class TestRunnerXUnitTestState implements iXUnitTestState {
958
- constructor (
959
- private testItemFinder : TestItemFinder ,
960
- private testRun : TestRunProxy
961
- ) { }
962
-
963
- passTest ( id : string , duration : number ) : void {
964
- const index = this . testItemFinder . getIndex ( id ) ;
965
- if ( index !== - 1 ) {
966
- this . testRun . passed ( this . testItemFinder . testItems [ index ] , duration ) ;
967
- }
968
- }
969
- failTest ( id : string , duration : number , message ?: string ) : void {
970
- const index = this . testItemFinder . getIndex ( id ) ;
971
- if ( index !== - 1 ) {
972
- const testMessage = new vscode . TestMessage ( message ?? "Failed" ) ;
973
- this . testRun . failed ( this . testItemFinder . testItems [ index ] , testMessage , duration ) ;
974
- }
975
- }
976
- skipTest ( id : string ) : void {
977
- const index = this . testItemFinder . getIndex ( id ) ;
978
- if ( index !== - 1 ) {
979
- this . testRun . skipped ( this . testItemFinder . testItems [ index ] ) ;
980
- }
981
- }
982
- }
0 commit comments