From 7c2e5e35a61adfee1fec69f811f79930bfd2c3b9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 18 Feb 2016 05:19:19 -0500 Subject: [PATCH] Generalize from passing around a single path to the test file to passing around a set of paths called `TestPaths` This commit is not quite standalone; it basically contains all the borrowing plumbing bits, the interesting stuff comes in the next commit. --- src/compiletest/compiletest.rs | 51 ++++-- src/compiletest/runtest.rs | 321 +++++++++++++++++---------------- src/libtest/lib.rs | 7 +- 3 files changed, 208 insertions(+), 171 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index da8331fc0628..e29a55bbadc3 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -28,10 +28,12 @@ extern crate log; use std::env; use std::fs; +use std::io; use std::path::{Path, PathBuf}; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb}; +use test::TestPaths; use util::logv; pub mod procsrv; @@ -267,15 +269,35 @@ pub fn make_tests(config: &Config) -> Vec { debug!("making tests from {:?}", config.src_base.display()); let mut tests = Vec::new(); - let dirs = fs::read_dir(&config.src_base).unwrap(); + collect_tests_from_dir(config, + &config.src_base, + &config.src_base, + &PathBuf::new(), + &mut tests) + .unwrap(); + tests +} + +fn collect_tests_from_dir(config: &Config, + base: &Path, + dir: &Path, + relative_dir_path: &Path, + tests: &mut Vec) + -> io::Result<()> { for file in dirs { - let file = file.unwrap().path(); - debug!("inspecting file {:?}", file.display()); - if is_test(config, &file) { - tests.push(make_test(config, &file)) + let file = try!(file); + let file_path = file.path(); + debug!("inspecting file {:?}", file_path.display()); + if is_test(config, &file_path) { + let paths = TestPaths { + file: file_path, + base: base.to_path_buf(), + relative_dir: relative_dir_path.to_path_buf(), + }; + tests.push(make_test(config, &paths)) } } - tests + Ok(()) } pub fn is_test(config: &Config, testfile: &Path) -> bool { @@ -305,15 +327,14 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool { return valid; } -pub fn make_test(config: &Config, testfile: &Path) -> test::TestDescAndFn -{ +pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn { test::TestDescAndFn { desc: test::TestDesc { - name: make_test_name(config, testfile), - ignore: header::is_test_ignored(config, testfile), + name: make_test_name(config, testpaths), + ignore: header::is_test_ignored(config, &testpaths.file), should_panic: test::ShouldPanic::No, }, - testfn: make_test_closure(config, &testfile), + testfn: make_test_closure(config, testpaths), } } @@ -330,11 +351,11 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName { test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile))) } -pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn { - let config = (*config).clone(); - let testfile = testfile.to_path_buf(); +pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn { + let config = config.clone(); + let testpaths = testpaths.clone(); test::DynTestFn(Box::new(move || { - runtest::run(config, &testfile) + runtest::run(config, &testpaths) })) } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5eef6b7f24c0..601033ff5e8f 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -15,6 +15,7 @@ use errors; use header::TestProps; use header; use procsrv; +use test::TestPaths; use util::logv; use std::env; @@ -27,7 +28,7 @@ use std::net::TcpStream; use std::path::{Path, PathBuf, Component}; use std::process::{Command, Output, ExitStatus}; -pub fn run(config: Config, testfile: &Path) { +pub fn run(config: Config, testpaths: &TestPaths) { match &*config.target { "arm-linux-androideabi" | "aarch64-linux-android" => { @@ -43,21 +44,21 @@ pub fn run(config: Config, testfile: &Path) { // We're going to be dumping a lot of info. Start on a new line. print!("\n\n"); } - debug!("running {:?}", testfile.display()); - let props = header::load_props(&testfile); + debug!("running {:?}", testpaths.file.display()); + let props = header::load_props(&testpaths.file); debug!("loaded props"); match config.mode { - CompileFail => run_cfail_test(&config, &props, &testfile), - ParseFail => run_cfail_test(&config, &props, &testfile), - RunFail => run_rfail_test(&config, &props, &testfile), - RunPass => run_rpass_test(&config, &props, &testfile), - RunPassValgrind => run_valgrind_test(&config, &props, &testfile), - Pretty => run_pretty_test(&config, &props, &testfile), - DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile), - DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile), - Codegen => run_codegen_test(&config, &props, &testfile), - Rustdoc => run_rustdoc_test(&config, &props, &testfile), - CodegenUnits => run_codegen_units_test(&config, &props, &testfile), + CompileFail => run_cfail_test(&config, &props, &testpaths), + ParseFail => run_cfail_test(&config, &props, &testpaths), + RunFail => run_rfail_test(&config, &props, &testpaths), + RunPass => run_rpass_test(&config, &props, &testpaths), + RunPassValgrind => run_valgrind_test(&config, &props, &testpaths), + Pretty => run_pretty_test(&config, &props, &testpaths), + DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testpaths), + DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testpaths), + Codegen => run_codegen_test(&config, &props, &testpaths), + Rustdoc => run_rustdoc_test(&config, &props, &testpaths), + CodegenUnits => run_codegen_units_test(&config, &props, &testpaths), } } @@ -69,8 +70,8 @@ fn get_output(props: &TestProps, proc_res: &ProcRes) -> String { } } -fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { - let proc_res = compile_test(config, props, testfile); +fn run_cfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + let proc_res = compile_test(config, props, testpaths); if proc_res.status.success() { fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..], @@ -84,27 +85,27 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { } let output_to_check = get_output(props, &proc_res); - let expected_errors = errors::load_errors(testfile); + let expected_errors = errors::load_errors(&testpaths.file); if !expected_errors.is_empty() { if !props.error_patterns.is_empty() { fatal("both error pattern and expected errors specified"); } - check_expected_errors(expected_errors, testfile, &proc_res); + check_expected_errors(expected_errors, testpaths, &proc_res); } else { - check_error_patterns(props, testfile, &output_to_check, &proc_res); + check_error_patterns(props, testpaths, &output_to_check, &proc_res); } check_no_compiler_crash(&proc_res); check_forbid_output(props, &output_to_check, &proc_res); } -fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) { - let proc_res = compile_test(config, props, testfile); +fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + let proc_res = compile_test(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("compilation failed!", &proc_res); } - let proc_res = exec_compiled_test(config, props, testfile); + let proc_res = exec_compiled_test(config, props, testpaths); // The value our Makefile configures valgrind to return on failure const VALGRIND_ERR: i32 = 100; @@ -114,7 +115,7 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) { let output_to_check = get_output(props, &proc_res); check_correct_failure_status(&proc_res); - check_error_patterns(props, testfile, &output_to_check, &proc_res); + check_error_patterns(props, testpaths, &output_to_check, &proc_res); } fn check_correct_failure_status(proc_res: &ProcRes) { @@ -128,27 +129,27 @@ fn check_correct_failure_status(proc_res: &ProcRes) { } } -fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) { - let proc_res = compile_test(config, props, testfile); +fn run_rpass_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + let proc_res = compile_test(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("compilation failed!", &proc_res); } - let proc_res = exec_compiled_test(config, props, testfile); + let proc_res = exec_compiled_test(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("test run failed!", &proc_res); } } -fn run_valgrind_test(config: &Config, props: &TestProps, testfile: &Path) { +fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { if config.valgrind_path.is_none() { assert!(!config.force_valgrind); - return run_rpass_test(config, props, testfile); + return run_rpass_test(config, props, testpaths); } - let mut proc_res = compile_test(config, props, testfile); + let mut proc_res = compile_test(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("compilation failed!", &proc_res); @@ -156,14 +157,14 @@ fn run_valgrind_test(config: &Config, props: &TestProps, testfile: &Path) { let mut new_config = config.clone(); new_config.runtool = new_config.valgrind_path.clone(); - proc_res = exec_compiled_test(&new_config, props, testfile); + proc_res = exec_compiled_test(&new_config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("test run failed!", &proc_res); } } -fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { +fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { if props.pp_exact.is_some() { logv(config, "testing for exact pretty-printing".to_owned()); } else { @@ -174,7 +175,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { match props.pp_exact { Some(_) => 1, None => 2 }; let mut src = String::new(); - File::open(testfile).unwrap().read_to_string(&mut src).unwrap(); + File::open(&testpaths.file).unwrap().read_to_string(&mut src).unwrap(); let mut srcs = vec!(src); let mut round = 0; @@ -182,7 +183,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { logv(config, format!("pretty-printing round {}", round)); let proc_res = print_source(config, props, - testfile, + testpaths, srcs[round].to_owned(), &props.pretty_mode); @@ -198,7 +199,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { let mut expected = match props.pp_exact { Some(ref file) => { - let filepath = testfile.parent().unwrap().join(file); + let filepath = testpaths.file.parent().unwrap().join(file); let mut s = String::new(); File::open(&filepath).unwrap().read_to_string(&mut s).unwrap(); s @@ -220,7 +221,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { if props.pretty_compare_only { return; } // Finally, let's make sure it actually appears to remain valid code - let proc_res = typecheck_source(config, props, testfile, actual); + 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); @@ -228,13 +229,13 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { if !props.pretty_expanded { return } // additionally, run `--pretty expanded` and try to build it. - let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded"); + 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); } let ProcRes{ stdout: expanded_src, .. } = proc_res; - let proc_res = typecheck_source(config, props, testfile, expanded_src); + 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); @@ -244,15 +245,15 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { fn print_source(config: &Config, props: &TestProps, - testfile: &Path, + testpaths: &TestPaths, src: String, pretty_type: &str) -> ProcRes { - let aux_dir = aux_output_dir_name(config, testfile); + let aux_dir = aux_output_dir_name(config, testpaths); compose_and_run(config, - testfile, + testpaths, make_pp_args(config, props, - testfile, + testpaths, pretty_type.to_owned()), props.exec_env.clone(), &config.compile_lib_path, @@ -262,9 +263,9 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { fn make_pp_args(config: &Config, props: &TestProps, - testfile: &Path, + testpaths: &TestPaths, pretty_type: String) -> ProcArgs { - let aux_dir = aux_output_dir_name(config, testfile); + let aux_dir = aux_output_dir_name(config, testpaths); // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec!("-".to_owned(), "-Zunstable-options".to_owned(), @@ -300,13 +301,13 @@ actual:\n\ } fn typecheck_source(config: &Config, props: &TestProps, - testfile: &Path, src: String) -> ProcRes { - let args = make_typecheck_args(config, props, testfile); - compose_and_run_compiler(config, props, testfile, args, Some(src)) + testpaths: &TestPaths, src: String) -> ProcRes { + let args = make_typecheck_args(config, props, testpaths); + compose_and_run_compiler(config, props, testpaths, args, Some(src)) } - fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> ProcArgs { - let aux_dir = aux_output_dir_name(config, testfile); + fn make_typecheck_args(config: &Config, props: &TestProps, testpaths: &TestPaths) -> ProcArgs { + let aux_dir = aux_output_dir_name(config, testpaths); let target = if props.force_host { &*config.host } else { @@ -330,7 +331,7 @@ actual:\n\ } } -fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { +fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { let mut config = Config { target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags), host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags), @@ -342,16 +343,16 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { commands, check_lines, breakpoint_lines - } = parse_debugger_commands(testfile, "gdb"); + } = parse_debugger_commands(testpaths, "gdb"); let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) - let compiler_run_result = compile_test(config, props, testfile); + let compiler_run_result = compile_test(config, props, testpaths); if !compiler_run_result.status.success() { fatal_proc_rec("compilation failed!", &compiler_run_result); } - let exe_file = make_exe_name(config, testfile); + let exe_file = make_exe_name(config, testpaths); let debugger_run_result; match &*config.target { @@ -369,8 +370,10 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { config.host, config.target)); for line in &breakpoint_lines { script_str.push_str(&format!("break {:?}:{}\n", - testfile.file_name().unwrap() - .to_string_lossy(), + testpaths.file + .file_name() + .unwrap() + .to_string_lossy(), *line)[..]); } script_str.push_str(&cmds); @@ -378,7 +381,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { debug!("script_str = {}", script_str); dump_output_file(config, - testfile, + testpaths, &script_str, "debugger.script"); @@ -441,7 +444,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { None => fatal("cannot find android cross path") }; - let debugger_script = make_out_name(config, testfile, "debugger.script"); + let debugger_script = make_out_name(config, testpaths, "debugger.script"); // FIXME (#9639): This needs to handle non-utf8 paths let debugger_opts = vec!("-quiet".to_owned(), @@ -531,7 +534,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { // Add line breakpoints for line in &breakpoint_lines { script_str.push_str(&format!("break '{}':{}\n", - testfile.file_name().unwrap() + testpaths.file.file_name().unwrap() .to_string_lossy(), *line)); } @@ -541,7 +544,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { debug!("script_str = {}", script_str); dump_output_file(config, - testfile, + testpaths, &script_str, "debugger.script"); @@ -550,7 +553,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { if cfg!(windows) {"gdb.exe"} else {"gdb"} } - let debugger_script = make_out_name(config, testfile, "debugger.script"); + let debugger_script = make_out_name(config, testpaths, "debugger.script"); // FIXME (#9639): This needs to handle non-utf8 paths let debugger_opts = @@ -567,7 +570,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)]; debugger_run_result = compose_and_run(config, - testfile, + testpaths, proc_args, environment, &config.run_lib_path, @@ -596,7 +599,7 @@ fn find_rust_src_root(config: &Config) -> Option { return None; } -fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) { +fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { if config.lldb_python_dir.is_none() { fatal("Can't run LLDB test because LLDB's python path is not set."); } @@ -610,12 +613,12 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) let config = &mut config; // compile test file (it should have 'compile-flags:-g' in the header) - let compile_result = compile_test(config, props, testfile); + let compile_result = compile_test(config, props, testpaths); if !compile_result.status.success() { fatal_proc_rec("compilation failed!", &compile_result); } - let exe_file = make_exe_name(config, testfile); + let exe_file = make_exe_name(config, testpaths); match config.lldb_version { Some(ref version) => { @@ -634,7 +637,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) check_lines, breakpoint_lines, .. - } = parse_debugger_commands(testfile, "lldb"); + } = parse_debugger_commands(testpaths, "lldb"); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running @@ -676,13 +679,14 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) // Write the script into a file debug!("script_str = {}", script_str); dump_output_file(config, - testfile, + testpaths, &script_str, "debugger.script"); - let debugger_script = make_out_name(config, testfile, "debugger.script"); + let debugger_script = make_out_name(config, testpaths, "debugger.script"); // Let LLDB execute the script via lldb_batchmode.py let debugger_run_result = run_lldb(config, + testpaths, &exe_file, &debugger_script, &rust_src_root); @@ -694,6 +698,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) check_debugger_output(&debugger_run_result, &check_lines); fn run_lldb(config: &Config, + testpaths: &TestPaths, test_executable: &Path, debugger_script: &Path, rust_src_root: &Path) @@ -701,7 +706,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py"); cmd2procres(config, - test_executable, + testpaths, Command::new(&config.python) .arg(&lldb_script_path) .arg(test_executable) @@ -711,7 +716,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) } } -fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command) +fn cmd2procres(config: &Config, testpaths: &TestPaths, cmd: &mut Command) -> ProcRes { let (status, out, err) = match cmd.output() { Ok(Output { status, stdout, stderr }) => { @@ -725,7 +730,7 @@ fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command) } }; - dump_output(config, test_executable, &out, &err); + dump_output(config, testpaths, &out, &err); ProcRes { status: Status::Normal(status), stdout: out, @@ -740,7 +745,7 @@ struct DebuggerCommands { breakpoint_lines: Vec, } -fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) +fn parse_debugger_commands(testpaths: &TestPaths, debugger_prefix: &str) -> DebuggerCommands { let command_directive = format!("{}-command", debugger_prefix); let check_directive = format!("{}-check", debugger_prefix); @@ -749,7 +754,7 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) let mut commands = vec!(); let mut check_lines = vec!(); let mut counter = 1; - let reader = BufReader::new(File::open(file_path).unwrap()); + let reader = BufReader::new(File::open(&testpaths.file).unwrap()); for line in reader.lines() { match line { Ok(line) => { @@ -860,11 +865,12 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) } fn check_error_patterns(props: &TestProps, - testfile: &Path, + testpaths: &TestPaths, output_to_check: &str, proc_res: &ProcRes) { if props.error_patterns.is_empty() { - fatal(&format!("no error pattern specified in {:?}", testfile.display())); + fatal(&format!("no error pattern specified in {:?}", + testpaths.file.display())); } let mut next_err_idx = 0; let mut next_err_pat = &props.error_patterns[next_err_idx]; @@ -915,7 +921,7 @@ fn check_forbid_output(props: &TestProps, } fn check_expected_errors(expected_errors: Vec, - testfile: &Path, + testpaths: &TestPaths, proc_res: &ProcRes) { // true if we found the error in question @@ -926,7 +932,7 @@ fn check_expected_errors(expected_errors: Vec, } let prefixes = expected_errors.iter().map(|ee| { - format!("{}:{}:", testfile.display(), ee.line) + format!("{}:{}:", testpaths.file.display(), ee.line) }).collect::>(); let (expect_help, expect_note) = @@ -1142,62 +1148,64 @@ impl fmt::Display for Status { } fn compile_test(config: &Config, props: &TestProps, - testfile: &Path) -> ProcRes { - let aux_dir = aux_output_dir_name(config, testfile); + testpaths: &TestPaths) -> ProcRes { + let aux_dir = aux_output_dir_name(config, testpaths); // FIXME (#9639): This needs to handle non-utf8 paths let link_args = vec!("-L".to_owned(), aux_dir.to_str().unwrap().to_owned()); let args = make_compile_args(config, props, link_args, - |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testfile); - compose_and_run_compiler(config, props, testfile, args, None) + |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testpaths); + compose_and_run_compiler(config, props, testpaths, args, None) } -fn document(config: &Config, props: &TestProps, - testfile: &Path, out_dir: &Path) -> ProcRes { +fn document(config: &Config, + props: &TestProps, + testpaths: &TestPaths, + out_dir: &Path) + -> ProcRes { if props.build_aux_docs { for rel_ab in &props.aux_builds { - let abs_ab = config.aux_base.join(rel_ab); - let aux_props = header::load_props(&abs_ab); - - let auxres = document(config, &aux_props, &abs_ab, out_dir); + let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab); + let aux_props = header::load_props(&aux_testpaths.file); + let auxres = document(config, &aux_props, &aux_testpaths, out_dir); if !auxres.status.success() { return auxres; } } } - let aux_dir = aux_output_dir_name(config, testfile); + let aux_dir = aux_output_dir_name(config, testpaths); let mut args = vec!["-L".to_owned(), aux_dir.to_str().unwrap().to_owned(), "-o".to_owned(), out_dir.to_str().unwrap().to_owned(), - testfile.to_str().unwrap().to_owned()]; + testpaths.file.to_str().unwrap().to_owned()]; args.extend(split_maybe_args(&props.compile_flags)); let args = ProcArgs { prog: config.rustdoc_path.to_str().unwrap().to_owned(), args: args, }; - compose_and_run_compiler(config, props, testfile, args, None) + compose_and_run_compiler(config, props, testpaths, args, None) } fn exec_compiled_test(config: &Config, props: &TestProps, - testfile: &Path) -> ProcRes { + testpaths: &TestPaths) -> ProcRes { let env = props.exec_env.clone(); match &*config.target { "arm-linux-androideabi" | "aarch64-linux-android" => { - _arm_exec_compiled_test(config, props, testfile, env) + _arm_exec_compiled_test(config, props, testpaths, env) } _=> { - let aux_dir = aux_output_dir_name(config, testfile); + let aux_dir = aux_output_dir_name(config, testpaths); compose_and_run(config, - testfile, - make_run_args(config, props, testfile), + testpaths, + make_run_args(config, props, testpaths), env, &config.run_lib_path, Some(aux_dir.to_str().unwrap()), @@ -1207,20 +1215,20 @@ fn exec_compiled_test(config: &Config, props: &TestProps, } fn compose_and_run_compiler(config: &Config, props: &TestProps, - testfile: &Path, args: ProcArgs, + testpaths: &TestPaths, args: ProcArgs, input: Option) -> ProcRes { if !props.aux_builds.is_empty() { - ensure_dir(&aux_output_dir_name(config, testfile)); + ensure_dir(&aux_output_dir_name(config, testpaths)); } - let aux_dir = aux_output_dir_name(config, testfile); + let aux_dir = aux_output_dir_name(config, testpaths); // FIXME (#9639): This needs to handle non-utf8 paths let extra_link_args = vec!["-L".to_owned(), aux_dir.to_str().unwrap().to_owned()]; for rel_ab in &props.aux_builds { - let abs_ab = config.aux_base.join(rel_ab); - let aux_props = header::load_props(&abs_ab); + let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab); + let aux_props = header::load_props(&aux_testpaths.file); let mut crate_type = if aux_props.no_prefer_dynamic { Vec::new() } else { @@ -1247,13 +1255,13 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, &aux_props, crate_type, |a,b| { - let f = make_lib_name(a, b, testfile); + let f = make_lib_name(a, &b.file, testpaths); let parent = f.parent().unwrap(); TargetLocation::ThisDirectory(parent.to_path_buf()) }, - &abs_ab); + &aux_testpaths); let auxres = compose_and_run(config, - &abs_ab, + &aux_testpaths, aux_args, Vec::new(), &config.compile_lib_path, @@ -1262,20 +1270,20 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, if !auxres.status.success() { fatal_proc_rec( &format!("auxiliary build of {:?} failed to compile: ", - abs_ab.display()), + aux_testpaths.file.display()), &auxres); } match &*config.target { "arm-linux-androideabi" | "aarch64-linux-android" => { - _arm_push_aux_shared_library(config, testfile); + _arm_push_aux_shared_library(config, testpaths); } _ => {} } } compose_and_run(config, - testfile, + testpaths, args, Vec::new(), &config.compile_lib_path, @@ -1285,16 +1293,17 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, fn ensure_dir(path: &Path) { if path.is_dir() { return; } - fs::create_dir(path).unwrap(); + fs::create_dir_all(path).unwrap(); } -fn compose_and_run(config: &Config, testfile: &Path, +fn compose_and_run(config: &Config, + testpaths: &TestPaths, ProcArgs{ args, prog }: ProcArgs, procenv: Vec<(String, String)> , lib_path: &str, aux_path: Option<&str>, input: Option) -> ProcRes { - return program_output(config, testfile, lib_path, + return program_output(config, testpaths, lib_path, prog, aux_path, args, procenv, input); } @@ -1307,18 +1316,18 @@ fn make_compile_args(config: &Config, props: &TestProps, extras: Vec , xform: F, - testfile: &Path) + testpaths: &TestPaths) -> ProcArgs where - F: FnOnce(&Config, &Path) -> TargetLocation, + F: FnOnce(&Config, &TestPaths) -> TargetLocation, { - let xform_file = xform(config, testfile); + let xform_file = xform(config, testpaths); let target = if props.force_host { &*config.host } else { &*config.target }; // FIXME (#9639): This needs to handle non-utf8 paths - let mut args = vec!(testfile.to_str().unwrap().to_owned(), + let mut args = vec!(testpaths.file.to_str().unwrap().to_owned(), "-L".to_owned(), config.build_base.to_str().unwrap().to_owned(), format!("--target={}", target)); @@ -1350,15 +1359,15 @@ fn make_compile_args(config: &Config, }; } -fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> PathBuf { +fn make_lib_name(config: &Config, auxfile: &Path, testpaths: &TestPaths) -> PathBuf { // what we return here is not particularly important, as it // happens; rustc ignores everything except for the directory. let auxname = output_testname(auxfile); - aux_output_dir_name(config, testfile).join(&auxname) + aux_output_dir_name(config, testpaths).join(&auxname) } -fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf { - let mut f = output_base_name(config, testfile); +fn make_exe_name(config: &Config, testpaths: &TestPaths) -> PathBuf { + let mut f = output_base_name(config, testpaths); // FIXME: This is using the host architecture exe suffix, not target! if config.target == "asmjs-unknown-emscripten" { let mut fname = f.file_name().unwrap().to_os_string(); @@ -1372,7 +1381,7 @@ fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf { f } -fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) +fn make_run_args(config: &Config, props: &TestProps, testpaths: &TestPaths) -> ProcArgs { // If we've got another tool to run under (valgrind), // then split apart its command @@ -1383,7 +1392,7 @@ fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) args.push("nodejs".to_owned()); } - let exe_file = make_exe_name(config, testfile); + let exe_file = make_exe_name(config, testpaths); // FIXME (#9639): This needs to handle non-utf8 paths args.push(exe_file.to_str().unwrap().to_owned()); @@ -1415,7 +1424,7 @@ fn split_maybe_args(argstr: &Option) -> Vec { } } -fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: String, +fn program_output(config: &Config, testpaths: &TestPaths, lib_path: &str, prog: String, aux_path: Option<&str>, args: Vec, env: Vec<(String, String)>, input: Option) -> ProcRes { @@ -1437,7 +1446,7 @@ fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: String &args, env, input).expect(&format!("failed to exec `{}`", prog)); - dump_output(config, testfile, &out, &err); + dump_output(config, testpaths, &out, &err); return ProcRes { status: Status::Normal(status), stdout: out, @@ -1463,31 +1472,33 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { } } -fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) { - dump_output_file(config, testfile, out, "out"); - dump_output_file(config, testfile, err, "err"); +fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) { + dump_output_file(config, testpaths, out, "out"); + dump_output_file(config, testpaths, err, "err"); maybe_dump_to_stdout(config, out, err); } -fn dump_output_file(config: &Config, testfile: &Path, - out: &str, extension: &str) { - let outfile = make_out_name(config, testfile, extension); +fn dump_output_file(config: &Config, + testpaths: &TestPaths, + out: &str, + extension: &str) { + let outfile = make_out_name(config, testpaths, extension); File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap(); } -fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> PathBuf { - output_base_name(config, testfile).with_extension(extension) +fn make_out_name(config: &Config, testpaths: &TestPaths, extension: &str) -> PathBuf { + output_base_name(config, testpaths).with_extension(extension) } -fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf { - let f = output_base_name(config, testfile); +fn aux_output_dir_name(config: &Config, testpaths: &TestPaths) -> PathBuf { + let f = output_base_name(config, testpaths); let mut fname = f.file_name().unwrap().to_os_string(); fname.push(&format!(".{}.libaux", config.mode)); f.with_file_name(&fname) } -fn output_testname(testfile: &Path) -> PathBuf { - PathBuf::from(testfile.file_stem().unwrap()) +fn output_testname(filepath: &Path) -> PathBuf { + PathBuf::from(filepath.file_stem().unwrap()) } fn output_base_name(config: &Config, testfile: &Path) -> PathBuf { @@ -1531,10 +1542,10 @@ stderr:\n\ fn _arm_exec_compiled_test(config: &Config, props: &TestProps, - testfile: &Path, + testpaths: &TestPaths, env: Vec<(String, String)>) -> ProcRes { - let args = make_run_args(config, props, testfile); + let args = make_run_args(config, props, testpaths); let cmdline = make_cmdline("", &args.prog, &args.args); @@ -1645,7 +1656,7 @@ fn _arm_exec_compiled_test(config: &Config, .expect(&format!("failed to exec `{}`", config.adb_path)); dump_output(config, - testfile, + testpaths, &stdout_out, &stderr_out); @@ -1657,8 +1668,8 @@ fn _arm_exec_compiled_test(config: &Config, } } -fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) { - let tdir = aux_output_dir_name(config, testfile); +fn _arm_push_aux_shared_library(config: &Config, testpaths: &TestPaths) { + let tdir = aux_output_dir_name(config, testpaths); let dirs = fs::read_dir(&tdir).unwrap(); for file in dirs { @@ -1692,8 +1703,8 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) { // codegen tests (using FileCheck) fn compile_test_and_save_ir(config: &Config, props: &TestProps, - testfile: &Path) -> ProcRes { - let aux_dir = aux_output_dir_name(config, testfile); + testpaths: &TestPaths) -> ProcRes { + let aux_dir = aux_output_dir_name(config, testpaths); // FIXME (#9639): This needs to handle non-utf8 paths let mut link_args = vec!("-L".to_owned(), aux_dir.to_str().unwrap().to_owned()); @@ -1705,34 +1716,34 @@ fn compile_test_and_save_ir(config: &Config, props: &TestProps, |a, b| TargetLocation::ThisDirectory( output_base_name(a, b).parent() .unwrap().to_path_buf()), - testfile); - compose_and_run_compiler(config, props, testfile, args, None) + testpaths); + compose_and_run_compiler(config, props, testpaths, args, None) } -fn check_ir_with_filecheck(config: &Config, testfile: &Path) -> ProcRes { - let irfile = output_base_name(config, testfile).with_extension("ll"); +fn check_ir_with_filecheck(config: &Config, testpaths: &TestPaths) -> ProcRes { + let irfile = output_base_name(config, testpaths).with_extension("ll"); let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck"); let proc_args = ProcArgs { // FIXME (#9639): This needs to handle non-utf8 paths prog: prog.to_str().unwrap().to_owned(), args: vec!(format!("-input-file={}", irfile.to_str().unwrap()), - testfile.to_str().unwrap().to_owned()) + testpaths.file.to_str().unwrap().to_owned()) }; - compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None) + compose_and_run(config, testpaths, proc_args, Vec::new(), "", None, None) } -fn run_codegen_test(config: &Config, props: &TestProps, testfile: &Path) { +fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { if config.llvm_bin_path.is_none() { fatal("missing --llvm-bin-path"); } - let mut proc_res = compile_test_and_save_ir(config, props, testfile); + let mut proc_res = compile_test_and_save_ir(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("compilation failed!", &proc_res); } - proc_res = check_ir_with_filecheck(config, testfile); + proc_res = check_ir_with_filecheck(config, testpaths); if !proc_res.status.success() { fatal_proc_rec("verification with 'FileCheck' failed", &proc_res); @@ -1750,30 +1761,30 @@ fn charset() -> &'static str { } } -fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) { - let out_dir = output_base_name(config, testfile); +fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + 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, testfile, &out_dir); + let proc_res = document(config, props, testpaths, &out_dir); if !proc_res.status.success() { fatal_proc_rec("rustdoc failed!", &proc_res); } let root = find_rust_src_root(config).unwrap(); let res = cmd2procres(config, - testfile, + testpaths, Command::new(&config.python) .arg(root.join("src/etc/htmldocck.py")) .arg(out_dir) - .arg(testfile)); + .arg(&testpaths.file)); if !res.status.success() { fatal_proc_rec("htmldocck failed!", &res); } } -fn run_codegen_units_test(config: &Config, props: &TestProps, testfile: &Path) { - let proc_res = compile_test(config, props, testfile); +fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + let proc_res = compile_test(config, props, testpaths); if !proc_res.status.success() { fatal_proc_rec("compilation failed!", &proc_res); @@ -1790,7 +1801,7 @@ fn run_codegen_units_test(config: &Config, props: &TestProps, testfile: &Path) { .map(|s| (&s[prefix.len()..]).to_string()) .collect(); - let expected: HashSet = errors::load_errors(testfile) + let expected: HashSet = errors::load_errors(&testpaths.file) .iter() .map(|e| e.msg.trim().to_string()) .collect(); diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 5693cc10a0f7..e82451937d39 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -203,7 +203,12 @@ pub struct TestDesc { pub should_panic: ShouldPanic, } -unsafe impl Send for TestDesc {} +#[derive(Clone)] +pub struct TestPaths { + pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs + pub base: PathBuf, // e.g., compile-test, auxiliary + pub relative_dir: PathBuf, // e.g., foo/bar +} #[derive(Debug)] pub struct TestDescAndFn {