Skip to content

Commit 6491f89

Browse files
ldomaradzkiclaude
andcommitted
Add Swift Testing framework summary parsing support
- Add regex pattern to parse "Test run with N tests in N suites passed" format - Fix passed_tests count showing 0 for Swift Testing output - Add testSwiftTestingSummaryPassed unit test - Add testRealWorldSwiftTestingOutput fixture-based test - Include swift-testing-output.txt test fixture 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b3229c1 commit 6491f89

File tree

4 files changed

+186
-2
lines changed

4 files changed

+186
-2
lines changed

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ let package = Package(
3333
dependencies: ["xcsift"],
3434
path: "Tests",
3535
resources: [
36-
.copy("Fixtures/build.txt")
36+
.copy("Fixtures/build.txt"),
37+
.copy("Fixtures/swift-testing-output.txt")
3738
]
3839
),
3940
// Temporarily commented out due to swift-syntax version conflict with SwiftLint

Sources/OutputParser.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,32 @@ class OutputParser {
674674
}
675675
return String(match.3)
676676
}
677-
677+
678+
// Pattern: Test run with N tests in N suites passed after X seconds.
679+
let swiftTestingPassedPattern = Regex {
680+
"Test run with "
681+
Capture(OneOrMore(.digit))
682+
" test"
683+
Optionally("s")
684+
" in "
685+
OneOrMore(.digit)
686+
" suite"
687+
Optionally("s")
688+
" passed after "
689+
Capture(OneOrMore(.any, .reluctant))
690+
" seconds"
691+
Optionally(".")
692+
Anchor.endOfSubject
693+
}
694+
695+
if let match = line.firstMatch(of: swiftTestingPassedPattern) {
696+
if let total = Int(match.1) {
697+
executedTestsCount = total
698+
summaryFailedTestsCount = 0 // All tests passed
699+
}
700+
return String(match.2)
701+
}
702+
678703
return nil
679704
}
680705
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
Test Suite 'All tests' started at 2025-10-21 13:54:18.134.
2+
Test Suite 'All tests' passed at 2025-10-21 13:54:18.140.
3+
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.006) seconds
4+
􀟈 Test run started.
5+
􀄵 Testing Library Version: 6.2 (3fdabe5392108d8)
6+
􀄵 Target Platform: arm64-apple-macosx
7+
􀟈 Suite "LocaleUrlTag Tests" started.
8+
􀟈 Suite "LocaleRedirectMiddleware Tests" started.
9+
􀟈 Suite "FrontmatterParser Tests" started.
10+
􀟈 Suite "HomeController Tests" started.
11+
􀟈 Test "LocaleUrlTag handles deep paths correctly in default locale" started.
12+
􀟈 Suite "getCanonicalPath" started.
13+
􀟈 Test "Handles trailing slash correctly for default locale" started.
14+
􀟈 Test "Handles trailing slash correctly for non-default locale" started.
15+
􀟈 Test "Removes quotes from values" started.
16+
􀟈 Test "LocaleUrlTag handles deep paths correctly in non-default locale" started.
17+
􀟈 Test "Skips empty lines and comments in frontmatter" started.
18+
􀟈 Test "LocaleUrlTag generates correct URLs in default locale (pl)" started.
19+
􀟈 Test "Throws error on missing closing delimiter" started.
20+
􀟈 Test "Parses valid frontmatter with metadata and markdown" started.
21+
􀟈 Test "LocaleUrlTag generates correct URLs in non-default locale (en)" started.
22+
􀟈 Test "Sets default locale (pl) when no locale parameter in URL" started.
23+
􀟈 Test "Redirects to path without locale for default locale (pl)" started.
24+
􀟈 Test "Non-default locale paths work correctly" started.
25+
􀟈 Test "Handles missing frontmatter - no opening delimiter" started.
26+
􀟈 Test "Sets session locale for valid non-default locale" started.
27+
􀟈 Test "Returns 404 for invalid locale" started.
28+
􀟈 Test "Correctly separates metadata from markdown body" started.
29+
􀟈 Test "Handles empty frontmatter" started.
30+
􀟈 Test "Trims whitespace from markdown body" started.
31+
􀟈 Test "Does not remove locale-like strings in non-prefix positions" started.
32+
􀟈 Test "Converts locale root paths to root" started.
33+
􀟈 Test "Preserves paths without locale prefix" started.
34+
􀟈 Test "Removes locale prefix from paths" started.
35+
􀟈 Test case passing 2 arguments input → "/pl/blog", expectedLocation → "/blog" to "Redirects to path without locale for default locale (pl)" started.
36+
􀟈 Test case passing 2 arguments input → "/pl/about", expectedLocation → "/about" to "Redirects to path without locale for default locale (pl)" started.
37+
􀟈 Test case passing 2 arguments input → "/pl/contact", expectedLocation → "/contact" to "Redirects to path without locale for default locale (pl)" started.
38+
􀟈 Test case passing 2 arguments input → "/pl", expectedLocation → "/" to "Redirects to path without locale for default locale (pl)" started.
39+
􀟈 Test case passing 1 argument path → "/es" to "Returns 404 for invalid locale" started.
40+
􀟈 Test case passing 1 argument path → "/fr/contact" to "Returns 404 for invalid locale" started.
41+
􁁛 Test "Skips empty lines and comments in frontmatter" passed after 0.001 seconds.
42+
􁁛 Test "Removes quotes from values" passed after 0.001 seconds.
43+
􀟈 Test case passing 2 arguments input → "/entries/about", expected → "/entries/about" to "Does not remove locale-like strings in non-prefix positions" started.
44+
􀟈 Test case passing 2 arguments input → "/blog/en/post", expected → "/blog/en/post" to "Does not remove locale-like strings in non-prefix positions" started.
45+
􀟈 Test case passing 1 argument input → "/en" to "Converts locale root paths to root" started.
46+
􁁛 Test "Parses valid frontmatter with metadata and markdown" passed after 0.001 seconds.
47+
􀟈 Test case passing 1 argument input → "/en/" to "Converts locale root paths to root" started.
48+
􀟈 Test case passing 1 argument input → "/pl/" to "Converts locale root paths to root" started.
49+
􀟈 Test case passing 1 argument path → "/de/about" to "Returns 404 for invalid locale" started.
50+
􀟈 Test case passing 1 argument input → "/pl" to "Converts locale root paths to root" started.
51+
􁁛 Test "Throws error on missing closing delimiter" passed after 0.002 seconds.
52+
􀟈 Test case passing 2 arguments input → "/blog/post", expected → "/blog/post" to "Preserves paths without locale prefix" started.
53+
􀟈 Test case passing 2 arguments input → "/en/about", expected → "/about" to "Removes locale prefix from paths" started.
54+
􀟈 Test case passing 2 arguments input → "/pl/contact", expected → "/contact" to "Removes locale prefix from paths" started.
55+
􀟈 Test case passing 2 arguments input → "/pl-news/article", expected → "/pl-news/article" to "Does not remove locale-like strings in non-prefix positions" started.
56+
􀟈 Test case passing 2 arguments input → "/about", expected → "/about" to "Preserves paths without locale prefix" started.
57+
􀟈 Test case passing 2 arguments input → "/contact", expected → "/contact" to "Preserves paths without locale prefix" started.
58+
􁁛 Test "Handles empty frontmatter" passed after 0.001 seconds.
59+
􀟈 Test case passing 2 arguments input → "/en/blog/posts/123", expected → "/blog/posts/123" to "Removes locale prefix from paths" started.
60+
􀟈 Test case passing 2 arguments input → "/pl/portfolio/art/gallery", expected → "/portfolio/art/gallery" to "Removes locale prefix from paths" started.
61+
􁁛 Test "Trims whitespace from markdown body" passed after 0.001 seconds.
62+
􀟈 Test case passing 2 arguments input → "/", expected → "/" to "Preserves paths without locale prefix" started.
63+
􁁛 Test "Handles missing frontmatter - no opening delimiter" passed after 0.002 seconds.
64+
􁁛 Test "Correctly separates metadata from markdown body" passed after 0.002 seconds.
65+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=F8C60DAF-4BF1-450E-9696-0A77896A03A9 [Vapor] GET /en
66+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=4C02B6DB-85F1-48E8-87CF-B9C5A2912251 [Vapor] GET /pl/blog
67+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=25920C2B-28A3-4B81-A28E-8B5063A7A9E3 [Vapor] GET /en/
68+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=7C1AE3DE-8BB6-4CD3-9981-4B1A832FB4F1 [Vapor] GET /pl/about
69+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=90AFF3A3-61E8-4B35-A1BC-934A118BE216 [Vapor] GET /pl
70+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=3F8C0331-F78B-45DF-A6FB-AE117A84E8C6 [Vapor] GET /about
71+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=6EA35484-17AD-4C59-B929-83C07702DCAB [Vapor] GET /es
72+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=DC1CD9DE-0583-47FD-A21D-F824616081C9 [Vapor] GET /en/about
73+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=7043F7E4-C9CD-486C-A76B-EFE00D8B7BDD [Vapor] GET /pl/
74+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=E119AD09-6B04-4A81-94CD-E029335FA9CB [Vapor] GET /about
75+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=2DE2EFCF-29AD-4E8C-BE07-C30160F9089C [Vapor] GET /pl/contact
76+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=238F8CA4-3F37-4E83-90D3-74AECC9B0C57 [Vapor] GET /en/about
77+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=C3203BC2-71F5-42BF-9AA7-B301CFA91BE1 [Vapor] GET /fr/contact
78+
􁁛 Suite "FrontmatterParser Tests" passed after 0.006 seconds.
79+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=0482AED7-101C-49C9-88D8-9EDF2CEF4505 [Vapor] GET /de/about
80+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=D6E59730-5554-4569-88EA-F523B6DCA14E [Vapor] GET /en
81+
2025-10-21T13:54:18+0200 info codes.vapor.application: request-id=B5A548F8-51CA-4CCA-9DF1-95313FA4CFC1 [Vapor] GET /
82+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
83+
􁁛 Test "Does not remove locale-like strings in non-prefix positions" with 3 test cases passed after 0.006 seconds.
84+
􁁛 Test "Removes locale prefix from paths" with 4 test cases passed after 0.006 seconds.
85+
􁁛 Test "Handles trailing slash correctly for default locale" passed after 0.006 seconds.
86+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
87+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
88+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
89+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
90+
􁁛 Test "Converts locale root paths to root" with 4 test cases passed after 0.006 seconds.
91+
􁁛 Test "Preserves paths without locale prefix" with 4 test cases passed after 0.006 seconds.
92+
2025-10-21T13:54:18+0200 warning codes.vapor.application: method=GET request-id=0482AED7-101C-49C9-88D8-9EDF2CEF4505 url=/de/about userAgent=[] [App] Abort.404: Not Found
93+
2025-10-21T13:54:18+0200 warning codes.vapor.application: method=GET request-id=6EA35484-17AD-4C59-B929-83C07702DCAB url=/es userAgent=[] [App] Abort.404: Not Found
94+
􁁛 Suite "getCanonicalPath" passed after 0.006 seconds.
95+
􁁛 Test "Redirects to path without locale for default locale (pl)" with 4 test cases passed after 0.006 seconds.
96+
􁁛 Suite "HomeController Tests" passed after 0.007 seconds.
97+
2025-10-21T13:54:18+0200 warning codes.vapor.application: method=GET request-id=C3203BC2-71F5-42BF-9AA7-B301CFA91BE1 url=/fr/contact userAgent=[] [App] Abort.404: Not Found
98+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
99+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
100+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
101+
􁁛 Test "Returns 404 for invalid locale" with 3 test cases passed after 0.007 seconds.
102+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
103+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
104+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
105+
􁁛 Test "Non-default locale paths work correctly" passed after 0.022 seconds.
106+
􁁛 Test "Sets default locale (pl) when no locale parameter in URL" passed after 0.022 seconds.
107+
􁁛 Test "LocaleUrlTag handles deep paths correctly in default locale" passed after 0.022 seconds.
108+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
109+
􁁛 Test "LocaleUrlTag generates correct URLs in non-default locale (en)" passed after 0.022 seconds.
110+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
111+
􁁛 Test "LocaleUrlTag handles deep paths correctly in non-default locale" passed after 0.023 seconds.
112+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
113+
􁁛 Test "Handles trailing slash correctly for non-default locale" passed after 0.023 seconds.
114+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
115+
􁁛 Test "Sets session locale for valid non-default locale" passed after 0.031 seconds.
116+
􁁛 Suite "LocaleRedirectMiddleware Tests" passed after 0.031 seconds.
117+
2025-10-21T13:54:18+0200 debug codes.vapor.application: [Vapor] Application shutting down
118+
􁁛 Test "LocaleUrlTag generates correct URLs in default locale (pl)" passed after 0.031 seconds.
119+
􁁛 Suite "LocaleUrlTag Tests" passed after 0.031 seconds.
120+
􁁛 Test run with 23 tests in 5 suites passed after 0.031 seconds.

