Skip to content

Commit f972479

Browse files
committed
Test: ensure swift-build does not emit fatal error on console
This partially ensures github issue 6605 will not re-occur. Add an automated tests that ensures swift-build will not emit `error: fatalError` message on the console output upon compilation failure as the swift-driver/swift-frontend emits that error. A similar test should be added, that invokes `swift build`
1 parent 0b569a1 commit f972479

File tree

8 files changed

+211
-1
lines changed

8 files changed

+211
-1
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version: 6.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "TypeLibrary",
8+
products: [
9+
// Products define the executables and libraries a package produces, making them visible to other packages.
10+
.library(
11+
name: "TypeLibrary",
12+
targets: ["TypeLibrary"]),
13+
],
14+
targets: [
15+
// Targets are the basic building blocks of a package, defining a module or a test suite.
16+
// Targets can depend on other targets in this package and products from dependencies.
17+
.target(
18+
name: "TypeLibrary"),
19+
.testTarget(
20+
name: "TypeLibraryTests",
21+
dependencies: ["TypeLibrary"]
22+
),
23+
]
24+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Testing
2+
@testable import TypeLibrary
3+
4+
@Test func example() async throws {
5+
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
6+
}
7+
8+
func testExample() throws {
9+
let x = 0
10+
let y = 1 / x
11+
print(y)
12+
}

