Skip to content

Commit 6afa010

Browse files
beccadaxDougGregor
authored andcommitted
Add a diagnostic verifier
1 parent 657c8fd commit 6afa010

File tree

4 files changed

+424
-19
lines changed

4 files changed

+424
-19
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
//===--- AssertDiagnosticsTests.swift - Diagnostic Test Assertion Tests ---===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 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 XCTest
14+
import SwiftDriver
15+
16+
// Yes, these are meta-tests! `assertDiagnostics(do:)` and friends are
17+
// complicated enough to warrant a few tests of their own. To test that they
18+
// fail when they're supposed to, this test class has access to an
19+
// `assertFails(times:during:)` helper; see `FailableTestCase` below for the
20+
// implementation.
21+
22+
class AssertDiagnosticsTests: FailableTestCase {
23+
func testAssertNoDiagnostics() {
24+
assertNoDiagnostics { _ in }
25+
26+
assertFails {
27+
assertNoDiagnostics { diags in
28+
diags.emit(error: "something happened")
29+
}
30+
}
31+
assertFails {
32+
assertNoDiagnostics { diags in
33+
diags.emit(warning: "hello")
34+
}
35+
}
36+
37+
// Unexpected warnings/notes/remarks are okay
38+
assertNoDiagnostics { diags in
39+
diags.emit(note: "hello")
40+
}
41+
assertNoDiagnostics { diags in
42+
diags.emit(remark: "hello")
43+
}
44+
}
45+
46+
func testAssertDiagnostics() {
47+
assertDiagnostics { diags, match in
48+
diags.emit(error: "yankees won again")
49+
match.expect(.error("won"))
50+
}
51+
assertDiagnostics { diags, match in
52+
match.expect(.error("won"))
53+
diags.emit(error: "yankees won again")
54+
}
55+
56+
assertFails(times: 2) {
57+
assertDiagnostics { diags, match in
58+
match.expect(.error("lost"))
59+
diags.emit(error: "yankees won again")
60+
}
61+
}
62+
63+
assertFails(times: 2) {
64+
assertDiagnostics { diags, match in
65+
diags.emit(error: "yankees won again")
66+
diags.emit(error: "yankees won yet again")
67+
}
68+
}
69+
70+
assertFails(times: 2) {
71+
assertDiagnostics { diags, match in
72+
match.expect(.error("won"))
73+
match.expect(.error("won"))
74+
}
75+
}
76+
77+
// We should get two assertion failures: one for expecting the warning, one
78+
// for emitting the error.
79+
assertFails(times: 2) {
80+
assertDiagnostics { diags, match in
81+
match.expect(.warning("won"))
82+
diags.emit(.error("yankees won again"))
83+
}
84+
}
85+
86+
// We should get one assertion failure for the unexpected error. An
87+
// unexpected note is okay.
88+
assertFails(times: 1) {
89+
assertDiagnostics { diags, match in
90+
diags.emit(error: "yankees won again")
91+
diags.emit(note: "investigate their star's doctor")
92+
}
93+
}
94+
95+
// ...unless we tighten things up.
96+
assertFails(times: 2) {
97+
assertDiagnostics { diags, match in
98+
diags.emit(error: "yankees won again")
99+
diags.emit(note: "investigate their star's doctor")
100+
match.forbidUnexpected(.note)
101+
}
102+
}
103+
104+
// ...or loosen them.
105+
assertDiagnostics { diags, match in
106+
diags.emit(error: "yankees won again")
107+
diags.emit(note: "investigate their star's doctor")
108+
match.permitUnexpected(.error)
109+
}
110+
}
111+
112+
func testAssertDriverDiagosotics() throws {
113+
try assertNoDriverDiagnostics(args: "swiftc", "test.swift")
114+
115+
try assertDriverDiagnostics(args: "swiftc", "test.swift") { driver, verify in
116+
driver.diagnosticEngine.emit(.error_mode_cannot_emit_module)
117+
verify.expect(.error_mode_cannot_emit_module)
118+
}
119+
120+
try assertFails {
121+
try assertDriverDiagnostics(args: "swiftc", "test.swift") { driver, verify in
122+
verify.expect(.error_mode_cannot_emit_module)
123+
}
124+
}
125+
126+
try assertFails {
127+
try assertDriverDiagnostics(args: "swiftc", "test.swift") { driver, verify in
128+
driver.diagnosticEngine.emit(.error_mode_cannot_emit_module)
129+
}
130+
}
131+
132+
try assertFails(times: 2) {
133+
try assertDriverDiagnostics(args: "swiftc", "test.swift") { driver, verify in
134+
driver.diagnosticEngine.emit(.error_mode_cannot_emit_module)
135+
verify.expect(.error_static_emit_executable_disallowed)
136+
}
137+
}
138+
}
139+
}
140+
141+
// MARK: - Failure testing
142+
143+
/// Subclasses are considered to pass if exactly the right number of test assertions
144+
/// fail in each `assertFails(times:during:)` block. Failures are recorded
145+
/// if they fail too often or not often enough.
146+
class FailableTestCase: XCTestCase {
147+
fileprivate var anticipatedFailures = 0
148+
149+
func assertFails(
150+
times: Int = 1,
151+
_ message: String = "",
152+
file: String = #file,
153+
line: Int = #line,
154+
during body: () throws -> Void
155+
) rethrows {
156+
var outer = anticipatedFailures
157+
anticipatedFailures = times
158+
159+
defer {
160+
if anticipatedFailures > 0 {
161+
recordFailure(
162+
withDescription: "\(anticipatedFailures) failure(s) were supposed to occur, but did not: \(message)",
163+
inFile: file, atLine: line,
164+
expected: false
165+
)
166+
}
167+
anticipatedFailures = outer
168+
}
169+
170+
try body()
171+
}
172+
173+
override func setUp() {
174+
super.setUp()
175+
anticipatedFailures = 0
176+
}
177+
178+
override func recordFailure(
179+
withDescription description: String,
180+
inFile filePath: String, atLine lineNumber: Int,
181+
expected: Bool
182+
) {
183+
guard anticipatedFailures == 0 else {
184+
anticipatedFailures -= 1
185+
return
186+
}
187+
188+
super.recordFailure(
189+
withDescription: description,
190+
inFile: filePath, atLine: lineNumber,
191+
expected: expected
192+
)
193+
}
194+
}

0 commit comments

Comments
 (0)