Skip to content

Commit

Permalink
Refactor JUnit Reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
cpisciotta committed Feb 24, 2025
1 parent b2f2b8b commit 6c01439
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 61 deletions.
80 changes: 31 additions & 49 deletions Sources/XcbeautifyLib/JunitReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,79 +19,61 @@ package final class JunitReporter {

package init() { }

package func add(line: String) {
// Remove any preceding or excessive spaces
let line = line.trimmingCharacters(in: .whitespacesAndNewlines)

if let groups = FailingTestCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generateFailingTest(groups: groups) else { return }
package func add(captureGroup: any CaptureGroup) {
switch captureGroup {
case let group as FailingTestCaptureGroup:
guard let testCase = generateFailingTest(group: group) else { return }
components.append(.failingTest(testCase))
} else if let groups = RestartingTestCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generateRestartingTest(groups: groups) else { return }
case let group as RestartingTestCaptureGroup:
guard let testCase = generateRestartingTest(group: group) else { return }
components.append(.failingTest(testCase))
} else if let groups = TestCasePassedCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generatePassingTest(groups: groups) else { return }
case let group as TestCasePassedCaptureGroup:
guard let testCase = generatePassingTest(group: group) else { return }
components.append(.testCasePassed(testCase))
} else if let groups = TestCaseSkippedCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generateSkippedTest(groups: groups) else { return }
case let group as TestCaseSkippedCaptureGroup:
guard let testCase = generateSkippedTest(group: group) else { return }
components.append(.skippedTest(testCase))
} else if let groups = TestSuiteStartedCaptureGroup.regex.captureGroups(for: line) {
guard let testStart = generateSuiteStart(groups: groups) else { return }
components.append(.testSuiteStart(testStart))
} else if let groups = ParallelTestCaseFailedCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generateParallelFailingTest(groups: groups) else { return }
case let group as ParallelTestCaseFailedCaptureGroup:
guard let testCase = generateParallelFailingTest(group: group) else { return }
parallelComponents.append(.failingTest(testCase))
} else if let groups = ParallelTestCasePassedCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generatePassingParallelTest(groups: groups) else { return }
case let group as ParallelTestCasePassedCaptureGroup:
guard let testCase = generatePassingParallelTest(group: group) else { return }
parallelComponents.append(.testCasePassed(testCase))
} else if let groups = ParallelTestCaseSkippedCaptureGroup.regex.captureGroups(for: line) {
guard let testCase = generateSkippedParallelTest(groups: groups) else { return }
case let group as ParallelTestCaseSkippedCaptureGroup:
guard let testCase = generateSkippedParallelTest(group: group) else { return }
parallelComponents.append(.testCasePassed(testCase))
} else {
// Not needed for generating a junit report
default:
return
}
}

private func generateFailingTest(groups: [String]) -> TestCase? {
guard let group = FailingTestCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.testSuite, name: group.testCase, time: nil, failure: .init(message: "\(group.file) - \(group.reason)"))
private func generateFailingTest(group: FailingTestCaptureGroup) -> TestCase? {
TestCase(classname: group.testSuite, name: group.testCase, time: nil, failure: .init(message: "\(group.file) - \(group.reason)"))
}

private func generateRestartingTest(groups: [String]) -> TestCase? {
guard let group = RestartingTestCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.testSuite, name: group.testCase, time: nil, failure: .init(message: group.wholeMessage))
private func generateRestartingTest(group: RestartingTestCaptureGroup) -> TestCase? {
TestCase(classname: group.testSuite, name: group.testCase, time: nil, failure: .init(message: group.wholeMessage))
}

private func generateParallelFailingTest(groups: [String]) -> TestCase? {
private func generateParallelFailingTest(group: ParallelTestCaseFailedCaptureGroup) -> TestCase? {
// Parallel tests do not provide meaningful failure messages
guard let group = ParallelTestCaseFailedCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.suite, name: group.testCase, time: nil, failure: .init(message: "Parallel test failed"))
}

