diff --git a/Sources/XcbeautifyLib/CaptureGroups.swift b/Sources/XcbeautifyLib/CaptureGroups.swift index 851f93f6..5b43f0db 100644 --- a/Sources/XcbeautifyLib/CaptureGroups.swift +++ b/Sources/XcbeautifyLib/CaptureGroups.swift @@ -1751,7 +1751,7 @@ struct FatalErrorCaptureGroup: ErrorCaptureGroup { /// Regular expression captured groups: /// $1 = whole error. /// it varies a lot, not sure if it makes sense to catch everything separately - static let regex = XCRegex(pattern: #"^(fatal error:.*)$"#) + static let regex = XCRegex(pattern: #"^((?:.* )?[fF]atal error:.*)$"#) let wholeError: String diff --git a/Sources/XcbeautifyLib/JunitReporter.swift b/Sources/XcbeautifyLib/JunitReporter.swift index c5eae0bd..ebb301e3 100644 --- a/Sources/XcbeautifyLib/JunitReporter.swift +++ b/Sources/XcbeautifyLib/JunitReporter.swift @@ -55,6 +55,17 @@ package final class JunitReporter { case let group as ParallelTestCaseSkippedCaptureGroup: let testCase = TestCase(classname: group.suite, name: group.testCase, time: group.time, skipped: .init(message: nil)) parallelComponents.append(.testCasePassed(testCase)) + case let group as TestCaseStartedCaptureGroup: + components.append(.testCaseStart(suite: group.suite, testName: group.testCase)) + case let group as FatalErrorCaptureGroup: + switch components.last { + case let .testCaseStart(suite, testName): + let testCase = TestCase(classname: suite, name: testName, time: nil, failure: .init(message: group.wholeError)) + components.append(.failingTest(testCase)) + default: + break + } + default: // Not needed for generating a junit report return @@ -95,6 +106,9 @@ private final class JunitComponentParser { let .testCasePassed(testCase), let .skippedTest(testCase): testCases.append(testCase) + + case .testCaseStart: + break } } @@ -120,6 +134,7 @@ private final class JunitComponentParser { private enum JunitComponent { case testSuiteStart(String) + case testCaseStart(suite: String, testName: String) case failingTest(TestCase) case testCasePassed(TestCase) case skippedTest(TestCase) diff --git a/Tests/XcbeautifyLibTests/JunitReporterTests.swift b/Tests/XcbeautifyLibTests/JunitReporterTests.swift index 23c9305d..9ab8fabd 100644 --- a/Tests/XcbeautifyLibTests/JunitReporterTests.swift +++ b/Tests/XcbeautifyLibTests/JunitReporterTests.swift @@ -286,6 +286,22 @@ class JunitReporterTests: XCTestCase { """ + private let expectedXCTestCrashXml = """ + + + + + + + + + + + + + + """ + func testParallelJunitReport() throws { let url = try XCTUnwrap(Bundle.module.url(forResource: "ParallelTestLog", withExtension: "txt")) let parser = Parser() @@ -301,4 +317,20 @@ class JunitReporterTests: XCTestCase { let expectedXml = expectedParallelXml XCTAssertEqual(xml, expectedXml) } + + func testXCTestCrashJunitReport() throws { + let url = try XCTUnwrap(Bundle.module.url(forResource: "xctest_crash_log", withExtension: "txt")) + let parser = Parser() + let reporter = JunitReporter() + + for line in try String(contentsOf: url).components(separatedBy: .newlines) { + if let captureGroup = parser.parse(line: line) { + reporter.add(captureGroup: captureGroup) + } + } + let data = try reporter.generateReport() + let xml = String(data: data, encoding: .utf8)! + let expectedXml = expectedXCTestCrashXml + XCTAssertEqual(xml, expectedXml) + } } diff --git a/Tests/XcbeautifyLibTests/TestData/xctest_crash_log.txt b/Tests/XcbeautifyLibTests/TestData/xctest_crash_log.txt new file mode 100644 index 00000000..055810f5 --- /dev/null +++ b/Tests/XcbeautifyLibTests/TestData/xctest_crash_log.txt @@ -0,0 +1,23 @@ +exec ${PAGER:-/usr/bin/less} "$0" || exit 1 +Executing tests from //Libs/Date:DateTests +----------------------------------------------------------------------------- +Existing simulator 'BAZEL_TEST_iPhone 11_18.4' (A75DA946-4A16-48A5-95F2-5E3AC12DF582) state is: booted +Test Suite 'All tests' started at 2025-05-19 18:43:25.150. +Test Suite 'DateTests.xctest' started at 2025-05-19 18:43:25.151. +Test Suite 'CalendarDay__Tests' started at 2025-05-19 18:43:25.151. +Test Case '-[DateTests.CalendarDay__Tests testCalendarDayRawValue]' started. +Test Case '-[DateTests.CalendarDay__Tests testCalendarDayRawValue]' passed (0.006 seconds). +Test Case '-[DateTests.CalendarDay__Tests testCreatingCalendarDay]' started. +Test Case '-[DateTests.CalendarDay__Tests testCreatingCalendarDay]' passed (0.000 seconds). +Test Case '-[DateTests.CalendarDay__Tests testDateConversion]' started. +Test Case '-[DateTests.CalendarDay__Tests testDateConversion]' passed (0.000 seconds). +Test Case '-[DateTests.CalendarDay__Tests testDateWithTimeConversion]' started. +Test Case '-[DateTests.CalendarDay__Tests testDateWithTimeConversion]' passed (0.000 seconds). +Test Case '-[DateTests.CalendarDay__Tests testDaysSince]' started. +Test Case '-[DateTests.CalendarDay__Tests testDaysSince]' passed (0.000 seconds). +Test Case '-[DateTests.CalendarDay__Tests testDaysSinceWithDaylightSavings]' started. +Test Case '-[DateTests.CalendarDay__Tests testDaysSinceWithDaylightSavings]' passed (0.000 seconds). +Test Case '-[DateTests.CalendarDay__Tests testToday]' started. +DateTests/CalendarDayTests.swift:63: Fatal error: This test is not implemented yet. +Child process terminated with signal 5: Trace/BPT trap +error: tests exited with '133'