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)];
19 #[phase(link, syntax)]
27 use getopts::{optopt, optflag, reqopt};
29 use common::mode_run_pass;
30 use common::mode_run_fail;
31 use common::mode_compile_fail;
32 use common::mode_pretty;
33 use common::mode_debug_info;
34 use common::mode_codegen;
46 fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }
49 let args = os::args();
50 let config = parse_config(args.move_iter().collect());
55 pub fn parse_config(args: Vec<~str> ) -> config {
57 let groups : Vec<getopts::OptGroup> =
58 vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
59 reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
60 reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
61 optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
62 optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
63 reqopt("", "src-base", "directory to scan for test files", "PATH"),
64 reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
65 reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
66 reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
67 reqopt("", "mode", "which sort of compile tests to run",
68 "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
69 optflag("", "ignored", "run tests marked as ignored"),
70 optopt("", "runtool", "supervisor program to run tests under \
71 (eg. emulator, valgrind)", "PROGRAM"),
72 optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
73 optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
74 optflag("", "verbose", "run tests verbosely, showing all output"),
75 optopt("", "logfile", "file to log test execution to", "FILE"),
76 optopt("", "save-metrics", "file to save metrics to", "FILE"),
77 optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
78 optopt("", "ratchet-noise-percent",
79 "percent change in metrics to consider noise", "N"),
80 optflag("", "jit", "run tests under the JIT"),
81 optopt("", "target", "the target to build for", "TARGET"),
82 optopt("", "host", "the host to build for", "HOST"),
83 optopt("", "adb-path", "path to the android debugger", "PATH"),
84 optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
85 optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
86 optflag("h", "help", "show this message"));
88 assert!(!args.is_empty());
89 let argv0 = (*args.get(0)).clone();
90 let args_ = args.tail();
91 if *args.get(1) == ~"-h" || *args.get(1) == ~"--help" {
92 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
93 println!("{}", getopts::usage(message, groups.as_slice()));
99 &match getopts::getopts(args_, groups.as_slice()) {
101 Err(f) => fail!("{}", f.to_err_msg())
104 if matches.opt_present("h") || matches.opt_present("help") {
105 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
106 println!("{}", getopts::usage(message, groups.as_slice()));
111 fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
112 Path::new(m.opt_str(nm).unwrap())
116 compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
117 run_lib_path: matches.opt_str("run-lib-path").unwrap(),
118 rustc_path: opt_path(matches, "rustc-path"),
119 clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
120 llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
121 src_base: opt_path(matches, "src-base"),
122 build_base: opt_path(matches, "build-base"),
123 aux_base: opt_path(matches, "aux-base"),
124 stage_id: matches.opt_str("stage-id").unwrap(),
125 mode: str_mode(matches.opt_str("mode").unwrap()),
126 run_ignored: matches.opt_present("ignored"),
128 if !matches.free.is_empty() {
129 Some((*matches.free.get(0)).clone())
133 logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
134 save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
136 matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
137 ratchet_noise_percent:
138 matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
139 runtool: matches.opt_str("runtool"),
140 host_rustcflags: matches.opt_str("host-rustcflags"),
141 target_rustcflags: matches.opt_str("target-rustcflags"),
142 jit: matches.opt_present("jit"),
143 target: opt_str2(matches.opt_str("target")).to_str(),
144 host: opt_str2(matches.opt_str("host")).to_str(),
145 adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
147 opt_str2(matches.opt_str("adb-test-dir")).to_str(),
149 "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
150 "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
151 !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
152 test_shard: test::opt_shard(matches.opt_str("test-shard")),
153 verbose: matches.opt_present("verbose")
157 pub fn log_config(config: &config) {
159 logv(c, format!("configuration:"));
160 logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
161 logv(c, format!("run_lib_path: {}", config.run_lib_path));
162 logv(c, format!("rustc_path: {}", config.rustc_path.display()));
163 logv(c, format!("src_base: {}", config.src_base.display()));
164 logv(c, format!("build_base: {}", config.build_base.display()));
165 logv(c, format!("stage_id: {}", config.stage_id));
166 logv(c, format!("mode: {}", mode_str(config.mode)));
167 logv(c, format!("run_ignored: {}", config.run_ignored));
168 logv(c, format!("filter: {}", opt_str(&config.filter)));
169 logv(c, format!("runtool: {}", opt_str(&config.runtool)));
170 logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
171 logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
172 logv(c, format!("jit: {}", config.jit));
173 logv(c, format!("target: {}", config.target));
174 logv(c, format!("host: {}", config.host));
175 logv(c, format!("adb_path: {}", config.adb_path));
176 logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
177 logv(c, format!("adb_device_status: {}", config.adb_device_status));
178 match config.test_shard {
179 None => logv(c, ~"test_shard: (all)"),
180 Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
182 logv(c, format!("verbose: {}", config.verbose));
183 logv(c, format!("\n"));
186 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
196 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
197 match maybestr { None => ~"(none)", Some(s) => { s } }
200 pub fn str_mode(s: ~str) -> mode {
202 "compile-fail" => mode_compile_fail,
203 "run-fail" => mode_run_fail,
204 "run-pass" => mode_run_pass,
205 "pretty" => mode_pretty,
206 "debug-info" => mode_debug_info,
207 "codegen" => mode_codegen,
208 _ => fail!("invalid mode")
212 pub fn mode_str(mode: mode) -> ~str {
214 mode_compile_fail => ~"compile-fail",
215 mode_run_fail => ~"run-fail",
216 mode_run_pass => ~"run-pass",
217 mode_pretty => ~"pretty",
218 mode_debug_info => ~"debug-info",
219 mode_codegen => ~"codegen",
223 pub fn run_tests(config: &config) {
224 if config.target == ~"arm-linux-androideabi" {
227 println!("arm-linux-androideabi debug-info \
228 test uses tcp 5039 port. please reserve it");
233 //arm-linux-androideabi debug-info test uses remote debugger
234 //so, we test 1 task at once.
235 // also trying to isolate problems with adb_run_wrapper.sh ilooping
236 os::setenv("RUST_TEST_TASKS","1");
239 let opts = test_opts(config);
240 let tests = make_tests(config);
241 // sadly osx needs some file descriptor limits raised for running tests in
242 // parallel (especially when we have lots and lots of child processes).
243 // For context, see #8904
244 io::test::raise_fd_limit();
245 let res = test::run_tests_console(&opts, tests.move_iter().collect());
248 Ok(false) => fail!("Some tests failed"),
250 println!("I/O failure during tests: {}", e);
255 pub fn test_opts(config: &config) -> test::TestOpts {
257 filter: config.filter.clone(),
258 run_ignored: config.run_ignored,
259 logfile: config.logfile.clone(),
261 run_benchmarks: true,
262 ratchet_metrics: config.ratchet_metrics.clone(),
263 ratchet_noise_percent: config.ratchet_noise_percent.clone(),
264 save_metrics: config.save_metrics.clone(),
265 test_shard: config.test_shard.clone()
269 pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
270 debug!("making tests from {}",
271 config.src_base.display());
272 let mut tests = Vec::new();
273 let dirs = fs::readdir(&config.src_base).unwrap();
274 for file in dirs.iter() {
275 let file = file.clone();
276 debug!("inspecting file {}", file.display());
277 if is_test(config, &file) {
278 let t = make_test(config, &file, || {
280 mode_codegen => make_metrics_test_closure(config, &file),
281 _ => make_test_closure(config, &file)
290 pub fn is_test(config: &config, testfile: &Path) -> bool {
291 // Pretty-printer does not work with .rc files yet
292 let valid_extensions =
294 mode_pretty => vec!(~".rs"),
295 _ => vec!(~".rc", ~".rs")
297 let invalid_prefixes = vec!(~".", ~"#", ~"~");
298 let name = testfile.filename_str().unwrap();
300 let mut valid = false;
302 for ext in valid_extensions.iter() {
303 if name.ends_with(*ext) { valid = true; }
306 for pre in invalid_prefixes.iter() {
307 if name.starts_with(*pre) { valid = false; }
313 pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
314 -> test::TestDescAndFn {
315 test::TestDescAndFn {
316 desc: test::TestDesc {
317 name: make_test_name(config, testfile),
318 ignore: header::is_test_ignored(config, testfile),
325 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
327 // Try to elide redundant long paths
328 fn shorten(path: &Path) -> ~str {
329 let filename = path.filename_str();
330 let p = path.dir_path();
331 let dir = p.filename_str();
332 format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
335 test::DynTestName(format!("[{}] {}",
336 mode_str(config.mode),
340 pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
341 let config = (*config).clone();
342 // FIXME (#9639): This needs to handle non-utf8 paths
343 let testfile = testfile.as_str().unwrap().to_owned();
344 test::DynTestFn(proc() { runtest::run(config, testfile) })
347 pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
348 let config = (*config).clone();
349 // FIXME (#9639): This needs to handle non-utf8 paths
350 let testfile = testfile.as_str().unwrap().to_owned();
351 test::DynMetricFn(proc(mm) {
352 runtest::run_metrics(config, testfile, mm)