about summary refs log tree commit diff
path: root/src/compiletest
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-01-03 21:01:48 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-01-04 15:25:17 -0800
commit70c808d173cfb7315131e6bf75e36fa4c9ee7db1 (patch)
tree6555fe35e63ca00b2e3e91a1c5a025095f2c540d /src/compiletest
parent3971b520bcdd556ff78120c77ffd13785e1c3695 (diff)
downloadrust-70c808d173cfb7315131e6bf75e36fa4c9ee7db1.tar.gz
rust-70c808d173cfb7315131e6bf75e36fa4c9ee7db1.zip
extend tester so that error msgs can be attached to lines
Diffstat (limited to 'src/compiletest')
-rw-r--r--src/compiletest/compiletest.rc2
-rw-r--r--src/compiletest/errors.rs54
-rw-r--r--src/compiletest/runtest.rs69
3 files changed, 122 insertions, 3 deletions
diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc
index 703862076a5..a0deaeda26a 100644
--- a/src/compiletest/compiletest.rc
+++ b/src/compiletest/compiletest.rc
@@ -5,11 +5,11 @@ mod util;
 mod header;
 mod runtest;
 mod common;
+mod errors;
 
 // Local Variables:
 // fill-column: 78;
 // indent-tabs-mode: nil
 // c-basic-offset: 4
 // buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
 // End:
diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs
new file mode 100644
index 00000000000..c0d96fc5142
--- /dev/null
+++ b/src/compiletest/errors.rs
@@ -0,0 +1,54 @@
+import option;
+import str;
+import std::io;
+import std::fs;
+
+import common::config;
+
+export load_errors;
+export expected_error;
+
+type expected_error = { line: uint, kind: str, msg: str };
+
+// Load any test directives embedded in the file
+fn load_errors(testfile: str) -> [expected_error] {
+    let error_patterns = [];
+    let rdr = result::get(io::file_reader(testfile));
+    let line_num = 1u;
+    while !rdr.eof() {
+        let ln = rdr.read_line();
+        error_patterns += parse_expected(line_num, ln);
+        line_num += 1u;
+    }
+    ret error_patterns;
+}
+
+fn parse_expected(line_num: uint, line: str) -> [expected_error] {
+    let error_tag = "//!";
+    let idx0 = str::find(line, error_tag);
+    if idx0 < 0 { ret []; }
+    let idx = (idx0 as uint) + str::byte_len(error_tag);
+
+    // "//!^^^ kind msg" denotes a message expected
+    // three lines above current line:
+    let adjust_line = 0u;
+    let len = str::byte_len(line);
+    while idx < len && line[idx] == ('^' as u8) {
+        adjust_line += 1u;
+        idx += 1u;
+    }
+
+    // Extract kind:
+    while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
+    let start_kind = idx;
+    while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
+    let kind = str::to_lower(str::slice(line, start_kind, idx));
+
+    // Extract msg:
+    while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
+    let msg = str::slice(line, idx, len);
+
+    #debug("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
+
+    ret [{line: line_num - adjust_line, kind: kind, msg: msg}];
+}
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index fefa9d7e617..3fc5fc4c75e 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -42,7 +42,16 @@ fn run_cfail_test(cx: cx, props: test_props, testfile: str) {
     }
 
     check_correct_failure_status(procres);
-    check_error_patterns(props, testfile, procres);
+
+    let expected_errors = errors::load_errors(testfile);
+    if vec::is_not_empty(expected_errors) {
+        if vec::is_not_empty(props.error_patterns) {
+            fatal("both error pattern and expected errors specified");
+        }
+        check_expected_errors(expected_errors, testfile, procres);
+    } else {
+        check_error_patterns(props, testfile, procres);
+    }
 }
 
 fn run_rfail_test(cx: cx, props: test_props, testfile: str) {
@@ -181,7 +190,9 @@ actual:\n\
     }
 }
 
-fn check_error_patterns(props: test_props, testfile: str, procres: procres) {
+fn check_error_patterns(props: test_props,
+                        testfile: str,
+                        procres: procres) {
     if vec::is_empty(props.error_patterns) {
         fatal("no error pattern specified in " + testfile);
     }
@@ -218,6 +229,60 @@ fn check_error_patterns(props: test_props, testfile: str, procres: procres) {
     }
 }
 
+fn check_expected_errors(expected_errors: [errors::expected_error],
+                         testfile: str,
+                         procres: procres) {
+
+    // true if we found the error in question
+    let found_flags = vec::init_elt_mut(false, vec::len(expected_errors));
+
+    if procres.status == 0 {
+        fatal("process did not return an error status");
+    }
+
+    // Scan and extract our error/warning messages,
+    // which look like:
+    //    filename:line1:col1: line2:col2: *error:* msg
+    //    filename:line1:col1: line2:col2: *warning:* msg
+    // where line1:col1: is the starting point, line2:col2:
+    // is the ending point, and * represents ANSI color codes.
+    for line: str in str::split(procres.stdout, '\n' as u8) {
+        let was_expected = false;
+        vec::iteri(expected_errors) {|i, ee|
+            if !found_flags[i] {
+                let needle = #fmt("%s:%u:", testfile, ee.line);
+                #debug["needle=%s ee.kind=%s ee.msg=%s line=%s",
+                       needle, ee.kind, ee.msg, line];
+                if (str::contains(line, needle) &&
+                    str::contains(line, ee.kind) &&
+                    str::contains(line, ee.msg)) {
+                    found_flags[i] = true;
+                    was_expected = true;
+                }
+            }
+        }
+
+        // ignore this msg which gets printed at the end
+        if str::contains(line, "aborting due to previous errors") {
+            was_expected = true;
+        }
+
+        if !was_expected && (str::contains(line, "error") ||
+                             str::contains(line, "warning")) {
+            fatal_procres(#fmt["unexpected error pattern '%s'!", line],
+                          procres);
+        }
+    }
+
+    uint::range(0u, vec::len(found_flags)) {|i|
+        if !found_flags[i] {
+            let ee = expected_errors[i];
+            fatal_procres(#fmt["expected %s on line %u not found: %s",
+                               ee.kind, ee.line, ee.msg], procres);
+        }
+    }
+}
+
 type procargs = {prog: str, args: [str]};
 
 type procres = {status: int, stdout: str, stderr: str, cmdline: str};