Skip to content

Commit 9c598e2

Browse files
authored
Delete TestSummary (#237)
## Changes Delete custom `TestSummary` logic. Instead, parse and use the output given by `xcodebuild`. This'll significantly simplify xcbeautify's codebase, give users more information, and more closely match `xcodebuild`'s raw output. ## Testing ### Test 1 > swift build && swift test | ./.build/debug/xcbeautify --disable-colored-output > filename.txt | | Old | New | |:---:|:---:|:---:| | Run 1 - Time | 19.24 seconds | 12.67 seconds | | Run 1 - Log | [old1.txt](https://github.com/user-attachments/files/16420420/old1.txt) | [new1.txt](https://github.com/user-attachments/files/16420408/new1.txt) | | Run 2 - Time | 12.48 seconds | 12.85 seconds | | Run 2 - Log | [old2.txt](https://github.com/user-attachments/files/16420425/old2.txt) | [new2.txt](https://github.com/user-attachments/files/16420409/new2.txt) | | Run 3 - Time | 12.86 | 12.93 seconds | | Run 3 - Log | [old3.txt](https://github.com/user-attachments/files/16420428/old3.txt) | [new3.txt](https://github.com/user-attachments/files/16420410/new3.txt) | ### Test 2 > make measure | | Old | New | |:---:|:---:|:---:| | Run 1 | 4.74 seconds | 4.91 seconds | | Run 2 | 4.76 seconds | 4.71 seconds | | Run 3 | 4.78 seconds | 4.73 seconds | ## Example Output ### Old ``` TerminalRendererTests ✔ testAggregateTarget (0.000 seconds) ... ✔ testXcodeprojError (0.000 seconds) ✔ testXcodeprojWarning (0.000 seconds) Tests Passed: 0 failed, 0 skipped, 306 total (12.477 seconds) ``` ### New ``` TerminalRendererTests ✔ testAggregateTarget (0.000 seconds) ... ✔ testXcodeprojError (0.000 seconds) ✔ testXcodeprojWarning (0.000 seconds) Executed 99 tests, with 0 failures (0 unexpected) in 0.014 (0.015) seconds Test Suite 'xcbeautifyPackageTests.xctest' passed at 2024-07-29 20:38:00.325. Executed 306 tests, with 0 failures (0 unexpected) in 12.355 (12.360) seconds Test Suite 'All tests' passed at 2024-07-29 20:38:00.325. Executed 306 tests, with 0 failures (0 unexpected) in 12.355 (12.361) seconds ```
1 parent d7c9ce7 commit 9c598e2

9 files changed

+107
-388
lines changed

Sources/XcbeautifyLib/CaptureGroups.swift

+28-20
Original file line numberDiff line numberDiff line change
@@ -436,25 +436,27 @@ struct CpresourceCaptureGroup: CopyCaptureGroup {
436436
}
437437

438438
struct ExecutedWithoutSkippedCaptureGroup: ExecutedCaptureGroup {
439-
static let outputType: OutputType = .task
439+
static let outputType: OutputType = .result
440440

441441
/// Regular expression captured groups:
442442
/// $1 = number of tests
443443
/// $2 = number of failures
444444
/// $3 = number of unexpected failures
445445
/// $4 = wall clock time in seconds (e.g. 0.295)
446-
static let regex = Regex(pattern: #"^\s*Executed\s(\d+)\stest[s]?,\swith\s(\d+)\sfailure[s]?\s\((\d+)\sunexpected\)\sin\s\d+\.\d{3}\s\((\d+\.\d{3})\)\sseconds"#)
446+
static let regex = Regex(pattern: #"^\s*(Executed\s(\d+)\stest[s]?,\swith\s(\d+)\sfailure[s]?\s\((\d+)\sunexpected\)\sin\s\d+\.\d{3}\s\((\d+\.\d{3})\)\sseconds.*)$"#)
447447

448+
let wholeResult: String
448449
let numberOfTests: Int
449450
let numberOfSkipped = 0
450451
let numberOfFailures: Int
451452
let numberOfUnexpectedFailures: Int
452453
let wallClockTimeInSeconds: Double
453454

454455
init?(groups: [String]) {
455-
assert(groups.count >= 4)
456-
guard let _numberOfTests = groups[safe: 0], let _numberOfFailures = groups[safe: 1], let _numberOfUnexpectedFailures = groups[safe: 2], let _wallClockTimeInSeconds = groups[safe: 3] else { return nil }
456+
assert(groups.count == 5)
457+
guard let wholeResult = groups[safe: 0], let _numberOfTests = groups[safe: 1], let _numberOfFailures = groups[safe: 2], let _numberOfUnexpectedFailures = groups[safe: 3], let _wallClockTimeInSeconds = groups[safe: 4] else { return nil }
457458
guard let numberOfTests = Int(_numberOfTests), let numberOfFailures = Int(_numberOfFailures), let numberOfUnexpectedFailures = Int(_numberOfUnexpectedFailures), let wallClockTimeInSeconds = Double(_wallClockTimeInSeconds) else { return nil }
459+
self.wholeResult = wholeResult
458460
self.numberOfTests = numberOfTests
459461
self.numberOfFailures = numberOfFailures
460462
self.numberOfUnexpectedFailures = numberOfUnexpectedFailures
@@ -463,26 +465,28 @@ struct ExecutedWithoutSkippedCaptureGroup: ExecutedCaptureGroup {
463465
}
464466

465467
struct ExecutedWithSkippedCaptureGroup: ExecutedCaptureGroup {
466-
static let outputType: OutputType = .task
468+
static let outputType: OutputType = .result
467469

468470
/// Regular expression captured groups:
469471
/// $1 = number of tests
470472
/// $2 = number of skipped
471473
/// $3 = number of failures
472474
/// $4 = number of unexpected failures
473475
/// $5 = wall clock time in seconds (e.g. 0.295)
474-
static let regex = Regex(pattern: #"^\s*Executed\s(\d+)\stest[s]?,\swith\s(\d+)\stest[s]?\sskipped\sand\s(\d+)\sfailure[s]?\s\((\d+)\sunexpected\)\sin\s\d+\.\d{3}\s\((\d+\.\d{3})\)\sseconds"#)
476+
static let regex = Regex(pattern: #"^\s*(Executed\s(\d+)\stest[s]?,\swith\s(\d+)\stest[s]?\sskipped\sand\s(\d+)\sfailure[s]?\s\((\d+)\sunexpected\)\sin\s\d+\.\d{3}\s\((\d+\.\d{3})\)\sseconds.*)$"#)
475477

478+
let wholeResult: String
476479
let numberOfTests: Int
477480
let numberOfSkipped: Int
478481
let numberOfFailures: Int
479482
let numberOfUnexpectedFailures: Int
480483
let wallClockTimeInSeconds: Double
481484

482485
init?(groups: [String]) {
483-
assert(groups.count >= 5)
484-
guard let _numberOfTests = groups[safe: 0], let _numberOfSkipped = groups[safe: 1], let _numberOfFailures = groups[safe: 2], let _numberOfUnexpectedFailures = groups[safe: 3], let _wallClockTimeInSeconds = groups[safe: 4] else { return nil }
486+
assert(groups.count == 6)
487+
guard let wholeResult = groups[safe: 0], let _numberOfTests = groups[safe: 1], let _numberOfSkipped = groups[safe: 2], let _numberOfFailures = groups[safe: 3], let _numberOfUnexpectedFailures = groups[safe: 4], let _wallClockTimeInSeconds = groups[safe: 5] else { return nil }
485488
guard let numberOfTests = Int(_numberOfTests), let numberOfSkipped = Int(_numberOfSkipped), let numberOfFailures = Int(_numberOfFailures), let numberOfUnexpectedFailures = Int(_numberOfUnexpectedFailures), let wallClockTimeInSeconds = Double(_wallClockTimeInSeconds) else { return nil }
489+
self.wholeResult = wholeResult
486490
self.numberOfTests = numberOfTests
487491
self.numberOfSkipped = numberOfSkipped
488492
self.numberOfFailures = numberOfFailures
@@ -1115,18 +1119,20 @@ struct TestsRunCompletionCaptureGroup: CaptureGroup {
11151119
/// $2 = result
11161120
/// $3 = time
11171121
#if os(Linux)
1118-
static let regex = Regex(pattern: #"^\s*Test Suite '(.*)' (finished|passed|failed) at (.*)"#)
1122+
static let regex = Regex(pattern: #"^\s*(Test Suite '(.*)' (finished|passed|failed) at (.*).*)"#)
11191123
#else
1120-
static let regex = Regex(pattern: #"^\s*Test Suite '(?:.*\/)?(.*[ox]ctest.*)' (finished|passed|failed) at (.*)"#)
1124+
static let regex = Regex(pattern: #"^\s*(Test Suite '(?:.*\/)?(.*[ox]ctest.*)' (finished|passed|failed) at (.*).*)"#)
11211125
#endif
11221126

1127+
let wholeResult: String
11231128
let suite: String
11241129
let result: String
11251130
let time: String
11261131

11271132
init?(groups: [String]) {
1128-
assert(groups.count >= 3)
1129-
guard let suite = groups[safe: 0], let result = groups[safe: 1], let time = groups[safe: 2] else { return nil }
1133+
assert(groups.count >= 4)
1134+
guard let wholeResult = groups[safe: 0], let suite = groups[safe: 1], let result = groups[safe: 2], let time = groups[safe: 3] else { return nil }
1135+
self.wholeResult = wholeResult
11301136
self.suite = suite
11311137
self.result = result
11321138
self.time = time
@@ -1174,25 +1180,27 @@ struct TestSuiteStartCaptureGroup: CaptureGroup {
11741180

11751181
struct TestSuiteAllTestsPassedCaptureGroup: CaptureGroup {
11761182
static let outputType: OutputType = .result
1177-
static let regex = Regex(pattern: #"^\s*Test Suite 'All tests' passed at"#)
1183+
static let regex = Regex(pattern: #"^\s*(Test Suite 'All tests' passed at.*)"#)
11781184

1179-
private init() { }
1185+
let wholeResult: String
11801186

11811187
init?(groups: [String]) {
1182-
assert(groups.count >= 0)
1183-
self.init()
1188+
assert(groups.count == 1)
1189+
guard let wholeResult = groups[safe: 0] else { return nil }
1190+
self.wholeResult = wholeResult
11841191
}
11851192
}
11861193

11871194
struct TestSuiteAllTestsFailedCaptureGroup: CaptureGroup {
11881195
static let outputType: OutputType = .result
1189-
static let regex = Regex(pattern: #"^\s*Test Suite 'All tests' failed at"#)
1196+
static let regex = Regex(pattern: #"^\s*(Test Suite 'All tests' failed at.*)"#)
11901197

1191-
private init() { }
1198+
let wholeResult: String
11921199

11931200
init?(groups: [String]) {
1194-
assert(groups.count >= 0)
1195-
self.init()
1201+
assert(groups.count == 1)
1202+
guard let wholeResult = groups[safe: 0] else { return nil }
1203+
self.wholeResult = wholeResult
11961204
}
11971205
}
11981206

Sources/XcbeautifyLib/Parser.swift

+4-49
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ package class Parser {
55

66
private let additionalLines: () -> String?
77

8-
private(set) var summary: TestSummary?
9-
10-
private(set) var needToRecordSummary = false
11-
128
private let preserveUnbeautifiedLines: Bool
139

1410
package private(set) var outputType = OutputType.undefined
@@ -100,6 +96,10 @@ package class Parser {
10096
PackageGraphResolvedItemCaptureGroup.self,
10197
DuplicateLocalizedStringKeyCaptureGroup.self,
10298
SwiftDriverJobDiscoveryEmittingModuleCaptureGroup.self,
99+
ExecutedWithoutSkippedCaptureGroup.self,
100+
ExecutedWithSkippedCaptureGroup.self,
101+
TestSuiteAllTestsPassedCaptureGroup.self,
102+
TestSuiteAllTestsFailedCaptureGroup.self,
103103
]
104104

105105
// MARK: - Init
@@ -135,28 +135,6 @@ package class Parser {
135135
guard let idx = captureGroupTypes.firstIndex(where: { $0.regex.match(string: line) }) else {
136136
// Some uncommon cases, which have additional logic and don't follow default flow
137137

138-
if ExecutedWithoutSkippedCaptureGroup.regex.match(string: line) {
139-
outputType = ExecutedWithoutSkippedCaptureGroup.outputType
140-
parseSummary(line: line, colored: colored, skipped: false)
141-
return nil
142-
}
143-
144-
if ExecutedWithSkippedCaptureGroup.regex.match(string: line) {
145-
outputType = ExecutedWithSkippedCaptureGroup.outputType
146-
parseSummary(line: line, colored: colored, skipped: true)
147-
return nil
148-
}
149-
150-
if TestSuiteAllTestsPassedCaptureGroup.regex.match(string: line) {
151-
needToRecordSummary = true
152-
return nil
153-
}
154-
155-
if TestSuiteAllTestsFailedCaptureGroup.regex.match(string: line) {
156-
needToRecordSummary = true
157-
return nil
158-
}
159-
160138
// Nothing found?
161139
outputType = OutputType.undefined
162140
return preserveUnbeautifiedLines ? line : nil
@@ -179,27 +157,4 @@ package class Parser {
179157

180158
return formattedOutput
181159
}
182-
183-
package func formattedSummary() -> String? {
184-
guard let summary else { return nil }
185-
return renderer.format(testSummary: summary)
186-
}
187-
188-
// MARK: Private
189-
190-
private func parseSummary(line: String, colored: Bool, skipped: Bool) {
191-
guard needToRecordSummary else { return }
192-
defer { needToRecordSummary = false }
193-
194-
guard let _group: CaptureGroup = line.captureGroup(with: skipped ? ExecutedWithSkippedCaptureGroup.pattern : ExecutedWithoutSkippedCaptureGroup.pattern) else { return }
195-
guard let group = _group as? ExecutedCaptureGroup else { return }
196-
197-
summary += TestSummary(
198-
testsCount: group.numberOfTests,
199-
skippedCount: group.numberOfSkipped,
200-
failuresCount: group.numberOfFailures,
201-
unexpectedCount: group.numberOfUnexpectedFailures,
202-
time: group.wallClockTimeInSeconds
203-
)
204-
}
205160
}

Sources/XcbeautifyLib/Renderers/GitHubActionsRenderer.swift

-10
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,6 @@ struct GitHubActionsRenderer: OutputRendering {
215215
message: warningMessage
216216
)
217217
}
218-
219-
func format(testSummary: TestSummary) -> String {
220-
if testSummary.isSuccess() {
221-
let message = "Tests Passed: \(testSummary.description)"
222-
return outputGitHubActionsLog(annotationType: .notice, message: message)
223-
} else {
224-
let message = "Tests Failed: \(testSummary.description)"
225-
return outputGitHubActionsLog(annotationType: .error, message: message)
226-
}
227-
}
228218
}
229219

230220
private struct FileComponents {

Sources/XcbeautifyLib/Renderers/OutputRendering.swift

+15-25
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ protocol OutputRendering {
66

77
func beautify(line: String, pattern: String) -> String?
88

9-
func format(testSummary: TestSummary) -> String
10-
119
func formatAnalyze(group: AnalyzeCaptureGroup) -> String
1210
func formatCheckDependencies() -> String
1311
func formatCleanRemove(group: CleanRemoveCaptureGroup) -> String
@@ -24,8 +22,8 @@ protocol OutputRendering {
2422
func formatCursor(group: CursorCaptureGroup) -> String?
2523
func formatDuplicateLocalizedStringKey(group: DuplicateLocalizedStringKeyCaptureGroup) -> String
2624
func formatError(group: ErrorCaptureGroup) -> String
27-
func formatExecutedWithoutSkipped(group: ExecutedWithoutSkippedCaptureGroup) -> String?
28-
func formatExecutedWithSkipped(group: ExecutedWithSkippedCaptureGroup) -> String?
25+
func formatExecutedWithoutSkipped(group: ExecutedWithoutSkippedCaptureGroup) -> String
26+
func formatExecutedWithSkipped(group: ExecutedWithSkippedCaptureGroup) -> String
2927
func formatFailingTest(group: FailingTestCaptureGroup) -> String
3028
func formatFileMissingError(group: FileMissingErrorCaptureGroup) -> String
3129
func formatGenerateCoverageData(group: GenerateCoverageDataCaptureGroup) -> String
@@ -66,9 +64,9 @@ protocol OutputRendering {
6664
func formatTestCaseSkipped(group: TestCaseSkippedCaptureGroup) -> String
6765
func formatTestCasePending(group: TestCasePendingCaptureGroup) -> String
6866
func formatTestCasesStarted(group: TestCaseStartedCaptureGroup) -> String?
69-
func formatTestsRunCompletion(group: TestsRunCompletionCaptureGroup) -> String?
70-
func formatTestSuiteAllTestsFailed(group: TestSuiteAllTestsFailedCaptureGroup) -> String?
71-
func formatTestSuiteAllTestsPassed(group: TestSuiteAllTestsPassedCaptureGroup) -> String?
67+
func formatTestsRunCompletion(group: TestsRunCompletionCaptureGroup) -> String
68+
func formatTestSuiteAllTestsFailed(group: TestSuiteAllTestsFailedCaptureGroup) -> String
69+
func formatTestSuiteAllTestsPassed(group: TestSuiteAllTestsPassedCaptureGroup) -> String
7270
func formatTestSuiteStart(group: TestSuiteStartCaptureGroup) -> String
7371
func formatTestSuiteStarted(group: TestSuiteStartedCaptureGroup) -> String
7472
func formatTIFFUtil(group: TIFFutilCaptureGroup) -> String?
@@ -337,12 +335,12 @@ extension OutputRendering {
337335
nil
338336
}
339337

340-
func formatExecutedWithoutSkipped(group: ExecutedWithoutSkippedCaptureGroup) -> String? {
341-
nil
338+
func formatExecutedWithoutSkipped(group: ExecutedWithoutSkippedCaptureGroup) -> String {
339+
group.wholeResult
342340
}
343341

344-
func formatExecutedWithSkipped(group: ExecutedWithSkippedCaptureGroup) -> String? {
345-
nil
342+
func formatExecutedWithSkipped(group: ExecutedWithSkippedCaptureGroup) -> String {
343+
group.wholeResult
346344
}
347345

348346
func formatGenerateCoverageData(group: GenerateCoverageDataCaptureGroup) -> String {
@@ -492,16 +490,16 @@ extension OutputRendering {
492490
nil
493491
}
494492

495-
func formatTestsRunCompletion(group: TestsRunCompletionCaptureGroup) -> String? {
496-
nil
493+
func formatTestsRunCompletion(group: TestsRunCompletionCaptureGroup) -> String {
494+
group.wholeResult
497495
}
498496

499-
func formatTestSuiteAllTestsFailed(group: TestSuiteAllTestsFailedCaptureGroup) -> String? {
500-
nil
497+
func formatTestSuiteAllTestsFailed(group: TestSuiteAllTestsFailedCaptureGroup) -> String {
498+
group.wholeResult
501499
}
502500

503-
func formatTestSuiteAllTestsPassed(group: TestSuiteAllTestsPassedCaptureGroup) -> String? {
504-
nil
501+
func formatTestSuiteAllTestsPassed(group: TestSuiteAllTestsPassedCaptureGroup) -> String {
502+
group.wholeResult
505503
}
506504

507505
func formatTestSuiteStart(group: TestSuiteStartCaptureGroup) -> String {
@@ -741,12 +739,4 @@ extension OutputRendering {
741739
func formatParallelTestingFailed(group: ParallelTestingFailedCaptureGroup) -> String {
742740
colored ? group.wholeError.s.Bold.f.Red : group.wholeError
743741
}
744-
745-
func format(testSummary: TestSummary) -> String {
746-
if testSummary.isSuccess() {
747-
colored ? "Tests Passed: \(testSummary.description)".s.Bold.f.Green : "Tests Passed: \(testSummary.description)"
748-
} else {
749-
colored ? "Tests Failed: \(testSummary.description)".s.Bold.f.Red : "Tests Failed: \(testSummary.description)"
750-
}
751-
}
752742
}

Sources/XcbeautifyLib/TestSummary.swift

-33
This file was deleted.

Sources/xcbeautify/Xcbeautify.swift

-4
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ struct Xcbeautify: ParsableCommand {
9898
output.write(parser.outputType, formatted)
9999
}
100100

101-
if let formattedSummary = parser.formattedSummary() {
102-
output.write(.result, formattedSummary)
103-
}
104-
105101
if !report.isEmpty {
106102
let outputPath = URL(
107103
fileURLWithPath: reportPath,

0 commit comments

Comments
 (0)