Tests/OutputParserTests.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,42 @@ final class OutputParserTests: XCTestCase {
306306
XCTAssertTrue(jsonString.contains("\"warnings\":["))
307307
XCTAssertTrue(jsonString.contains("unused variable"))
308308
}
309+
310+
func testSwiftTestingSummaryPassed() {
311+
let parser = OutputParser()
312+
let input = """
313+
✓ Test "LocaleUrlTag handles deep paths correctly in default locale" passed after 0.022 seconds.
314+
✓ Test "LocaleUrlTag generates correct URLs in non-default locale (en)" passed after 0.022 seconds.
315+
✓ Test "LocaleUrlTag handles deep paths correctly in non-default locale" passed after 0.023 seconds.
316+
Test run with 23 tests in 5 suites passed after 0.031 seconds.
317+
"""
318+
319+
let result = parser.parse(input: input)
320+
321+
XCTAssertEqual(result.status, "success")
322+
XCTAssertEqual(result.summary.passedTests, 23)
323+
XCTAssertEqual(result.summary.failedTests, 0)
324+
XCTAssertEqual(result.summary.buildTime, "0.031")
325+
}
326+
327+
func testRealWorldSwiftTestingOutput() throws {
328+
let parser = OutputParser()
329+
330+
// Load the real-world Swift Testing output fixture
331+
let fixtureURL = URL(fileURLWithPath: #file)
332+
.deletingLastPathComponent()
333+
.appendingPathComponent("Fixtures")
334+
.appendingPathComponent("swift-testing-output.txt")
335+
336+
let input = try String(contentsOf: fixtureURL, encoding: .utf8)
337+
338+
// This is real Swift Testing output with 23 passed tests
339+
let result = parser.parse(input: input)
340+
341+
XCTAssertEqual(result.status, "success")
342+
XCTAssertEqual(result.summary.errors, 0)
343+
XCTAssertEqual(result.summary.failedTests, 0)
344+
XCTAssertEqual(result.summary.passedTests, 23)
345+
XCTAssertEqual(result.summary.buildTime, "0.031")
346+
}
309347
}

0 commit comments

Comments
 (0)