Skip to content

Commit 70c808d

Browse files
committed
extend tester so that error msgs can be attached to lines
1 parent 3971b52 commit 70c808d

File tree

4 files changed

+123
-5
lines changed

4 files changed

+123
-5
lines changed

src/compiletest/compiletest.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ mod util;
55
mod header;
66
mod runtest;
77
mod common;
8+
mod errors;
89

910
// Local Variables:
1011
// fill-column: 78;
1112
// indent-tabs-mode: nil
1213
// c-basic-offset: 4
1314
// buffer-file-coding-system: utf-8-unix
14-
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
1515
// End:

src/compiletest/errors.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import option;
2+
import str;
3+
import std::io;
4+
import std::fs;
5+
6+
import common::config;
7+
8+
export load_errors;
9+
export expected_error;
10+
11+
type expected_error = { line: uint, kind: str, msg: str };
12+
13+
// Load any test directives embedded in the file
14+
fn load_errors(testfile: str) -> [expected_error] {
15+
let error_patterns = [];
16+
let rdr = result::get(io::file_reader(testfile));
17+
let line_num = 1u;
18+
while !rdr.eof() {
19+
let ln = rdr.read_line();
20+
error_patterns += parse_expected(line_num, ln);
21+
line_num += 1u;
22+
}
23+
ret error_patterns;
24+
}
25+
26+
fn parse_expected(line_num: uint, line: str) -> [expected_error] {
27+
let error_tag = "//!";
28+
let idx0 = str::find(line, error_tag);
29+
if idx0 < 0 { ret []; }
30+
let idx = (idx0 as uint) + str::byte_len(error_tag);
31+
32+
// "//!^^^ kind msg" denotes a message expected
33+
// three lines above current line:
34+
let adjust_line = 0u;
35+
let len = str::byte_len(line);
36+
while idx < len && line[idx] == ('^' as u8) {
37+
adjust_line += 1u;
38+
idx += 1u;
39+
}
40+
41+
// Extract kind:
42+
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
43+
let start_kind = idx;
44+
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
45+
let kind = str::to_lower(str::slice(line, start_kind, idx));
46+
47+
// Extract msg:
48+
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
49+
let msg = str::slice(line, idx, len);
50+
51+
#debug("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
52+
53+
ret [{line: line_num - adjust_line, kind: kind, msg: msg}];
54+
}

src/compiletest/runtest.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,16 @@ fn run_cfail_test(cx: cx, props: test_props, testfile: str) {
4242
}
4343

4444
check_correct_failure_status(procres);
45-
check_error_patterns(props, testfile, procres);
45+
46+
let expected_errors = errors::load_errors(testfile);
47+
if vec::is_not_empty(expected_errors) {
48+
if vec::is_not_empty(props.error_patterns) {
49+
fatal("both error pattern and expected errors specified");
50+
}
51+
check_expected_errors(expected_errors, testfile, procres);
52+
} else {
53+
check_error_patterns(props, testfile, procres);
54+
}
4655
}
4756

4857
fn run_rfail_test(cx: cx, props: test_props, testfile: str) {
@@ -181,7 +190,9 @@ actual:\n\
181190
}
182191
}
183192

184-
fn check_error_patterns(props: test_props, testfile: str, procres: procres) {
193+
fn check_error_patterns(props: test_props,
194+
testfile: str,
195+
procres: procres) {
185196
if vec::is_empty(props.error_patterns) {
186197
fatal("no error pattern specified in " + testfile);
187198
}
@@ -218,6 +229,60 @@ fn check_error_patterns(props: test_props, testfile: str, procres: procres) {
218229
}
219230
}
220231

232+
fn check_expected_errors(expected_errors: [errors::expected_error],
233+
testfile: str,
234+
procres: procres) {
235+
236+
// true if we found the error in question
237+
let found_flags = vec::init_elt_mut(false, vec::len(expected_errors));
238+
239+
if procres.status == 0 {
240+
fatal("process did not return an error status");
241+
}
242+
243+
// Scan and extract our error/warning messages,
244+
// which look like:
245+
// filename:line1:col1: line2:col2: *error:* msg
246+
// filename:line1:col1: line2:col2: *warning:* msg
247+
// where line1:col1: is the starting point, line2:col2:
248+
// is the ending point, and * represents ANSI color codes.
249+
for line: str in str::split(procres.stdout, '\n' as u8) {
250+
let was_expected = false;
251+
vec::iteri(expected_errors) {|i, ee|
252+
if !found_flags[i] {
253+
let needle = #fmt("%s:%u:", testfile, ee.line);
254+
#debug["needle=%s ee.kind=%s ee.msg=%s line=%s",
255+
needle, ee.kind, ee.msg, line];
256+
if (str::contains(line, needle) &&
257+
str::contains(line, ee.kind) &&
258+
str::contains(line, ee.msg)) {
259+
found_flags[i] = true;
260+
was_expected = true;
261+
}
262+
}
263+
}
264+
265+
// ignore this msg which gets printed at the end
266+
if str::contains(line, "aborting due to previous errors") {
267+
was_expected = true;
268+
}
269+
270+
if !was_expected && (str::contains(line, "error") ||
271+
str::contains(line, "warning")) {
272+
fatal_procres(#fmt["unexpected error pattern '%s'!", line],
273+
procres);
274+
}
275+
}
276+
277+
uint::range(0u, vec::len(found_flags)) {|i|
278+
if !found_flags[i] {
279+
let ee = expected_errors[i];
280+
fatal_procres(#fmt["expected %s on line %u not found: %s",
281+
ee.kind, ee.line, ee.msg], procres);
282+
}
283+
}
284+
}
285+
221286
type procargs = {prog: str, args: [str]};
222287

223288
type procres = {status: int, stdout: str, stderr: str, cmdline: str};

src/test/compile-fail/alt-join.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// error-pattern:unresolved name
21
// a good test that we merge paths correctly in the presence of a
32
// variable that's used before it's declared
43

@@ -7,6 +6,6 @@ fn my_fail() -> ! { fail; }
76
fn main() {
87
alt true { false { my_fail(); } true { } }
98

10-
log(debug, x);
9+
log(debug, x); //! ERROR unresolved name: x
1110
let x: int;
1211
}

0 commit comments

Comments
 (0)