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 {
47 green::start(argc, argv, rustuv::event_loop, main)
51 let args = os::args();
52 let config = parse_config(args.move_iter().collect());
57 pub fn parse_config(args: Vec<~str> ) -> config {
59 let groups : Vec<getopts::OptGroup> =
60 vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
61 reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
62 reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
63 optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
64 optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
65 reqopt("", "src-base", "directory to scan for test files", "PATH"),
66 reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
67 reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
68 reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
69 reqopt("", "mode", "which sort of compile tests to run",
70 "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
71 optflag("", "ignored", "run tests marked as ignored"),
72 optopt("", "runtool", "supervisor program to run tests under \
73 (eg. emulator, valgrind)", "PROGRAM"),
74 optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
75 optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
76 optflag("", "verbose", "run tests verbosely, showing all output"),
77 optopt("", "logfile", "file to log test execution to", "FILE"),
78 optopt("", "save-metrics", "file to save metrics to", "FILE"),
79 optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
80 optopt("", "ratchet-noise-percent",
81 "percent change in metrics to consider noise", "N"),
82 optflag("", "jit", "run tests under the JIT"),
83 optopt("", "target", "the target to build for", "TARGET"),
84 optopt("", "host", "the host to build for", "HOST"),
85 optopt("", "adb-path", "path to the android debugger", "PATH"),
86 optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
87 optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
88 optflag("h", "help", "show this message"));
90 assert!(!args.is_empty());
91 let argv0 = (*args.get(0)).clone();
92 let args_ = args.tail();
93 if *args.get(1) == ~"-h" || *args.get(1) == ~"--help" {
94 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
95 println!("{}", getopts::usage(message, groups.as_slice()));
101 &match getopts::getopts(args_, groups.as_slice()) {
103 Err(f) => fail!("{}", f.to_err_msg())
106 if matches.opt_present("h") || matches.opt_present("help") {
107 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
108 println!("{}", getopts::usage(message, groups.as_slice()));
113 fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
114 Path::new(m.opt_str(nm).unwrap())
118 compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
119 run_lib_path: matches.opt_str("run-lib-path").unwrap(),
120 rustc_path: opt_path(matches, "rustc-path"),
121 clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
122 llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
123 src_base: opt_path(matches, "src-base"),
124 build_base: opt_path(matches, "build-base"),
125 aux_base: opt_path(matches, "aux-base"),
126 stage_id: matches.opt_str("stage-id").unwrap(),
127 mode: str_mode(matches.opt_str("mode").unwrap()),
128 run_ignored: matches.opt_present("ignored"),
130 if !matches.free.is_empty() {
131 Some((*matches.free.get(0)).clone())
135 logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
136 save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
138 matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
139 ratchet_noise_percent:
140 matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
141 runtool: matches.opt_str("runtool"),
142 host_rustcflags: matches.opt_str("host-rustcflags"),
143 target_rustcflags: matches.opt_str("target-rustcflags"),
144 jit: matches.opt_present("jit"),
145 target: opt_str2(matches.opt_str("target")).to_str(),
146 host: opt_str2(matches.opt_str("host")).to_str(),
147 adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
149 opt_str2(matches.opt_str("adb-test-dir")).to_str(),
151 "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
152 "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
153 !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
154 test_shard: test::opt_shard(matches.opt_str("test-shard")),
155 verbose: matches.opt_present("verbose")
159 pub fn log_config(config: &config) {
161 logv(c, format!("configuration:"));
162 logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
163 logv(c, format!("run_lib_path: {}", config.run_lib_path));
164 logv(c, format!("rustc_path: {}", config.rustc_path.display()));
165 logv(c, format!("src_base: {}", config.src_base.display()));
166 logv(c, format!("build_base: {}", config.build_base.display()));
167 logv(c, format!("stage_id: {}", config.stage_id));
168 logv(c, format!("mode: {}", mode_str(config.mode)));
169 logv(c, format!("run_ignored: {}", config.run_ignored));
170 logv(c, format!("filter: {}", opt_str(&config.filter)));
171 logv(c, format!("runtool: {}", opt_str(&config.runtool)));
172 logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
173 logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
174 logv(c, format!("jit: {}", config.jit));
175 logv(c, format!("target: {}", config.target));
176 logv(c, format!("host: {}", config.host));
177 logv(c, format!("adb_path: {}", config.adb_path));
178 logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
179 logv(c, format!("adb_device_status: {}", config.adb_device_status));
180 match config.test_shard {
181 None => logv(c, ~"test_shard: (all)"),
182 Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
184 logv(c, format!("verbose: {}", config.verbose));
185 logv(c, format!("\n"));
188 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
198 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
199 match maybestr { None => ~"(none)", Some(s) => { s } }
202 pub fn str_mode(s: ~str) -> mode {
204 "compile-fail" => mode_compile_fail,
205 "run-fail" => mode_run_fail,
206 "run-pass" => mode_run_pass,
207 "pretty" => mode_pretty,
208 "debug-info" => mode_debug_info,
209 "codegen" => mode_codegen,
210 _ => fail!("invalid mode")
214 pub fn mode_str(mode: mode) -> ~str {
216 mode_compile_fail => ~"compile-fail",
217 mode_run_fail => ~"run-fail",
218 mode_run_pass => ~"run-pass",
219 mode_pretty => ~"pretty",
220 mode_debug_info => ~"debug-info",
221 mode_codegen => ~"codegen",
225 pub fn run_tests(config: &config) {
226 if config.target == ~"arm-linux-androideabi" {
229 println!("arm-linux-androideabi debug-info \
230 test uses tcp 5039 port. please reserve it");
235 //arm-linux-androideabi debug-info test uses remote debugger
236 //so, we test 1 task at once.
237 // also trying to isolate problems with adb_run_wrapper.sh ilooping
238 os::setenv("RUST_TEST_TASKS","1");
241 let opts = test_opts(config);
242 let tests = make_tests(config);
243 // sadly osx needs some file descriptor limits raised for running tests in
244 // parallel (especially when we have lots and lots of child processes).
245 // For context, see #8904
246 io::test::raise_fd_limit();
247 let res = test::run_tests_console(&opts, tests.move_iter().collect());
250 Ok(false) => fail!("Some tests failed"),
252 println!("I/O failure during tests: {}", e);
257 pub fn test_opts(config: &config) -> test::TestOpts {
259 filter: config.filter.clone(),
260 run_ignored: config.run_ignored,
261 logfile: config.logfile.clone(),
263 run_benchmarks: true,
264 ratchet_metrics: config.ratchet_metrics.clone(),
265 ratchet_noise_percent: config.ratchet_noise_percent.clone(),
266 save_metrics: config.save_metrics.clone(),
267 test_shard: config.test_shard.clone()
271 pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
272 debug!("making tests from {}",
273 config.src_base.display());
274 let mut tests = Vec::new();
275 let dirs = fs::readdir(&config.src_base).unwrap();
276 for file in dirs.iter() {
277 let file = file.clone();
278 debug!("inspecting file {}", file.display());
279 if is_test(config, &file) {
280 let t = make_test(config, &file, || {
282 mode_codegen => make_metrics_test_closure(config, &file),
283 _ => make_test_closure(config, &file)
292 pub fn is_test(config: &config, testfile: &Path) -> bool {
293 // Pretty-printer does not work with .rc files yet
294 let valid_extensions =
296 mode_pretty => vec!(~".rs"),
297 _ => vec!(~".rc", ~".rs")
299 let invalid_prefixes = vec!(~".", ~"#", ~"~");
300 let name = testfile.filename_str().unwrap();
302 let mut valid = false;
304 for ext in valid_extensions.iter() {
305 if name.ends_with(*ext) { valid = true; }
308 for pre in invalid_prefixes.iter() {
309 if name.starts_with(*pre) { valid = false; }
315 pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
316 -> test::TestDescAndFn {
317 test::TestDescAndFn {
318 desc: test::TestDesc {
319 name: make_test_name(config, testfile),
320 ignore: header::is_test_ignored(config, testfile),
327 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
329 // Try to elide redundant long paths
330 fn shorten(path: &Path) -> ~str {
331 let filename = path.filename_str();
332 let p = path.dir_path();
333 let dir = p.filename_str();
334 format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
337 test::DynTestName(format!("[{}] {}",
338 mode_str(config.mode),
342 pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
343 let config = (*config).clone();
344 // FIXME (#9639): This needs to handle non-utf8 paths
345 let testfile = testfile.as_str().unwrap().to_owned();
346 test::DynTestFn(proc() { runtest::run(config, testfile) })
349 pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
350 let config = (*config).clone();
351 // FIXME (#9639): This needs to handle non-utf8 paths
352 let testfile = testfile.as_str().unwrap().to_owned();
353 test::DynMetricFn(proc(mm) {
354 runtest::run_metrics(config, testfile, mm)