Skip to content

Commit 0166ce0

Browse files
committed
create test harness
To run, execute `make check-stage0-syntax`
1 parent 41c9950 commit 0166ce0

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

src/libsyntax/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,7 @@ pub mod ext {
141141
}
142142
}
143143

144+
#[cfg(test)]
145+
mod test_snippet;
146+
144147
// __build_diagnostic_array! { libsyntax, DIAGNOSTICS }

src/libsyntax/test_snippet.rs

+218
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
use codemap::CodeMap;
2+
use errors::Handler;
3+
use errors::emitter::EmitterWriter;
4+
use std::io;
5+
use std::io::prelude::*;
6+
use std::rc::Rc;
7+
use std::str;
8+
use std::sync::{Arc, Mutex};
9+
use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
10+
11+
/// Identify a position in the text by the Nth occurrence of a string.
12+
struct Position {
13+
string: &'static str,
14+
count: usize,
15+
}
16+
17+
struct SpanLabel {
18+
start: Position,
19+
end: Position,
20+
label: &'static str,
21+
}
22+
23+
struct Shared<T: Write> {
24+
data: Arc<Mutex<T>>,
25+
}
26+
27+
impl<T: Write> Write for Shared<T> {
28+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
29+
self.data.lock().unwrap().write(buf)
30+
}
31+
32+
fn flush(&mut self) -> io::Result<()> {
33+
self.data.lock().unwrap().flush()
34+
}
35+
}
36+
37+
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
38+
let output = Arc::new(Mutex::new(Vec::new()));
39+
40+
let code_map = Rc::new(CodeMap::new());
41+
code_map.new_filemap_and_lines("test.rs", None, &file_text);
42+
43+
let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
44+
let mut msp = MultiSpan::from_span(primary_span);
45+
for span_label in span_labels {
46+
let span = make_span(&file_text, &span_label.start, &span_label.end);
47+
msp.push_span_label(span, span_label.label.to_string());
48+
println!("span: {:?} label: {:?}", span, span_label.label);
49+
println!("text: {:?}", code_map.span_to_snippet(span));
50+
}
51+
52+
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
53+
Some(code_map.clone()));
54+
let handler = Handler::with_emitter(true, false, Box::new(emitter));
55+
handler.span_err(msp, "foo");
56+
57+
assert!(expected_output.chars().next() == Some('\n'),
58+
"expected output should begin with newline");
59+
let expected_output = &expected_output[1..];
60+
61+
let bytes = output.lock().unwrap();
62+
let actual_output = str::from_utf8(&bytes).unwrap();
63+
println!("expected output:\n------\n{}------", expected_output);
64+
println!("actual output:\n------\n{}------", actual_output);
65+
66+
assert!(expected_output == actual_output)
67+
}
68+
69+
fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
70+
let start = make_pos(file_text, start);
71+
let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
72+
assert!(start <= end);
73+
Span {
74+
lo: BytePos(start as u32),
75+
hi: BytePos(end as u32),
76+
expn_id: NO_EXPANSION,
77+
}
78+
}
79+
80+
fn make_pos(file_text: &str, pos: &Position) -> usize {
81+
let mut remainder = file_text;
82+
let mut offset = 0;
83+
for _ in 0..pos.count {
84+
if let Some(n) = remainder.find(&pos.string) {
85+
offset += n;
86+
remainder = &remainder[n + 1..];
87+
} else {
88+
panic!("failed to find {} instances of {:?} in {:?}",
89+
pos.count,
90+
pos.string,
91+
file_text);
92+
}
93+
}
94+
offset
95+
}
96+
97+
#[test]
98+
fn ends_on_col0() {
99+
test_harness(r#"
100+
fn foo() {
101+
}
102+
"#,
103+
vec![SpanLabel {
104+
start: Position {
105+
string: "{",
106+
count: 1,
107+
},
108+
end: Position {
109+
string: "}",
110+
count: 1,
111+
},
112+
label: "test",
113+
}],
114+
r#"
115+
error: foo
116+
--> test.rs:2:10
117+
|
118+
2 | fn foo() {
119+
| __________^ starting here...
120+
3 | | }
121+
| |_^ ...ending here: test
122+
123+
"#);
124+
}
125+
126+
#[test]
127+
fn non_nested() {
128+
test_harness(r#"
129+
fn foo() {
130+
X0 Y0
131+
X1 Y1
132+
}
133+
"#,
134+
vec![SpanLabel {
135+
start: Position {
136+
string: "X0",
137+
count: 1,
138+
},
139+
end: Position {
140+
string: "X1",
141+
count: 1,
142+
},
143+
label: "`X` is a good letter",
144+
},
145+
SpanLabel {
146+
start: Position {
147+
string: "Y0",
148+
count: 1,
149+
},
150+
end: Position {
151+
string: "Y1",
152+
count: 1,
153+
},
154+
label: "`Y` is a good letter too",
155+
},
156+
],
157+
r#"
158+
error: foo
159+
--> test.rs:3:3
160+
|
161+
3 | X0 Y0
162+
| _______- starting here...
163+
| |
164+
| starting here...
165+
4 | || X1 Y1
166+
| |________- ...ending here: `Y` is a good letter too
167+
| |
168+
| ...ending here: `X` is a good letter
169+
170+
"#);
171+
}
172+
173+
#[test]
174+
fn nested() {
175+
test_harness(r#"
176+
fn foo() {
177+
X0 Y0
178+
Y1 X1
179+
}
180+
"#,
181+
vec![SpanLabel {
182+
start: Position {
183+
string: "X0",
184+
count: 1,
185+
},
186+
end: Position {
187+
string: "X1",
188+
count: 1,
189+
},
190+
label: "`X` is a good letter",
191+
},
192+
SpanLabel {
193+
start: Position {
194+
string: "Y0",
195+
count: 1,
196+
},
197+
end: Position {
198+
string: "Y1",
199+
count: 1,
200+
},
201+
label: "`Y` is a good letter too",
202+
},
203+
],
204+
r#"
205+
error: foo
206+
--> test.rs:3:3
207+
|
208+
3 | X0 Y0
209+
| _______- starting here...
210+
| |
211+
| starting here...
212+
4 | || Y1 X1
213+
| ||_______^ ...ending here: `X` is a good letter
214+
| |
215+
| ...ending here: `Y` is a good letter too
216+
217+
"#);
218+
}

0 commit comments

Comments
 (0)