private func generatePassingTest(groups: [String]) -> TestCase? {
guard let group = TestCasePassedCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.suite, name: group.testCase, time: group.time)
TestCase(classname: group.suite, name: group.testCase, time: nil, failure: .init(message: "Parallel test failed"))
}

private func generateSkippedTest(groups: [String]) -> TestCase? {
guard let group = TestCaseSkippedCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.suite, name: group.testCase, time: group.time, skipped: .init(message: nil))
private func generatePassingTest(group: TestCasePassedCaptureGroup) -> TestCase? {
TestCase(classname: group.suite, name: group.testCase, time: group.time)
}

private func generatePassingParallelTest(groups: [String]) -> TestCase? {
guard let group = ParallelTestCasePassedCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.suite, name: group.testCase, time: group.time)
private func generateSkippedTest(group: TestCaseSkippedCaptureGroup) -> TestCase? {
TestCase(classname: group.suite, name: group.testCase, time: group.time, skipped: .init(message: nil))
}

private func generateSkippedParallelTest(groups: [String]) -> TestCase? {
guard let group = ParallelTestCaseSkippedCaptureGroup(groups: groups) else { return nil }
return TestCase(classname: group.suite, name: group.testCase, time: group.time, skipped: .init(message: nil))
private func generatePassingParallelTest(group: ParallelTestCasePassedCaptureGroup) -> TestCase? {
TestCase(classname: group.suite, name: group.testCase, time: group.time)
}

private func generateSuiteStart(groups: [String]) -> String? {
guard let group = TestSuiteStartedCaptureGroup(groups: groups) else { return nil }
return group.suiteName
private func generateSkippedParallelTest(group: ParallelTestCaseSkippedCaptureGroup) -> TestCase? {
TestCase(classname: group.suite, name: group.testCase, time: group.time, skipped: .init(message: nil))
}

package func generateReport() throws -> Data {
Expand Down
15 changes: 5 additions & 10 deletions Sources/xcbeautify/Xcbeautify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,6 @@ struct Xcbeautify: ParsableCommand {
let output = OutputHandler(quiet: quiet, quieter: quieter, isCI: isCI) { print($0) }
let junitReporter = JunitReporter()

func readLine() -> String? {
let line = Swift.readLine()
if let line {
if report.contains(.junit) {
junitReporter.add(line: line)
}
}
return line
}

let parser = Parser()

let formatter = XcbeautifyLib.Formatter(
Expand All @@ -114,6 +104,11 @@ struct Xcbeautify: ParsableCommand {

continue
}

if report.contains(.junit) {
junitReporter.add(captureGroup: captureGroup)
}

guard let formatted = formatter.format(captureGroup: captureGroup) else { continue }
output.write(captureGroup.outputType, formatted)
}
Expand Down
10 changes: 8 additions & 2 deletions Tests/XcbeautifyLibTests/JunitReporterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,12 @@ class JunitReporterTests: XCTestCase {
func testJunitReport() throws {
let url = try XCTUnwrap(Bundle.module.url(forResource: "TestLog", withExtension: "txt"))
let reporter = JunitReporter()
let parser = Parser()

for component in try String(contentsOf: url).components(separatedBy: .newlines) {
reporter.add(line: component)
if let group = parser.parse(line: component.trimmingCharacters(in: .whitespacesAndNewlines)) {
reporter.add(captureGroup: group)
}
}
let data = try reporter.generateReport()
let xml = String(data: data, encoding: .utf8)!
Expand Down Expand Up @@ -277,8 +280,11 @@ class JunitReporterTests: XCTestCase {
func testParallelJunitReport() throws {
let url = try XCTUnwrap(Bundle.module.url(forResource: "ParallelTestLog", withExtension: "txt"))
let reporter = JunitReporter()
let parser = Parser()
for component in try String(contentsOf: url).components(separatedBy: .newlines) {
reporter.add(line: component)
if let captureGroup = parser.parse(line: component.trimmingCharacters(in: .whitespacesAndNewlines)) {
reporter.add(captureGroup: captureGroup)
}
}
let data = try reporter.generateReport()
let xml = String(data: data, encoding: .utf8)!
Expand Down

0 comments on commit 6c01439

Please sign in to comment.