Skip to content

Commit 27dcd82

Browse files
authored
Parse XCTest output anywhere in output lines (#1511)
Sometimes when running tests that print user output during their execution this output can be printed on the same line as XCTest results output, either before or after the results string. Previously this showed as a test that never finished (pending) in then test explorer, but with the introduction of #1505 tests that start but don't find any completion output are assumed to be crashed and marked as failed. This extra user output interleaved with XCTest output would cause false positives, leading users to believe that their test never completed (crashed) when really we just missed the success/failure message from XCTest due to overly strict parsing. Relax the XCTest output parsing regexes so that matched strings don't need to be at the start of a line.
1 parent a42be57 commit 27dcd82

File tree

2 files changed

+45
-14
lines changed

2 files changed

+45
-14
lines changed

src/TestExplorer/TestParsers/XCTestOutputParser.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -38,37 +38,37 @@ enum TestCompletionState {
3838
/** Regex for parsing darwin XCTest output */
3939
export const darwinTestRegex = {
4040
// Regex "Test Case '-[<test target> <class.function>]' started"
41-
started: /^Test Case '-\[(\S+)\s(.*)\]' started./,
41+
started: /Test Case '-\[(\S+)\s(.*)\]' started\./,
4242
// Regex "Test Case '-[<test target> <class.function>]' <completion_state> (<duration> seconds)"
43-
finished: /^Test Case '-\[(\S+)\s(.*)\]' (.*) \((\d.*) seconds\)/,
43+
finished: /Test Case '-\[(\S+)\s(.*)\]' (.*) \((\d.*) seconds\)/,
4444
// Regex "<path/to/test>:<line number>: error: -[<test target> <class.function>] : <error>"
45-
error: /^(.+):(\d+):\serror:\s-\[(\S+)\s(.*)\] : (.*)$/,
45+
error: /(.+):(\d+):\serror:\s-\[(\S+)\s(.*)\] : (.*)$/,
4646
// Regex "<path/to/test>:<line number>: -[<test target> <class.function>] : Test skipped"
47-
skipped: /^(.+):(\d+):\s-\[(\S+)\s(.*)\] : Test skipped/,
47+
skipped: /(.+):(\d+):\s-\[(\S+)\s(.*)\] : Test skipped/,
4848
// Regex "Test Suite '<class>' started"
49-
startedSuite: /^Test Suite '(.*)' started/,
49+
startedSuite: /Test Suite '(.*)' started/,
5050
// Regex "Test Suite '<class>' passed"
51-
passedSuite: /^Test Suite '(.*)' passed/,
51+
passedSuite: /Test Suite '(.*)' passed/,
5252
// Regex "Test Suite '<class>' failed"
53-
failedSuite: /^Test Suite '(.*)' failed/,
53+
failedSuite: /Test Suite '(.*)' failed/,
5454
};
5555

5656
/** Regex for parsing non darwin XCTest output */
5757
export const nonDarwinTestRegex = {
5858
// Regex "Test Case '-[<test target> <class.function>]' started"
59-
started: /^Test Case '(.*)\.(.*)' started/,
59+
started: /Test Case '(.*)\.(.*)' started/,
6060
// Regex "Test Case '<class>.<function>' <completion_state> (<duration> seconds)"
61-
finished: /^Test Case '(.*)\.(.*)' (.*) \((\d.*) seconds\)/,
61+
finished: /Test Case '(.*)\.(.*)' (.*) \((\d.*) seconds\)/,
6262
// Regex "<path/to/test>:<line number>: error: <class>.<function> : <error>"
63-
error: /^(.+):(\d+):\serror:\s*(.*)\.(.*) : (.*)/,
63+
error: /(.+):(\d+):\serror:\s*(.*)\.(.*) : (.*)/,
6464
// Regex "<path/to/test>:<line number>: <class>.<function> : Test skipped"
65-
skipped: /^(.+):(\d+):\s*(.*)\.(.*) : Test skipped/,
65+
skipped: /(.+):(\d+):\s*(.*)\.(.*) : Test skipped/,
6666
// Regex "Test Suite '<class>' started"
67-
startedSuite: /^Test Suite '(.*)' started/,
67+
startedSuite: /Test Suite '(.*)' started/,
6868
// Regex "Test Suite '<class>' passed"
69-
passedSuite: /^Test Suite '(.*)' passed/,
69+
passedSuite: /Test Suite '(.*)' passed/,
7070
// Regex "Test Suite '<class>' failed"
71-
failedSuite: /^Test Suite '(.*)' failed/,
71+
failedSuite: /Test Suite '(.*)' failed/,
7272
};
7373

7474
export interface IXCTestOutputParser {

test/integration-tests/testexplorer/XCTestOutputParser.test.ts

+31
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,37 @@ Test Suite 'Selected tests' failed at 2024-10-20 22:01:46.306.
484484
assert.deepEqual(inputToTestOutput(input), testRunState.allOutput);
485485
});
486486

487+
test("Interleaved user and XCTest output", () => {
488+
const input = `Test Suite 'Selected tests' started at 2024-10-20 22:01:46.206.
489+
Test Suite 'EmptyAppPackageTests.xctest' started at 2024-10-20 22:01:46.207.
490+
Test Suite 'TestSuite1' started at 2024-10-20 22:01:46.207.
491+
Test Case '-[MyTests.TestSuite1 testFirst]' started.
492+
[debug]: evaluating manifest for 'pkg' v. unknown
493+
[debug]: loading manifeTest Case '-[MyTests.TestSuite1 testFirst]' passed (0.001 seconds).
494+
Test Suite 'TestSuite1' passed at 2024-10-20 22:01:46.208.
495+
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.000) seconds`;
496+
497+
outputParser.parseResult(input, testRunState);
498+
499+
const testOutput = inputToTestOutput(input);
500+
assertTestRunState(testRunState, [
501+
{
502+
name: "MyTests.TestSuite1",
503+
output: [testOutput[2], testOutput[6]],
504+
status: TestStatus.passed,
505+
},
506+
{
507+
name: "MyTests.TestSuite1/testFirst",
508+
output: [testOutput[3], testOutput[5]],
509+
status: TestStatus.passed,
510+
timing: {
511+
duration: 0.001,
512+
},
513+
},
514+
]);
515+
assert.deepEqual(inputToTestOutput(input), testRunState.allOutput);
516+
});
517+
487518
suite("Diffs", () => {
488519
const testRun = (message: string, actual?: string, expected?: string) => {
489520
const input = `Test Case '-[MyTests.MyTests testFail]' started.

0 commit comments

Comments
 (0)