1
Fork 0

thread revision identifier around in test output

This commit is contained in:
Niko Matsakis 2016-03-02 04:16:30 -05:00
parent 4cffa9b4e3
commit 3fb80e33a8

View file

@ -103,28 +103,30 @@ fn run_cfail_test_revision(config: &Config,
let proc_res = compile_test(config, props, testpaths);
if proc_res.status.success() {
fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..],
&proc_res);
fatal_proc_rec(
revision,
&format!("{} test compiled successfully!", config.mode)[..],
&proc_res);
}
check_correct_failure_status(&proc_res);
check_correct_failure_status(revision, &proc_res);
if proc_res.status.success() {
fatal("process did not return an error status");
fatal(revision, "process did not return an error status");
}
let output_to_check = get_output(props, &proc_res);
let expected_errors = errors::load_errors(&testpaths.file, revision);
if !expected_errors.is_empty() {
if !props.error_patterns.is_empty() {
fatal("both error pattern and expected errors specified");
fatal(revision, "both error pattern and expected errors specified");
}
check_expected_errors(expected_errors, testpaths, &proc_res);
check_expected_errors(revision, expected_errors, testpaths, &proc_res);
} else {
check_error_patterns(props, testpaths, &output_to_check, &proc_res);
check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
}
check_no_compiler_crash(&proc_res);
check_forbid_output(props, &output_to_check, &proc_res);
check_no_compiler_crash(revision, &proc_res);
check_forbid_output(revision, props, &output_to_check, &proc_res);
}
fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
@ -134,11 +136,11 @@ fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
fn run_rfail_test_revision(config: &Config,
props: &TestProps,
testpaths: &TestPaths,
_revision: Option<&str>) {
revision: Option<&str>) {
let proc_res = compile_test(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
fatal_proc_rec(revision, "compilation failed!", &proc_res);
}
let proc_res = exec_compiled_test(config, props, testpaths);
@ -146,19 +148,20 @@ fn run_rfail_test_revision(config: &Config,
// The value our Makefile configures valgrind to return on failure
const VALGRIND_ERR: i32 = 100;
if proc_res.status.code() == Some(VALGRIND_ERR) {
fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
fatal_proc_rec(revision, "run-fail test isn't valgrind-clean!", &proc_res);
}
let output_to_check = get_output(props, &proc_res);
check_correct_failure_status(&proc_res);
check_error_patterns(props, testpaths, &output_to_check, &proc_res);
check_correct_failure_status(revision, &proc_res);
check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
}
fn check_correct_failure_status(proc_res: &ProcRes) {
fn check_correct_failure_status(revision: Option<&str>, proc_res: &ProcRes) {
// The value the rust runtime returns on failure
const RUST_ERR: i32 = 101;
if proc_res.status.code() != Some(RUST_ERR) {
fatal_proc_rec(
revision,
&format!("failure produced the wrong error: {}",
proc_res.status),
proc_res);
@ -172,22 +175,22 @@ fn run_rpass_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
fn run_rpass_test_revision(config: &Config,
props: &TestProps,
testpaths: &TestPaths,
_revision: Option<&str>) {
revision: Option<&str>) {
let proc_res = compile_test(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
fatal_proc_rec(revision, "compilation failed!", &proc_res);
}
let proc_res = exec_compiled_test(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("test run failed!", &proc_res);
fatal_proc_rec(revision, "test run failed!", &proc_res);
}
}
fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant to rpass tests");
assert!(props.revisions.is_empty(), "revisions not relevant here");
if config.valgrind_path.is_none() {
assert!(!config.force_valgrind);
@ -197,7 +200,7 @@ fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths)
let mut proc_res = compile_test(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
fatal_proc_rec(None, "compilation failed!", &proc_res);
}
let mut new_config = config.clone();
@ -205,11 +208,13 @@ fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths)
proc_res = exec_compiled_test(&new_config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("test run failed!", &proc_res);
fatal_proc_rec(None, "test run failed!", &proc_res);
}
}
fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant here");
if props.pp_exact.is_some() {
logv(config, "testing for exact pretty-printing".to_owned());
} else {
@ -233,8 +238,9 @@ fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
&props.pretty_mode);
if !proc_res.status.success() {
fatal_proc_rec(&format!("pretty-printing failed in round {}", round),
&proc_res);
fatal_proc_rec(None,
&format!("pretty-printing failed in round {}", round),
&proc_res);
}
let ProcRes{ stdout, .. } = proc_res;
@ -269,21 +275,23 @@ fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
let proc_res = typecheck_source(config, props, testpaths, actual);
if !proc_res.status.success() {
fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
fatal_proc_rec(None, "pretty-printed source does not typecheck", &proc_res);
}
if !props.pretty_expanded { return }
// additionally, run `--pretty expanded` and try to build it.
let proc_res = print_source(config, props, testpaths, srcs[round].clone(), "expanded");
if !proc_res.status.success() {
fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
fatal_proc_rec(None, "pretty-printing (expanded) failed", &proc_res);
}
let ProcRes{ stdout: expanded_src, .. } = proc_res;
let proc_res = typecheck_source(config, props, testpaths, expanded_src);
if !proc_res.status.success() {
fatal_proc_rec("pretty-printed source (expanded) does not typecheck",
&proc_res);
fatal_proc_rec(
None,
"pretty-printed source (expanded) does not typecheck",
&proc_res);
}
return;
@ -329,7 +337,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
fn compare_source(expected: &str, actual: &str) {
if expected != actual {
error("pretty-printed source does not match expected source");
error(None, "pretty-printed source does not match expected source");
println!("\n\
expected:\n\
------------------------------------------\n\
@ -377,6 +385,8 @@ actual:\n\
}
fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant here");
let mut config = Config {
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
@ -394,7 +404,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa
// compile test file (it should have 'compile-flags:-g' in the header)
let compiler_run_result = compile_test(config, props, testpaths);
if !compiler_run_result.status.success() {
fatal_proc_rec("compilation failed!", &compiler_run_result);
fatal_proc_rec(None, "compilation failed!", &compiler_run_result);
}
let exe_file = make_exe_name(config, testpaths);
@ -486,7 +496,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa
let tool_path = match config.android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => fatal("cannot find android cross path")
None => fatal(None, "cannot find android cross path")
};
let debugger_script = make_out_name(config, testpaths, "debugger.script");
@ -625,7 +635,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa
}
if !debugger_run_result.status.success() {
fatal("gdb failed to execute");
fatal(None, "gdb failed to execute");
}
check_debugger_output(&debugger_run_result, &check_lines);
@ -645,8 +655,10 @@ fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
}
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant here");
if config.lldb_python_dir.is_none() {
fatal("Can't run LLDB test because LLDB's python path is not set.");
fatal(None, "Can't run LLDB test because LLDB's python path is not set.");
}
let mut config = Config {
@ -660,7 +672,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestP
// compile test file (it should have 'compile-flags:-g' in the header)
let compile_result = compile_test(config, props, testpaths);
if !compile_result.status.success() {
fatal_proc_rec("compilation failed!", &compile_result);
fatal_proc_rec(None, "compilation failed!", &compile_result);
}
let exe_file = make_exe_name(config, testpaths);
@ -737,7 +749,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestP
&rust_src_root);
if !debugger_run_result.status.success() {
fatal_proc_rec("Error while running LLDB", &debugger_run_result);
fatal_proc_rec(None, "Error while running LLDB", &debugger_run_result);
}
check_debugger_output(&debugger_run_result, &check_lines);
@ -770,7 +782,7 @@ fn cmd2procres(config: &Config, testpaths: &TestPaths, cmd: &mut Command)
String::from_utf8(stderr).unwrap())
},
Err(e) => {
fatal(&format!("Failed to setup Python process for \
fatal(None, &format!("Failed to setup Python process for \
LLDB script: {}", e))
}
};
@ -820,7 +832,7 @@ fn parse_debugger_commands(testpaths: &TestPaths, debugger_prefix: &str)
});
}
Err(e) => {
fatal(&format!("Error while parsing debugger commands: {}", e))
fatal(None, &format!("Error while parsing debugger commands: {}", e))
}
}
counter += 1;
@ -902,19 +914,21 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
}
}
if i != num_check_lines {
fatal_proc_rec(&format!("line not found in debugger output: {}",
fatal_proc_rec(None, &format!("line not found in debugger output: {}",
check_lines.get(i).unwrap()),
debugger_run_result);
}
}
}
fn check_error_patterns(props: &TestProps,
fn check_error_patterns(revision: Option<&str>,
props: &TestProps,
testpaths: &TestPaths,
output_to_check: &str,
proc_res: &ProcRes) {
if props.error_patterns.is_empty() {
fatal(&format!("no error pattern specified in {:?}",
fatal(revision,
&format!("no error pattern specified in {:?}",
testpaths.file.display()));
}
let mut next_err_idx = 0;
@ -936,44 +950,50 @@ fn check_error_patterns(props: &TestProps,
let missing_patterns = &props.error_patterns[next_err_idx..];
if missing_patterns.len() == 1 {
fatal_proc_rec(&format!("error pattern '{}' not found!", missing_patterns[0]),
proc_res);
fatal_proc_rec(
revision,
&format!("error pattern '{}' not found!", missing_patterns[0]),
proc_res);
} else {
for pattern in missing_patterns {
error(&format!("error pattern '{}' not found!", *pattern));
error(revision, &format!("error pattern '{}' not found!", *pattern));
}
fatal_proc_rec("multiple error patterns not found", proc_res);
fatal_proc_rec(revision, "multiple error patterns not found", proc_res);
}
}
fn check_no_compiler_crash(proc_res: &ProcRes) {
fn check_no_compiler_crash(revision: Option<&str>, proc_res: &ProcRes) {
for line in proc_res.stderr.lines() {
if line.starts_with("error: internal compiler error:") {
fatal_proc_rec("compiler encountered internal error",
proc_res);
fatal_proc_rec(revision,
"compiler encountered internal error",
proc_res);
}
}
}
fn check_forbid_output(props: &TestProps,
fn check_forbid_output(revision: Option<&str>,
props: &TestProps,
output_to_check: &str,
proc_res: &ProcRes) {
for pat in &props.forbid_output {
if output_to_check.contains(pat) {
fatal_proc_rec("forbidden pattern found in compiler output", proc_res);
fatal_proc_rec(revision,
"forbidden pattern found in compiler output",
proc_res);
}
}
}
fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
fn check_expected_errors(revision: Option<&str>,
expected_errors: Vec<errors::ExpectedError>,
testpaths: &TestPaths,
proc_res: &ProcRes) {
// true if we found the error in question
let mut found_flags = vec![false; expected_errors.len()];
if proc_res.status.success() {
fatal("process did not return an error status");
fatal_proc_rec(revision, "process did not return an error status", proc_res);
}
let prefixes = expected_errors.iter().map(|ee| {
@ -989,23 +1009,6 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
(acc_help || ee.kind == "help:", acc_note ||
ee.kind == "note:"));
fn prefix_matches(line: &str, prefix: &str) -> bool {
use std::ascii::AsciiExt;
// On windows just translate all '\' path separators to '/'
let line = line.replace(r"\", "/");
if cfg!(windows) {
line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
} else {
line.starts_with(prefix)
}
}
// A multi-line error will have followup lines which start with a space
// or open paren.
fn continuation( line: &str) -> bool {
line.starts_with(" ") || line.starts_with("(")
}
// Scan and extract our error/warning messages,
// which look like:
// filename:line1:col1: line2:col2: *error:* msg
@ -1015,6 +1018,8 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
//
// This pattern is ambiguous on windows, because filename may contain
// a colon, so any path prefix must be detected and removed first.
let mut unexpected = 0;
let mut not_found = 0;
for line in proc_res.stderr.lines() {
let mut was_expected = false;
let mut prev = 0;
@ -1036,9 +1041,11 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
break;
}
}
if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
if
(prefix_matches(line, &prefixes[i]) || continuation(line)) &&
line.contains(&ee.kind) &&
line.contains(&ee.msg) {
line.contains(&ee.msg)
{
found_flags[i] = true;
was_expected = true;
break;
@ -1053,20 +1060,44 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
}
if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) {
fatal_proc_rec(&format!("unexpected compiler message: '{}'",
line),
proc_res);
error(revision, &format!("unexpected compiler message: '{}'", line));
unexpected += 1;
}
}
for (i, &flag) in found_flags.iter().enumerate() {
if !flag {
let ee = &expected_errors[i];
fatal_proc_rec(&format!("expected {} on line {} not found: {}",
ee.kind, ee.line, ee.msg),
proc_res);
error(revision, &format!("expected {} on line {} not found: {}",
ee.kind, ee.line, ee.msg));
not_found += 1;
}
}
if unexpected > 0 || not_found > 0 {
fatal_proc_rec(
revision,
&format!("{} unexpected errors found, {} expected errors not found",
unexpected, not_found),
proc_res);
}
fn prefix_matches(line: &str, prefix: &str) -> bool {
use std::ascii::AsciiExt;
// On windows just translate all '\' path separators to '/'
let line = line.replace(r"\", "/");
if cfg!(windows) {
line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
} else {
line.starts_with(prefix)
}
}
// A multi-line error will have followup lines which start with a space
// or open paren.
fn continuation( line: &str) -> bool {
line.starts_with(" ") || line.starts_with("(")
}
}
fn is_unexpected_compiler_message(line: &str, expect_help: bool, expect_note: bool) -> bool {
@ -1331,6 +1362,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
None);
if !auxres.status.success() {
fatal_proc_rec(
None,
&format!("auxiliary build of {:?} failed to compile: ",
aux_testpaths.file.display()),
&auxres);
@ -1582,13 +1614,20 @@ fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
}
}
fn error(err: &str) { println!("\nerror: {}", err); }
fn error(revision: Option<&str>, err: &str) {
match revision {
Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
None => println!("\nerror: {}", err)
}
}
fn fatal(err: &str) -> ! { error(err); panic!(); }
fn fatal(revision: Option<&str>, err: &str) -> ! {
error(revision, err); panic!();
}
fn fatal_proc_rec(err: &str, proc_res: &ProcRes) -> ! {
print!("\n\
error: {}\n\
fn fatal_proc_rec(revision: Option<&str>, err: &str, proc_res: &ProcRes) -> ! {
error(revision, err);
print!("\
status: {}\n\
command: {}\n\
stdout:\n\
@ -1600,7 +1639,7 @@ stderr:\n\
{}\n\
------------------------------------------\n\
\n",
err, proc_res.status, proc_res.cmdline, proc_res.stdout,
proc_res.status, proc_res.cmdline, proc_res.stdout,
proc_res.stderr);
panic!();
}
@ -1798,20 +1837,22 @@ fn check_ir_with_filecheck(config: &Config, testpaths: &TestPaths) -> ProcRes {
}
fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant here");
if config.llvm_bin_path.is_none() {
fatal("missing --llvm-bin-path");
fatal(None, "missing --llvm-bin-path");
}
let mut proc_res = compile_test_and_save_ir(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
fatal_proc_rec(None, "compilation failed!", &proc_res);
}
proc_res = check_ir_with_filecheck(config, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("verification with 'FileCheck' failed",
&proc_res);
fatal_proc_rec(None,
"verification with 'FileCheck' failed",
&proc_res);
}
}
@ -1827,13 +1868,15 @@ fn charset() -> &'static str {
}
fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant here");
let out_dir = output_base_name(config, testpaths);
let _ = fs::remove_dir_all(&out_dir);
ensure_dir(&out_dir);
let proc_res = document(config, props, testpaths, &out_dir);
if !proc_res.status.success() {
fatal_proc_rec("rustdoc failed!", &proc_res);
fatal_proc_rec(None, "rustdoc failed!", &proc_res);
}
let root = find_rust_src_root(config).unwrap();
@ -1844,20 +1887,20 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
.arg(out_dir)
.arg(&testpaths.file));
if !res.status.success() {
fatal_proc_rec("htmldocck failed!", &res);
fatal_proc_rec(None, "htmldocck failed!", &res);
}
}
fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
assert!(props.revisions.is_empty(), "revisions not relevant to codegen units");
assert!(props.revisions.is_empty(), "revisions not relevant here");
let proc_res = compile_test(config, props, testpaths);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
fatal_proc_rec(None, "compilation failed!", &proc_res);
}
check_no_compiler_crash(&proc_res);
check_no_compiler_crash(None, &proc_res);
let prefix = "TRANS_ITEM ";