Package.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,12 @@ if ProcessInfo.processInfo.environment["SWIFTCI_DISABLE_SDK_DEPENDENT_TESTS"] ==
873873
"Basics",
874874
]
875875
),
876-
876+
.testTarget(
877+
name: "_InternalTestSupportTests",
878+
dependencies: [
879+
"_InternalTestSupport"
880+
]
881+
),
877882
.testTarget(
878883
name: "CommandsTests",
879884
dependencies: [

Sources/_InternalTestSupport/misc.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import Foundation
1314
import Basics
1415
import struct Foundation.URL
1516
#if os(macOS)
@@ -465,3 +466,8 @@ extension PackageIdentity: @retroactive ExpressibleByStringInterpolation {}
465466
extension AbsolutePath: @retroactive ExpressibleByStringLiteral {}
466467
extension AbsolutePath: @retroactive ExpressibleByStringInterpolation {}
467468
#endif
469+
470+
public func getNumberOfMatches(of match: String, in value: String) -> Int {
471+
guard match.count != 0 else { return 0 }
472+
return value.ranges(of: match).count
473+
}

Tests/CommandsTests/BuildCommandTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import Foundation
1314
import Basics
1415
@testable import Commands
1516
@testable import CoreCommands
@@ -678,4 +679,37 @@ final class BuildCommandTests: CommandsTestCase {
678679
XCTAssertGreaterThan(codeCovFiles.count, 0)
679680
}
680681
}
682+
683+
// Test for GitHub Issue #6605
684+
func testFatalErrorDisplayedOnlyOnceWhenSingleXCTestHasFatalErrorInBuildCompilation() async throws {
685+
// GIVEN we have a Swift Package that has a fatalError building the tests
686+
let expected = 0
687+
try await fixture(name: "Miscellaneous/Errors/FatalErrorInSingleXCTest/TypeLibrary") { fixturePath in
688+
// WHEN swift-build --build-tests is executed"
689+
await XCTAssertAsyncThrowsError(try await self.execute(["--build-tests"], packagePath: fixturePath)) { error in
690+
// THEN I expect a failure
691+
guard case SwiftPMError.executionFailure(_, let stdout, let stderr) = error else {
692+
XCTFail()
693+
return
694+
}
695+
696+
let matchString = "error: fatalError"
697+
let stdoutMatches = getNumberOfMatches(of: matchString, in: stdout)
698+
let stderrMatches = getNumberOfMatches(of: matchString, in: stderr)
699+
let actualNumMatches = stdoutMatches + stderrMatches
700+
701+
// AND a fatal error message is printed \(expected) times
702+
XCTAssertEqual(
703+
actualNumMatches,
704+
expected, // swift-driver/swift-front-end emits a `error: fatalError` on the console output
705+
[
706+
"Actual (\(actualNumMatches)) is not as expected (\(expected))",
707+
"stdout: \(stdout.debugDescription)",
708+
"stderr: \(stderr.debugDescription)"
709+
].joined(separator: "\n")
710+
)
711+
}
712+
}
713+
}
714+
681715
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import _InternalTestSupport
2+
import XCTest
3+
4+
final class TestGetNumberOfMatches: XCTestCase {
5+
func testEmptyStringMatchesOnEmptyStringZeroTimes() {
6+
let matchOn = ""
7+
let value = ""
8+
let expectedNumMatches = 0
9+
10+
let actual = getNumberOfMatches(of: matchOn, in: value)
11+
12+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
13+
}
14+
15+
func testEmptyStringMatchesOnNonEmptySingleLineStringZeroTimes() {
16+
let matchOn = ""
17+
let value = "This is a non-empty string"
18+
let expectedNumMatches = 0
19+
20+
let actual = getNumberOfMatches(of: matchOn, in: value)
21+
22+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
23+
}
24+
25+
func testEmptyStringMatchesOnNonEmptyMultilineStringWithNeLineCharacterZeroTimes() {
26+
let matchOn = ""
27+
let value = "This is a non-empty string\nThis is the second line"
28+
let expectedNumMatches = 0
29+
30+
let actual = getNumberOfMatches(of: matchOn, in: value)
31+
32+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
33+
}
34+
35+
func testEmptyStringMatchesOnNonEmptyMultilineStringUsingTripleDoubleQuotesZeroTimes() {
36+
let matchOn = ""
37+
let value = """
38+
This is a non-empty string
39+
This is the second line
40+
This is the third line
41+
"""
42+
let expectedNumMatches = 0
43+
44+
let actual = getNumberOfMatches(of: matchOn, in: value)
45+
46+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
47+
}
48+
49+
func testNonEmptyStringMatchesOnEmptyStringReturnsZero() {
50+
let matchOn = """
51+
This is a non-empty string
52+
This is the second line
53+
This is the third line
54+
"""
55+
let value = ""
56+
let expectedNumMatches = 0
57+
58+
let actual = getNumberOfMatches(of: matchOn, in: value)
59+
60+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
61+
}
62+
63+
func testfatalErrorMatchesOnMultiLineWithTwoOccurencesReturnsTwo() {
64+
let matchOn = "error: fatalError"
65+
let value = """
66+
> swift test 25/10/24 10:44:14
67+
Building for debugging...
68+
/Users/arandomuser/Documents/personal/repro-swiftpm-6605/Tests/repro-swiftpm-6605Tests/repro_swiftpm_6605Tests.swift:7:19: error: division by zero
69+
let y = 1 / x
70+
^
71+
error: fatalError
72+
73+
error: fatalError
74+
"""
75+
let expectedNumMatches = 2
76+
77+
let actual = getNumberOfMatches(of: matchOn, in: value)
78+
79+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
80+
}
81+
82+
func testfatalErrorWithLeadingNewLineMatchesOnMultiLineWithTwoOccurencesReturnsTwo() {
83+
let matchOn = "\nerror: fatalError"
84+
let value = """
85+
> swift test 25/10/24 10:44:14
86+
Building for debugging...
87+
/Users/arandomuser/Documents/personal/repro-swiftpm-6605/Tests/repro-swiftpm-6605Tests/repro_swiftpm_6605Tests.swift:7:19: error: division by zero
88+
let y = 1 / x
89+
^
90+
error: fatalError
91+
92+
error: fatalError
93+
"""
94+
let expectedNumMatches = 2
95+
96+
let actual = getNumberOfMatches(of: matchOn, in: value)
97+
98+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
99+
}
100+
101+
func testfatalErrorWithLeadingAndTrailingNewLineMatchesOnMultiLineWithOneOccurencesReturnsOne() {
102+
let matchOn = "\nerror: fatalError\n"
103+
let value = """
104+
> swift test 25/10/24 10:44:14
105+
Building for debugging...
106+
/Users/arandomuser/Documents/personal/repro-swiftpm-6605/Tests/repro-swiftpm-6605Tests/repro_swiftpm_6605Tests.swift:7:19: error: division by zero
107+
let y = 1 / x
108+
^
109+
error: fatalError
110+
111+
error: fatalError
112+
"""
113+
let expectedNumMatches = 1
114+
115+
let actual = getNumberOfMatches(of: matchOn, in: value)
116+
117+
XCTAssertEqual(actual, expectedNumMatches, "Actual is not as expected")
118+
}
119+
}

0 commit comments

Comments
 (0)