Skip to content

Commit 44d3b8b

Browse files
committed
WIP
1 parent d8a5f0b commit 44d3b8b

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SwiftDiagnostics
14+
import XCTest
15+
import SwiftSyntax
16+
import SwiftSyntaxBuilder
17+
import _SwiftSyntaxTestSupport
18+
import SwiftParser
19+
20+
struct DiagnosticDescriptor {
21+
let locationMarker: String
22+
let id: MessageID
23+
let message: String
24+
let severity: DiagnosticSeverity
25+
let highlight: [Syntax] // TODO: How to create an abstract model for this?
26+
let noteDescriptors: [NoteDescriptor]
27+
let fixIts: [FixIt] // TODO: How to create an abstract model for this?
28+
29+
init(
30+
locationMarker: String,
31+
id: MessageID,
32+
message: String,
33+
severity: DiagnosticSeverity = .error,
34+
highlight: [Syntax] = [],
35+
noteDescriptors: [NoteDescriptor] = [],
36+
fixIts: [FixIt] = []
37+
) {
38+
self.locationMarker = locationMarker
39+
self.id = id
40+
self.message = message
41+
self.severity = severity
42+
self.highlight = highlight
43+
self.noteDescriptors = noteDescriptors
44+
self.fixIts = fixIts
45+
}
46+
}
47+
48+
struct NoteDescriptor {
49+
let locationMarker: String
50+
let id: MessageID
51+
let message: String
52+
}
53+
54+
func assertAnnotated(
55+
markedSource: String,
56+
withDiagnostics diagnosticDescriptors: [DiagnosticDescriptor],
57+
matches expectedAnnotatedSource: String,
58+
file: StaticString = #file,
59+
line: UInt = #line
60+
) {
61+
let (markers, source) = extractMarkers(markedSource)
62+
let tree = Parser.parse(source: source)
63+
64+
var diagnostics = [Diagnostic]()
65+
for diagnosticDescriptor in diagnosticDescriptors {
66+
guard let markerOffset = markers[diagnosticDescriptor.locationMarker] else {
67+
XCTFail("Marker \(diagnosticDescriptor.locationMarker) not found in the marked source", file: file, line: line)
68+
continue
69+
}
70+
let markerPosition = AbsolutePosition(utf8Offset: markerOffset)
71+
guard let token = tree.token(at: markerPosition), let node = token.parent else {
72+
XCTFail("Node not found at marker \(diagnosticDescriptor.locationMarker)", file: file, line: line)
73+
continue
74+
}
75+
76+
var notes = [Note]()
77+
for noteDescriptor in diagnosticDescriptor.noteDescriptors {
78+
guard let markerOffset = markers[noteDescriptor.locationMarker] else {
79+
XCTFail("Marker \(noteDescriptor.locationMarker) not found in the marked source", file: file, line: line)
80+
continue
81+
}
82+
let markerPosition = AbsolutePosition(utf8Offset: markerOffset)
83+
guard let token = tree.token(at: markerPosition), let node = token.parent else {
84+
XCTFail("Node not found at marker \(noteDescriptor.locationMarker)", file: file, line: line)
85+
continue
86+
}
87+
88+
let note = Note(
89+
node: node,
90+
message: SimpleNoteMessage(message: noteDescriptor.message, fixItID: noteDescriptor.id)
91+
)
92+
notes.append(note)
93+
}
94+
95+
let diagnostic = Diagnostic(
96+
node: node,
97+
message: SimpleDiagnosticMessage(
98+
message: diagnosticDescriptor.message,
99+
diagnosticID: diagnosticDescriptor.id,
100+
severity: diagnosticDescriptor.severity
101+
),
102+
highlights: diagnosticDescriptor.highlight,
103+
notes: notes,
104+
fixIts: diagnosticDescriptor.fixIts
105+
)
106+
diagnostics.append(diagnostic)
107+
}
108+
109+
let annotatedSource = DiagnosticsFormatter.annotatedSource(tree: tree, diags: diagnostics)
110+
111+
assertStringsEqualWithDiff(
112+
annotatedSource,
113+
expectedAnnotatedSource,
114+
file: file,
115+
line: line
116+
)
117+
}
118+
119+
final class DiagnosticsFormatterTests: XCTestCase {
120+
func test_1() {
121+
assertAnnotated(
122+
markedSource: """
123+
func foo() -> Int {
124+
if 1️⃣1 != 0 {
125+
return 0
126+
}
127+
return 1
128+
}
129+
""",
130+
withDiagnostics: [
131+
DiagnosticDescriptor(
132+
locationMarker: "1️⃣",
133+
id: .test,
134+
message: "My message goes here!",
135+
severity: .warning
136+
),
137+
],
138+
matches: """
139+
1 │ func foo() -> Int {
140+
2 │ if 1 != 0 {
141+
│ ╰─ warning: My message goes here!
142+
3 │ return 0
143+
4 │ }
144+
145+
"""
146+
)
147+
}
148+
149+
func test_2() {
150+
assertAnnotated(
151+
markedSource: """
152+
func foo() -> Int {
153+
if 1️⃣1 != 0 2️⃣{
154+
return 0
155+
}
156+
return 1
157+
}
158+
""",
159+
withDiagnostics: [
160+
DiagnosticDescriptor(
161+
locationMarker: "1️⃣",
162+
id: .test,
163+
message: "My message goes here!",
164+
noteDescriptors: [
165+
NoteDescriptor(locationMarker: "1️⃣", id: .test, message: "First message"),
166+
NoteDescriptor(locationMarker: "1️⃣", id: .test, message: "Second message"),
167+
NoteDescriptor(locationMarker: "2️⃣", id: .test, message: "Other message")
168+
]
169+
),
170+
],
171+
matches: """
172+
1 │ func foo() -> Int {
173+
2 │ if 1 != 0 {
174+
│ │ ╰─ note: Other message
175+
│ ├─ error: My message goes here!
176+
│ ├─ note: First message
177+
│ ╰─ note: Second message
178+
3 │ return 0
179+
4 │ }
180+
181+
"""
182+
)
183+
}
184+
185+
func test_3() {
186+
assertAnnotated(
187+
markedSource: """
188+
func 2️⃣foo() -> Int {
189+
if 1️⃣1 != 0 {
190+
return 0
191+
}
192+
return 1
193+
}
194+
""",
195+
withDiagnostics: [
196+
DiagnosticDescriptor(
197+
locationMarker: "1️⃣",
198+
id: .test,
199+
message: "My message goes here!",
200+
noteDescriptors: [
201+
NoteDescriptor(locationMarker: "1️⃣", id: .test, message: "First message"),
202+
NoteDescriptor(locationMarker: "2️⃣", id: .test, message: "Second message"),
203+
]
204+
),
205+
],
206+
matches: """
207+
1 │ func foo() -> Int {
208+
| ╰─ note: Second message // This note comes from from diagnostic, how to present it?
209+
2 │ if 1 != 0 {
210+
│ ├─ error: My message goes here!
211+
│ ╰─ note: First message
212+
3 │ return 0
213+
4 │ }
214+
215+
"""
216+
)
217+
}
218+
}
219+
220+
fileprivate extension MessageID {
221+
static let test = Self(domain: "test", id: "conjured")
222+
}

0 commit comments

Comments
 (0)