1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #[crate_type = "bin"];
14 #[allow(non_camel_case_types)];
15 #[allow(deprecated_owned_vector)]; // NOTE: remove after stage0
20 #[phase(link, syntax)]
26 use getopts::{optopt, optflag, reqopt};
28 use common::mode_run_pass;
29 use common::mode_run_fail;
30 use common::mode_compile_fail;
31 use common::mode_pretty;
32 use common::mode_debug_info;
33 use common::mode_codegen;
45 let args = os::args();
46 let config = parse_config(args.move_iter().collect());
51 pub fn parse_config(args: Vec<~str> ) -> config {
53 let groups : Vec<getopts::OptGroup> =
54 vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
55 reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
56 reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
57 optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
58 optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
59 reqopt("", "src-base", "directory to scan for test files", "PATH"),
60 reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
61 reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
62 reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
63 reqopt("", "mode", "which sort of compile tests to run",
64 "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
65 optflag("", "ignored", "run tests marked as ignored"),
66 optopt("", "runtool", "supervisor program to run tests under \
67 (eg. emulator, valgrind)", "PROGRAM"),
68 optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
69 optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
70 optflag("", "verbose", "run tests verbosely, showing all output"),
71 optopt("", "logfile", "file to log test execution to", "FILE"),
72 optopt("", "save-metrics", "file to save metrics to", "FILE"),
73 optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
74 optopt("", "ratchet-noise-percent",
75 "percent change in metrics to consider noise", "N"),
76 optflag("", "jit", "run tests under the JIT"),
77 optopt("", "target", "the target to build for", "TARGET"),
78 optopt("", "host", "the host to build for", "HOST"),
79 optopt("", "adb-path", "path to the android debugger", "PATH"),
80 optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
81 optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
82 optflag("h", "help", "show this message"));
84 assert!(!args.is_empty());
85 let argv0 = (*args.get(0)).clone();
86 let args_ = args.tail();
87 if *args.get(1) == ~"-h" || *args.get(1) == ~"--help" {
88 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
89 println!("{}", getopts::usage(message, groups.as_slice()));
95 &match getopts::getopts(args_, groups.as_slice()) {
97 Err(f) => fail!("{}", f.to_err_msg())
100 if matches.opt_present("h") || matches.opt_present("help") {
101 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
102 println!("{}", getopts::usage(message, groups.as_slice()));
107 fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
108 Path::new(m.opt_str(nm).unwrap())
112 compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
113 run_lib_path: matches.opt_str("run-lib-path").unwrap(),
114 rustc_path: opt_path(matches, "rustc-path"),
115 clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
116 llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
117 src_base: opt_path(matches, "src-base"),
118 build_base: opt_path(matches, "build-base"),
119 aux_base: opt_path(matches, "aux-base"),
120 stage_id: matches.opt_str("stage-id").unwrap(),
121 mode: str_mode(matches.opt_str("mode").unwrap()),
122 run_ignored: matches.opt_present("ignored"),
124 if !matches.free.is_empty() {
125 Some((*matches.free.get(0)).clone())
129 logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
130 save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
132 matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
133 ratchet_noise_percent:
134 matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
135 runtool: matches.opt_str("runtool"),
136 host_rustcflags: matches.opt_str("host-rustcflags"),
137 target_rustcflags: matches.opt_str("target-rustcflags"),
138 jit: matches.opt_present("jit"),
139 target: opt_str2(matches.opt_str("target")).to_str(),
140 host: opt_str2(matches.opt_str("host")).to_str(),
141 adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
143 opt_str2(matches.opt_str("adb-test-dir")).to_str(),
145 "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
146 "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
147 !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
148 test_shard: test::opt_shard(matches.opt_str("test-shard")),
149 verbose: matches.opt_present("verbose")
153 pub fn log_config(config: &config) {
155 logv(c, format!("configuration:"));
156 logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
157 logv(c, format!("run_lib_path: {}", config.run_lib_path));
158 logv(c, format!("rustc_path: {}", config.rustc_path.display()));
159 logv(c, format!("src_base: {}", config.src_base.display()));
160 logv(c, format!("build_base: {}", config.build_base.display()));
161 logv(c, format!("stage_id: {}", config.stage_id));
162 logv(c, format!("mode: {}", mode_str(config.mode)));
163 logv(c, format!("run_ignored: {}", config.run_ignored));
164 logv(c, format!("filter: {}", opt_str(&config.filter)));
165 logv(c, format!("runtool: {}", opt_str(&config.runtool)));
166 logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
167 logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
168 logv(c, format!("jit: {}", config.jit));
169 logv(c, format!("target: {}", config.target));
170 logv(c, format!("host: {}", config.host));
171 logv(c, format!("adb_path: {}", config.adb_path));
172 logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
173 logv(c, format!("adb_device_status: {}", config.adb_device_status));
174 match config.test_shard {
175 None => logv(c, ~"test_shard: (all)"),
176 Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
178 logv(c, format!("verbose: {}", config.verbose));
179 logv(c, format!("\n"));
182 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
192 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
193 match maybestr { None => ~"(none)", Some(s) => { s } }
196 pub fn str_mode(s: ~str) -> mode {
198 "compile-fail" => mode_compile_fail,
199 "run-fail" => mode_run_fail,
200 "run-pass" => mode_run_pass,
201 "pretty" => mode_pretty,
202 "debug-info" => mode_debug_info,
203 "codegen" => mode_codegen,
204 _ => fail!("invalid mode")
208 pub fn mode_str(mode: mode) -> ~str {
210 mode_compile_fail => ~"compile-fail",
211 mode_run_fail => ~"run-fail",
212 mode_run_pass => ~"run-pass",
213 mode_pretty => ~"pretty",
214 mode_debug_info => ~"debug-info",
215 mode_codegen => ~"codegen",
219 pub fn run_tests(config: &config) {
220 if config.target == ~"arm-linux-androideabi" {
223 println!("arm-linux-androideabi debug-info \
224 test uses tcp 5039 port. please reserve it");
229 //arm-linux-androideabi debug-info test uses remote debugger
230 //so, we test 1 task at once.
231 // also trying to isolate problems with adb_run_wrapper.sh ilooping
232 os::setenv("RUST_TEST_TASKS","1");
235 let opts = test_opts(config);
236 let tests = make_tests(config);
237 // sadly osx needs some file descriptor limits raised for running tests in
238 // parallel (especially when we have lots and lots of child processes).
239 // For context, see #8904
240 io::test::raise_fd_limit();
241 let res = test::run_tests_console(&opts, tests.move_iter().collect());
244 Ok(false) => fail!("Some tests failed"),
246 println!("I/O failure during tests: {}", e);
251 pub fn test_opts(config: &config) -> test::TestOpts {
253 filter: config.filter.clone(),
254 run_ignored: config.run_ignored,
255 logfile: config.logfile.clone(),
257 run_benchmarks: true,
258 ratchet_metrics: config.ratchet_metrics.clone(),
259 ratchet_noise_percent: config.ratchet_noise_percent.clone(),
260 save_metrics: config.save_metrics.clone(),
261 test_shard: config.test_shard.clone()
265 pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
266 debug!("making tests from {}",
267 config.src_base.display());
268 let mut tests = Vec::new();
269 let dirs = fs::readdir(&config.src_base).unwrap();
270 for file in dirs.iter() {
271 let file = file.clone();
272 debug!("inspecting file {}", file.display());
273 if is_test(config, &file) {
274 let t = make_test(config, &file, || {
276 mode_codegen => make_metrics_test_closure(config, &file),
277 _ => make_test_closure(config, &file)
286 pub fn is_test(config: &config, testfile: &Path) -> bool {
287 // Pretty-printer does not work with .rc files yet
288 let valid_extensions =
290 mode_pretty => vec!(~".rs"),
291 _ => vec!(~".rc", ~".rs")
293 let invalid_prefixes = vec!(~".", ~"#", ~"~");
294 let name = testfile.filename_str().unwrap();
296 let mut valid = false;
298 for ext in valid_extensions.iter() {
299 if name.ends_with(*ext) { valid = true; }
302 for pre in invalid_prefixes.iter() {
303 if name.starts_with(*pre) { valid = false; }
309 pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
310 -> test::TestDescAndFn {
311 test::TestDescAndFn {
312 desc: test::TestDesc {
313 name: make_test_name(config, testfile),
314 ignore: header::is_test_ignored(config, testfile),
321 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
323 // Try to elide redundant long paths
324 fn shorten(path: &Path) -> ~str {
325 let filename = path.filename_str();
326 let p = path.dir_path();
327 let dir = p.filename_str();
328 format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
331 test::DynTestName(format!("[{}] {}",
332 mode_str(config.mode),
336 pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
337 let config = (*config).clone();
338 // FIXME (#9639): This needs to handle non-utf8 paths
339 let testfile = testfile.as_str().unwrap().to_owned();
340 test::DynTestFn(proc() { runtest::run(config, testfile) })
343 pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
344 let config = (*config).clone();
345 // FIXME (#9639): This needs to handle non-utf8 paths
346 let testfile = testfile.as_str().unwrap().to_owned();
347 test::DynMetricFn(proc(mm) {
348 runtest::run_metrics(config, testfile, mm)