Auto merge of #31749 - nikomatsakis:compiletest-subdir, r=alexcrichton

You can now group tests into directories like `run-pass/borrowck` or `compile-fail/borrowck`. By default, all `.rs` files within any directory are considered tests: to ignore some directory, create a placeholder file called `compiletest-ignore-dir` (I had to do this for several existing directories).

r? @alexcrichton
cc @brson
This commit is contained in:
bors 2016-02-26 00:53:38 +00:00
commit 15e9a95a4b
171 changed files with 283 additions and 201 deletions

View File

@ -458,21 +458,22 @@ $(foreach host,$(CFG_HOST), \
# Rules for the compiletest tests (rpass, rfail, etc.)
######################################################################
RPASS_RS := $(wildcard $(S)src/test/run-pass/*.rs)
RPASS_VALGRIND_RS := $(wildcard $(S)src/test/run-pass-valgrind/*.rs)
RPASS_FULL_RS := $(wildcard $(S)src/test/run-pass-fulldeps/*.rs)
RFAIL_FULL_RS := $(wildcard $(S)src/test/run-fail-fulldeps/*.rs)
CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
PFAIL_RS := $(wildcard $(S)src/test/parse-fail/*.rs)
PRETTY_RS := $(wildcard $(S)src/test/pretty/*.rs)
DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
CODEGEN_UNITS_RS := $(wildcard $(S)src/test/codegen-units/*.rs)
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
RPASS_RS := $(call rwildcard,$(S)src/test/run-pass/,*.rs)
RPASS_VALGRIND_RS := $(call rwildcard,$(S)src/test/run-pass-valgrind/,*.rs)
RPASS_FULL_RS := $(call rwildcard,$(S)src/test/run-pass-fulldeps/,*.rs)
RFAIL_FULL_RS := $(call rwildcard,$(S)src/test/run-fail-fulldeps/,*.rs)
CFAIL_FULL_RS := $(call rwildcard,$(S)src/test/compile-fail-fulldeps/,*.rs)
RFAIL_RS := $(call rwildcard,$(S)src/test/run-fail/,*.rs)
RFAIL_RS := $(call rwildcard,$(S)src/test/run-fail/,*.rs)
CFAIL_RS := $(call rwildcard,$(S)src/test/compile-fail/,*.rs)
PFAIL_RS := $(call rwildcard,$(S)src/test/parse-fail/,*.rs)
PRETTY_RS := $(call rwildcard,$(S)src/test/pretty/,*.rs)
DEBUGINFO_GDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs)
DEBUGINFO_LLDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs)
CODEGEN_RS := $(call rwildcard,$(S)src/test/codegen/,*.rs)
CODEGEN_CC := $(call rwildcard,$(S)src/test/codegen/,*.cc)
CODEGEN_UNITS_RS := $(call rwildcard,$(S)src/test/codegen-units/,*.rs)
RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs)
RPASS_TESTS := $(RPASS_RS)
RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)

View File

@ -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,61 @@ pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
debug!("making tests from {:?}",
config.src_base.display());
let mut tests = Vec::new();
let dirs = fs::read_dir(&config.src_base).unwrap();
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))
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<test::TestDescAndFn>)
-> io::Result<()> {
// Ignore directories that contain a file
// `compiletest-ignore-dir`.
for file in try!(fs::read_dir(dir)) {
let file = try!(file);
if file.file_name() == *"compiletest-ignore-dir" {
return Ok(());
}
}
tests
let dirs = try!(fs::read_dir(dir));
for file in dirs {
let file = try!(file);
let file_path = file.path();
debug!("inspecting file {:?}", file_path.display());
if is_test(config, &file_path) {
// If we find a test foo/bar.rs, we have to build the
// output directory `$build/foo` so we can write
// `$build/foo/bar` into it. We do this *now* in this
// sequential loop because otherwise, if we do it in the
// tests themselves, they race for the privilege of
// creating the directories and sometimes fail randomly.
let build_dir = config.build_base.join(&relative_dir_path);
fs::create_dir_all(&build_dir).unwrap();
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))
} else if file_path.is_dir() {
let relative_file_path = relative_dir_path.join(file.file_name());
try!(collect_tests_from_dir(config,
base,
&file_path,
&relative_file_path,
tests));
}
}
Ok(())
}
pub fn is_test(config: &Config, testfile: &Path) -> bool {
@ -305,36 +353,33 @@ 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),
}
}
pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
// Try to elide redundant long paths
fn shorten(path: &Path) -> String {
let filename = path.file_name().unwrap().to_str();
let p = path.parent().unwrap();
let dir = p.file_name().unwrap().to_str();
format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
}
test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName {
// Convert a complete path to something like
//
// run-pass/foo/bar/baz.rs
let path =
PathBuf::from(config.mode.to_string())
.join(&testpaths.relative_dir)
.join(&testpaths.file.file_name().unwrap());
test::DynTestName(format!("[{}] {}", config.mode, path.display()))
}
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)
}))
}

View File

@ -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<PathBuf> {
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<usize>,
}
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<errors::ExpectedError>,
testfile: &Path,
testpaths: &TestPaths,
proc_res: &ProcRes) {
// true if we found the error in question
@ -926,7 +932,9 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
}
let prefixes = expected_errors.iter().map(|ee| {
format!("{}:{}:", testfile.display(), ee.line)
let expected = format!("{}:{}:", testpaths.file.display(), ee.line);
// On windows just translate all '\' path separators to '/'
expected.replace(r"\", "/")
}).collect::<Vec<String>>();
let (expect_help, expect_note) =
@ -1142,62 +1150,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()),
@ -1206,21 +1216,36 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
}
}
fn compute_aux_test_paths(config: &Config,
testpaths: &TestPaths,
rel_ab: &str)
-> TestPaths
{
let abs_ab = config.aux_base.join(rel_ab);
TestPaths {
file: abs_ab,
base: testpaths.base.clone(),
relative_dir: Path::new(rel_ab).parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| PathBuf::new())
}
}
fn compose_and_run_compiler(config: &Config, props: &TestProps,
testfile: &Path, args: ProcArgs,
testpaths: &TestPaths, args: ProcArgs,
input: Option<String>) -> 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 +1272,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 +1287,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 +1310,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<String>) -> ProcRes {
return program_output(config, testfile, lib_path,
return program_output(config, testpaths, lib_path,
prog, aux_path, args, procenv, input);
}
@ -1307,18 +1333,18 @@ fn make_compile_args<F>(config: &Config,
props: &TestProps,
extras: Vec<String> ,
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 +1376,15 @@ fn make_compile_args<F>(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 +1398,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 +1409,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 +1441,7 @@ fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
}
}
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<String>,
env: Vec<(String, String)>,
input: Option<String>) -> ProcRes {
@ -1437,7 +1463,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,36 +1489,41 @@ 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 {
config.build_base
.join(&output_testname(testfile))
fn output_base_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
let dir = config.build_base.join(&testpaths.relative_dir);
// Note: The directory `dir` is created during `collect_tests_from_dir`
dir
.join(&output_testname(&testpaths.file))
.with_extension(&config.stage_id)
}
@ -1531,10 +1562,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 +1676,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 +1688,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 +1723,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 +1736,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 +1781,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 +1821,7 @@ fn run_codegen_units_test(config: &Config, props: &TestProps, testfile: &Path) {
.map(|s| (&s[prefix.len()..]).to_string())
.collect();
let expected: HashSet<String> = errors::load_errors(testfile)
let expected: HashSet<String> = errors::load_errors(&testpaths.file)
.iter()
.map(|e| e.msg.trim().to_string())
.collect();

View File

@ -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 {

Some files were not shown because too many files have changed in this diff Show More