Skip to content

Commit 8b3632a

Browse files
authored
SourceLocation.init should enforce valid arguments (#817)
This modifies `SourceLocation.init()` to add `precondition`s which enforce that its arguments are valid, matching preconditions in the corresponding properties. ### Modifications: - Add `precondition`s to the initializer which match those in `didSet` of the corresponding properties. - Add precondition DocC symbol documentation where relevant. - Adjusted existing tests which were previously invalid (although not particularly problematic) but were not failing. ### Result: Newly-added exit tests now pass. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 35f2618 commit 8b3632a

File tree

4 files changed

+73
-31
lines changed

4 files changed

+73
-31
lines changed

Sources/Testing/Running/Configuration.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,10 @@ public struct Configuration: Sendable {
7575

7676
/// The maximum number of times the test run should iterate.
7777
///
78-
/// - Precondition: The value of this property must be greater than or equal
79-
/// to `1`.
78+
/// - Precondition: The value of this property must be greater than `0`.
8079
public var maximumIterationCount: Int {
8180
willSet {
82-
precondition(newValue >= 1, "Test runs must iterate at least once.")
81+
precondition(newValue > 0, "Test runs must iterate at least once (maximumIterationCount was \(newValue)).")
8382
}
8483
}
8584

Sources/Testing/SourceAttribution/SourceLocation.swift

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@
1212
public struct SourceLocation: Sendable {
1313
/// The file ID of the source file.
1414
///
15+
/// - Precondition: The value of this property must not be empty and must be
16+
/// formatted as described in the documentation for the
17+
/// [`#fileID`](https://developer.apple.com/documentation/swift/fileID()).
18+
/// macro in the Swift standard library.
19+
///
1520
/// ## See Also
1621
///
1722
/// - ``moduleName``
1823
/// - ``fileName``
1924
public var fileID: String {
20-
didSet {
21-
precondition(!fileID.isEmpty)
22-
precondition(fileID.contains("/"))
25+
willSet {
26+
precondition(!newValue.isEmpty, "SourceLocation.fileID must not be empty (was \(newValue))")
27+
precondition(newValue.contains("/"), "SourceLocation.fileID must be a well-formed file ID (was \(newValue))")
2328
}
2429
}
2530

@@ -74,20 +79,45 @@ public struct SourceLocation: Sendable {
7479
public var _filePath: String
7580

7681
/// The line in the source file.
82+
///
83+
/// - Precondition: The value of this property must be greater than `0`.
7784
public var line: Int {
78-
didSet {
79-
precondition(line > 0)
85+
willSet {
86+
precondition(newValue > 0, "SourceLocation.line must be greater than 0 (was \(newValue))")
8087
}
8188
}
8289

8390
/// The column in the source file.
91+
///
92+
/// - Precondition: The value of this property must be greater than `0`.
8493
public var column: Int {
85-
didSet {
86-
precondition(column > 0)
94+
willSet {
95+
precondition(newValue > 0, "SourceLocation.column must be greater than 0 (was \(newValue))")
8796
}
8897
}
8998

99+
/// Initialize an instance of this type with the specified location details.
100+
///
101+
/// - Parameters:
102+
/// - fileID: The file ID of the source file, using the format described in
103+
/// the documentation for the
104+
/// [`#fileID`](https://developer.apple.com/documentation/swift/fileID())
105+
/// macro in the Swift standard library.
106+
/// - filePath: The path to the source file.
107+
/// - line: The line in the source file. Must be greater than `0`.
108+
/// - column: The column in the source file. Must be greater than `0`.
109+
///
110+
/// - Precondition: `fileID` must not be empty and must be formatted as
111+
/// described in the documentation for
112+
/// [`#fileID`](https://developer.apple.com/documentation/swift/fileID()).
113+
/// - Precondition: `line` must be greater than `0`.
114+
/// - Precondition: `column` must be greater than `0`.
90115
public init(fileID: String, filePath: String, line: Int, column: Int) {
116+
precondition(!fileID.isEmpty, "SourceLocation.fileID must not be empty (was \(fileID))")
117+
precondition(fileID.contains("/"), "SourceLocation.fileID must be a well-formed file ID (was \(fileID))")
118+
precondition(line > 0, "SourceLocation.line must be greater than 0 (was \(line))")
119+
precondition(column > 0, "SourceLocation.column must be greater than 0 (was \(column))")
120+
91121
self.fileID = fileID
92122
self._filePath = filePath
93123
self.line = line

Tests/TestingTests/IssueTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,8 +1489,8 @@ struct IssueCodingTests {
14891489

14901490
@Test func sourceLocationPropertyGetter() throws {
14911491
let sourceLocation = SourceLocation(
1492-
fileID: "fileID",
1493-
filePath: "filePath",
1492+
fileID: "M/file.swift",
1493+
filePath: "M/file.swift",
14941494
line: 13,
14951495
column: 42
14961496
)
@@ -1509,8 +1509,8 @@ struct IssueCodingTests {
15091509

15101510
@Test func sourceLocationPropertySetter() throws {
15111511
let initialSourceLocation = SourceLocation(
1512-
fileID: "fileID",
1513-
filePath: "filePath",
1512+
fileID: "M/file.swift",
1513+
filePath: "file.swift",
15141514
line: 13,
15151515
column: 42
15161516
)
@@ -1523,8 +1523,8 @@ struct IssueCodingTests {
15231523
let issue = Issue(kind: .apiMisused, sourceContext: sourceContext)
15241524

15251525
let updatedSourceLocation = SourceLocation(
1526-
fileID: "fileID2",
1527-
filePath: "filePath2",
1526+
fileID: "M/file2.swift",
1527+
filePath: "file2.swift",
15281528
line: 14,
15291529
column: 43
15301530
)

Tests/TestingTests/SourceLocationTests.swift

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,6 @@ struct SourceLocationTests {
5151
#expect(sourceLocation.fileName == "D.swift")
5252
}
5353

54-
55-
#if !SWT_NO_EXIT_TESTS
56-
@Test("SourceLocation.fileID property must be well-formed")
57-
func sourceLocationFileIDWellFormed() async {
58-
await #expect(exitsWith: .failure) {
59-
var sourceLocation = #_sourceLocation
60-
sourceLocation.fileID = ""
61-
}
62-
await #expect(exitsWith: .failure) {
63-
var sourceLocation = #_sourceLocation
64-
sourceLocation.fileID = "ABC"
65-
}
66-
}
67-
#endif
68-
6954
@Test("SourceLocation.line and .column properties")
7055
func sourceLocationLineAndColumn() {
7156
var sourceLocation = #_sourceLocation
@@ -81,6 +66,34 @@ struct SourceLocationTests {
8166
}
8267

8368
#if !SWT_NO_EXIT_TESTS
69+
@Test("SourceLocation.init requires well-formed arguments")
70+
func sourceLocationInitPreconditions() async {
71+
await #expect(exitsWith: .failure, "Empty fileID") {
72+
_ = SourceLocation(fileID: "", filePath: "", line: 1, column: 1)
73+
}
74+
await #expect(exitsWith: .failure, "Invalid fileID") {
75+
_ = SourceLocation(fileID: "B.swift", filePath: "", line: 1, column: 1)
76+
}
77+
await #expect(exitsWith: .failure, "Zero line") {
78+
_ = SourceLocation(fileID: "A/B.swift", filePath: "", line: 0, column: 1)
79+
}
80+
await #expect(exitsWith: .failure, "Zero column") {
81+
_ = SourceLocation(fileID: "A/B.swift", filePath: "", line: 1, column: 0)
82+
}
83+
}
84+
85+
@Test("SourceLocation.fileID property must be well-formed")
86+
func sourceLocationFileIDWellFormed() async {
87+
await #expect(exitsWith: .failure) {
88+
var sourceLocation = #_sourceLocation
89+
sourceLocation.fileID = ""
90+
}
91+
await #expect(exitsWith: .failure) {
92+
var sourceLocation = #_sourceLocation
93+
sourceLocation.fileID = "ABC"
94+
}
95+
}
96+
8497
@Test("SourceLocation.line and column properties must be positive")
8598
func sourceLocationLineAndColumnPositive() async {
8699
await #expect(exitsWith: .failure) {

0 commit comments

Comments
 (0)