Skip to content

Commit 91d26cb

Browse files
committed
Add notes to assertion
1 parent 4357755 commit 91d26cb

12 files changed

+283
-100
lines changed

Tests/SwiftParserTest/Assertions.swift

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ struct DiagnosticSpec {
239239
/// If not `nil`, assert that the highlighted range has this content.
240240
let highlight: String?
241241
/// If not `nil`, assert that the diagnostic contains notes with these messages.
242-
let notes: [NoteSpec]?
242+
let notes: [NoteSpec]
243243
/// If not `nil`, assert that the diagnostic contains fix-its with these messages.
244244
/// Use the `fixedSource` parameter on `AssertParse` to check that applying the Fix-It yields the expected result.
245245
let fixIts: [String]
@@ -254,7 +254,7 @@ struct DiagnosticSpec {
254254
message: String?,
255255
severity: DiagnosticSeverity = .error,
256256
highlight: String? = nil,
257-
notes: [NoteSpec]? = nil,
257+
notes: [NoteSpec] = [],
258258
fixIts: [String] = [],
259259
file: StaticString = #file,
260260
line: UInt = #line
@@ -418,20 +418,18 @@ func assertDiagnostic<T: SyntaxProtocol>(
418418
line: line
419419
)
420420
}
421-
if let notes = spec.notes {
422-
if diag.notes.count != notes.count {
423-
XCTFail(
424-
"""
425-
Expected \(notes.count) notes but received \(diag.notes.count):
426-
\(diag.notes.map(\.debugDescription).joined(separator: "\n"))
427-
""",
428-
file: file,
429-
line: line
430-
)
431-
} else {
432-
for (note, expectedNote) in zip(diag.notes, notes) {
433-
assertNote(note, in: tree, markerLocations: markerLocations, expected: expectedNote, file: expectedNote.file, line: expectedNote.line)
434-
}
421+
if diag.notes.count != spec.notes.count {
422+
XCTFail(
423+
"""
424+
Expected \(spec.notes.count) notes but received \(diag.notes.count):
425+
\(diag.notes.map(\.debugDescription).joined(separator: "\n"))
426+
""",
427+
file: file,
428+
line: line
429+
)
430+
} else {
431+
for (note, expectedNote) in zip(diag.notes, spec.notes) {
432+
assertNote(note, in: tree, markerLocations: markerLocations, expected: expectedNote, file: expectedNote.file, line: expectedNote.line)
435433
}
436434
}
437435

Tests/SwiftParserTest/AttributeTests.swift

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@ final class AttributeTests: XCTestCase {
1818
func testMissingArgumentToAttribute() {
1919
assertParse(
2020
"""
21-
@_dynamicReplacement(1️⃣
21+
@_dynamicReplacementℹ️(1️⃣
2222
func 2️⃣test_dynamic_replacement_for2() {
2323
}
2424
""",
2525
diagnostics: [
26-
DiagnosticSpec(message: "expected argument for '@_dynamicReplacement' attribute", fixIts: ["insert attribute argument"]),
27-
DiagnosticSpec(message: "expected ')' to end attribute", fixIts: ["insert ')'"]),
26+
DiagnosticSpec(
27+
message: "expected argument for '@_dynamicReplacement' attribute",
28+
fixIts: ["insert attribute argument"]
29+
),
30+
DiagnosticSpec(
31+
message: "expected ')' to end attribute",
32+
notes: [NoteSpec(message: "to match this opening '('")],
33+
fixIts: ["insert ')'"]
34+
),
2835
],
2936
fixedSource: """
3037
@_dynamicReplacement(for : <#identifier#>)
@@ -37,14 +44,23 @@ final class AttributeTests: XCTestCase {
3744
func testMissingGenericTypeToAttribute() {
3845
assertParse(
3946
"""
40-
@differentiable(reverse wrt1️⃣,where T2️⃣
47+
@differentiableℹ️(reverse wrt1️⃣,where T2️⃣
4148
func podcastPlaybackSpeed() {
4249
}
4350
""",
4451
diagnostics: [
45-
DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' and parameters in '@differentiable' argument", fixIts: ["insert ':' and parameters"]),
52+
DiagnosticSpec(
53+
locationMarker: "1️⃣",
54+
message: "expected ':' and parameters in '@differentiable' argument",
55+
fixIts: ["insert ':' and parameters"]
56+
),
4657
DiagnosticSpec(locationMarker: "2️⃣", message: "expected ':' or '==' to indicate a conformance or same-type requirement"),
47-
DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end attribute", fixIts: ["insert ')'"]),
58+
DiagnosticSpec(
59+
locationMarker: "2️⃣",
60+
message: "expected ')' to end attribute",
61+
notes: [NoteSpec(message: "to match this opening '('")],
62+
fixIts: ["insert ')'"]
63+
),
4864
],
4965
fixedSource: """
5066
@differentiable(reverse wrt: <#identifier#>,where T)
@@ -57,12 +73,23 @@ final class AttributeTests: XCTestCase {
5773
func testMissingClosingParenToAttribute() {
5874
assertParse(
5975
"""
60-
@_specialize(e1️⃣
76+
@_specializeℹ️(e1️⃣
6177
""",
6278
diagnostics: [
63-
DiagnosticSpec(message: "expected ':' in attribute argument", fixIts: ["insert ':'"]),
64-
DiagnosticSpec(message: "expected ')' to end attribute", fixIts: ["insert ')'"]),
65-
DiagnosticSpec(message: "expected declaration after attribute", fixIts: ["insert declaration"]),
79+
DiagnosticSpec(
80+
message: "expected ':' in attribute argument",
81+
fixIts: ["insert ':'"]
82+
),
83+
DiagnosticSpec(
84+
message: "expected ')' to end attribute",
85+
notes: [NoteSpec(message: "to match this opening '('")],
86+
fixIts: ["insert ')'"]
87+
),
88+
DiagnosticSpec(
89+
message: "expected declaration after attribute",
90+
fixIts: ["insert declaration"]
91+
),
92+
6693
]
6794
)
6895
}

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,14 @@ final class DeclarationTests: XCTestCase {
128128
]
129129
)
130130
assertParse(
131-
"class B<where g1️⃣",
131+
"class Bℹ️<where g1️⃣",
132132
diagnostics: [
133133
DiagnosticSpec(message: "expected ':' or '==' to indicate a conformance or same-type requirement"),
134-
DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]),
135-
DiagnosticSpec(message: "expected member block in class", fixIts: ["insert member block"]),
134+
DiagnosticSpec(message: "expected '>' to end generic parameter clause",
135+
notes: [NoteSpec(message: "to match this opening '<'")],
136+
fixIts: ["insert '>'"]),
137+
DiagnosticSpec(message: "expected member block in class",
138+
fixIts: ["insert member block"]),
136139
]
137140
)
138141
}
@@ -185,11 +188,14 @@ final class DeclarationTests: XCTestCase {
185188
)
186189

187190
assertParse(
188-
"protocol P{1️⃣{}case2️⃣",
191+
"protocol Pℹ️{1️⃣{}case2️⃣",
189192
diagnostics: [
190193
DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '{}' before enum case"),
191-
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case", fixIts: ["insert identifier"]),
192-
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end protocol", fixIts: ["insert '}'"]),
194+
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case",
195+
fixIts: ["insert identifier"]),
196+
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end protocol",
197+
notes: [NoteSpec(message: "to match this opening '{'")],
198+
fixIts: ["insert '}'"]),
193199
]
194200
)
195201
}
@@ -626,9 +632,11 @@ final class DeclarationTests: XCTestCase {
626632

627633
func testMissingClosingParenInFunctionSignature() {
628634
assertParse(
629-
"func test(first second: Int1️⃣",
635+
"func testℹ️(first second: Int1️⃣",
630636
diagnostics: [
631-
DiagnosticSpec(message: "expected ')' to end parameter clause", fixIts: ["insert ')'"])
637+
DiagnosticSpec(message: "expected ')' to end parameter clause",
638+
notes: [NoteSpec(message: " to match this opening '('")],
639+
fixIts: ["insert ')'"])
632640
]
633641
)
634642
}
@@ -745,14 +753,18 @@ final class DeclarationTests: XCTestCase {
745753
func testExpressionMember() {
746754
assertParse(
747755
"""
748-
struct S {1️⃣
749-
/2️⃣ ###line 25 "line-directive.swift"3️⃣
756+
struct S ℹ️{1️⃣
757+
🔟/2️⃣ ###line 25 "line-directive.swift"3️⃣
750758
4️⃣}
751759
""",
752760
diagnostics: [
753-
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]),
761+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end struct",
762+
notes: [NoteSpec(message: "to match this opening '{'")],
763+
fixIts: ["insert '}'"]),
754764
DiagnosticSpec(locationMarker: "2️⃣", message: "bare slash regex literal may not start with space"),
755-
DiagnosticSpec(locationMarker: "3️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/\'"]),
765+
DiagnosticSpec(locationMarker: "3️⃣", message: "expected '/' to end regex literal",
766+
notes: [NoteSpec(locationMarker: "🔟", message: "to match this opening '/'")],
767+
fixIts: ["insert '/\'"]),
756768
DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous brace at top level"),
757769
]
758770
)

Tests/SwiftParserTest/translated/ActorTests.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ final class ActorTests: XCTestCase {
2121
actor MyActor11️⃣
2222
""",
2323
diagnostics: [
24-
DiagnosticSpec(message: "expected member block in actor", fixIts: ["insert member block"])
24+
DiagnosticSpec(
25+
message: "expected member block in actor",
26+
fixIts: ["insert member block"]
27+
)
2528
]
2629
)
2730
}

Tests/SwiftParserTest/translated/AsyncTests.swift

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ final class AsyncTests: XCTestCase {
2929
assertParse(
3030
"func asyncGlobal3() throws 1️⃣async { }",
3131
diagnostics: [
32-
DiagnosticSpec(message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"])
32+
DiagnosticSpec(
33+
message: "'async' must precede 'throws'",
34+
fixIts: ["move 'async' in front of 'throws'"]
35+
)
3336
],
3437
fixedSource: "func asyncGlobal3() async throws { }"
3538
)
@@ -39,7 +42,10 @@ final class AsyncTests: XCTestCase {
3942
assertParse(
4043
"func asyncGlobal3(fn: () throws -> Int) rethrows 1️⃣async { }",
4144
diagnostics: [
42-
DiagnosticSpec(message: "'async' must precede 'rethrows'", fixIts: ["move 'async' in front of 'rethrows'"])
45+
DiagnosticSpec(
46+
message: "'async' must precede 'rethrows'",
47+
fixIts: ["move 'async' in front of 'rethrows'"]
48+
)
4349
],
4450
fixedSource: "func asyncGlobal3(fn: () throws -> Int) async rethrows { }"
4551
)
@@ -49,7 +55,10 @@ final class AsyncTests: XCTestCase {
4955
assertParse(
5056
"func asyncGlobal4() -> Int 1️⃣async { }",
5157
diagnostics: [
52-
DiagnosticSpec(message: "'async' must preceed '->'", fixIts: ["move 'async' in front of '->'"])
58+
DiagnosticSpec(
59+
message: "'async' must preceed '->'",
60+
fixIts: ["move 'async' in front of '->'"]
61+
)
5362
],
5463
fixedSource: "func asyncGlobal4() async -> Int { }"
5564
)
@@ -59,7 +68,10 @@ final class AsyncTests: XCTestCase {
5968
assertParse(
6069
"func asyncGlobal5() -> Int 1️⃣async throws { }",
6170
diagnostics: [
62-
DiagnosticSpec(message: "'async throws' must preceed '->'", fixIts: ["move 'async throws' in front of '->'"])
71+
DiagnosticSpec(
72+
message: "'async throws' must preceed '->'",
73+
fixIts: ["move 'async throws' in front of '->'"]
74+
)
6375
],
6476
fixedSource: "func asyncGlobal5() async throws -> Int { }"
6577
)
@@ -69,7 +81,10 @@ final class AsyncTests: XCTestCase {
6981
assertParse(
7082
"func asyncGlobal6() -> Int 1️⃣throws async { }",
7183
diagnostics: [
72-
DiagnosticSpec(message: "'throws async' must preceed '->'", fixIts: ["move 'throws async' in front of '->'"])
84+
DiagnosticSpec(
85+
message: "'throws async' must preceed '->'",
86+
fixIts: ["move 'throws async' in front of '->'"]
87+
)
7388
],
7489
fixedSource: "func asyncGlobal6() async throws -> Int { }"
7590
)
@@ -79,7 +94,10 @@ final class AsyncTests: XCTestCase {
7994
assertParse(
8095
"func asyncGlobal7() throws -> Int 1️⃣async { }",
8196
diagnostics: [
82-
DiagnosticSpec(message: "'async' must preceed '->'", fixIts: ["move 'async' in front of '->'"])
97+
DiagnosticSpec(
98+
message: "'async' must preceed '->'",
99+
fixIts: ["move 'async' in front of '->'"]
100+
)
83101
],
84102
fixedSource: "func asyncGlobal7() async throws -> Int { }"
85103
)
@@ -88,12 +106,25 @@ final class AsyncTests: XCTestCase {
88106
func testAsync8() {
89107
assertParse(
90108
"""
91-
func asyncGlobal8() async throws 1️⃣async -> 2️⃣async Int 3️⃣async {}
109+
func asyncGlobal8() ℹ️async throws 1️⃣async -> 2️⃣async Int 3️⃣async {}
92110
""",
93111
diagnostics: [
94-
DiagnosticSpec(locationMarker: "1️⃣", message: "'async' has already been specified", fixIts: ["remove redundant 'async'"]),
95-
DiagnosticSpec(locationMarker: "2️⃣", message: "'async' must preceed '->'", fixIts: ["remove redundant 'async'"]),
96-
DiagnosticSpec(locationMarker: "3️⃣", message: "'async' must preceed '->'", fixIts: ["remove redundant 'async'"]),
112+
DiagnosticSpec(
113+
locationMarker: "1️⃣",
114+
message: "'async' has already been specified",
115+
notes: [NoteSpec(message: "'async' declared here")],
116+
fixIts: ["remove redundant 'async'"]
117+
),
118+
DiagnosticSpec(
119+
locationMarker: "2️⃣",
120+
message: "'async' must preceed '->'",
121+
fixIts: ["remove redundant 'async'"]
122+
),
123+
DiagnosticSpec(
124+
locationMarker: "3️⃣",
125+
message: "'async' must preceed '->'",
126+
fixIts: ["remove redundant 'async'"]
127+
),
97128
],
98129
fixedSource: """
99130
func asyncGlobal8() async throws -> Int {}
@@ -118,7 +149,11 @@ final class AsyncTests: XCTestCase {
118149
}
119150
""",
120151
diagnostics: [
121-
DiagnosticSpec(locationMarker: "1️⃣", message: "deinitializers cannot have a name", fixIts: ["remove 'async'"]),
152+
DiagnosticSpec(
153+
locationMarker: "1️⃣",
154+
message: "deinitializers cannot have a name",
155+
fixIts: ["remove 'async'"]
156+
),
122157
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code 'async' in subscript"),
123158
]
124159
)
@@ -144,7 +179,10 @@ final class AsyncTests: XCTestCase {
144179
assertParse(
145180
"typealias AsyncFunc3 = () throws 1️⃣async -> ()",
146181
diagnostics: [
147-
DiagnosticSpec(message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"])
182+
DiagnosticSpec(
183+
message: "'async' must precede 'throws'",
184+
fixIts: ["move 'async' in front of 'throws'"]
185+
)
148186
],
149187
fixedSource: "typealias AsyncFunc3 = () async throws -> ()"
150188
)
@@ -170,7 +208,10 @@ final class AsyncTests: XCTestCase {
170208
assertParse(
171209
"let _ = [() throws 1️⃣async -> ()]()",
172210
diagnostics: [
173-
DiagnosticSpec(message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"])
211+
DiagnosticSpec(
212+
message: "'async' must precede 'throws'",
213+
fixIts: ["move 'async' in front of 'throws'"]
214+
)
174215
],
175216
fixedSource: "let _ = [() async throws -> ()]()"
176217
)
@@ -182,7 +223,10 @@ final class AsyncTests: XCTestCase {
182223
let _ = [() -> 1️⃣async ()]()
183224
""",
184225
diagnostics: [
185-
DiagnosticSpec(message: "'async' must preceed '->'", fixIts: ["move 'async' in front of '->'"])
226+
DiagnosticSpec(
227+
message: "'async' must preceed '->'",
228+
fixIts: ["move 'async' in front of '->'"]
229+
)
186230
],
187231
fixedSource: """
188232
let _ = [() async -> ()]()

0 commit comments

Comments
 (0)