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