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 // we use our own (green) start below; do not link in libnative; issue #13247.
17 #![allow(non_camel_case_types)]
22 #[phase(link, syntax)]
30 use getopts::{optopt, optflag, reqopt};
32 use common::mode_run_pass;
33 use common::mode_run_fail;
34 use common::mode_compile_fail;
35 use common::mode_pretty;
36 use common::mode_debug_info;
37 use common::mode_codegen;
49 fn start(argc: int, argv: **u8) -> int {
50 green::start(argc, argv, rustuv::event_loop, main)
54 let args = os::args();
55 let config = parse_config(args.move_iter().collect());
60 pub fn parse_config(args: Vec<~str> ) -> config {
62 let groups : Vec<getopts::OptGroup> =
63 vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
64 reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
65 reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
66 optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
67 optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
68 reqopt("", "src-base", "directory to scan for test files", "PATH"),
69 reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
70 reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
71 reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
72 reqopt("", "mode", "which sort of compile tests to run",
73 "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
74 optflag("", "ignored", "run tests marked as ignored"),
75 optopt("", "runtool", "supervisor program to run tests under \
76 (eg. emulator, valgrind)", "PROGRAM"),
77 optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
78 optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
79 optflag("", "verbose", "run tests verbosely, showing all output"),
80 optopt("", "logfile", "file to log test execution to", "FILE"),
81 optopt("", "save-metrics", "file to save metrics to", "FILE"),
82 optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
83 optopt("", "ratchet-noise-percent",
84 "percent change in metrics to consider noise", "N"),
85 optflag("", "jit", "run tests under the JIT"),
86 optopt("", "target", "the target to build for", "TARGET"),
87 optopt("", "host", "the host to build for", "HOST"),
88 optopt("", "adb-path", "path to the android debugger", "PATH"),
89 optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
90 optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
91 optflag("h", "help", "show this message"));
93 assert!(!args.is_empty());
94 let argv0 = (*args.get(0)).clone();
95 let args_ = args.tail();
96 if *args.get(1) == ~"-h" || *args.get(1) == ~"--help" {
97 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
98 println!("{}", getopts::usage(message, groups.as_slice()));
104 &match getopts::getopts(args_, groups.as_slice()) {
106 Err(f) => fail!("{}", f.to_err_msg())
109 if matches.opt_present("h") || matches.opt_present("help") {
110 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
111 println!("{}", getopts::usage(message, groups.as_slice()));
116 fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
117 Path::new(m.opt_str(nm).unwrap())
121 compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
122 run_lib_path: matches.opt_str("run-lib-path").unwrap(),
123 rustc_path: opt_path(matches, "rustc-path"),
124 clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
125 llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
126 src_base: opt_path(matches, "src-base"),
127 build_base: opt_path(matches, "build-base"),
128 aux_base: opt_path(matches, "aux-base"),
129 stage_id: matches.opt_str("stage-id").unwrap(),
130 mode: str_mode(matches.opt_str("mode").unwrap()),
131 run_ignored: matches.opt_present("ignored"),
133 if !matches.free.is_empty() {
134 Some((*matches.free.get(0)).clone())
138 logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
139 save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
141 matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
142 ratchet_noise_percent:
143 matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
144 runtool: matches.opt_str("runtool"),
145 host_rustcflags: matches.opt_str("host-rustcflags"),
146 target_rustcflags: matches.opt_str("target-rustcflags"),
147 jit: matches.opt_present("jit"),
148 target: opt_str2(matches.opt_str("target")).to_str(),
149 host: opt_str2(matches.opt_str("host")).to_str(),
150 adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
152 opt_str2(matches.opt_str("adb-test-dir")).to_str(),
154 "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
155 "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
156 !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
157 test_shard: test::opt_shard(matches.opt_str("test-shard")),
158 verbose: matches.opt_present("verbose")
162 pub fn log_config(config: &config) {
164 logv(c, format!("configuration:"));
165 logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
166 logv(c, format!("run_lib_path: {}", config.run_lib_path));
167 logv(c, format!("rustc_path: {}", config.rustc_path.display()));
168 logv(c, format!("src_base: {}", config.src_base.display()));
169 logv(c, format!("build_base: {}", config.build_base.display()));
170 logv(c, format!("stage_id: {}", config.stage_id));
171 logv(c, format!("mode: {}", mode_str(config.mode)));
172 logv(c, format!("run_ignored: {}", config.run_ignored));
173 logv(c, format!("filter: {}", opt_str(&config.filter)));
174 logv(c, format!("runtool: {}", opt_str(&config.runtool)));
175 logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
176 logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
177 logv(c, format!("jit: {}", config.jit));
178 logv(c, format!("target: {}", config.target));
179 logv(c, format!("host: {}", config.host));
180 logv(c, format!("adb_path: {}", config.adb_path));
181 logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
182 logv(c, format!("adb_device_status: {}", config.adb_device_status));
183 match config.test_shard {
184 None => logv(c, ~"test_shard: (all)"),
185 Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
187 logv(c, format!("verbose: {}", config.verbose));
188 logv(c, format!("\n"));
191 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
201 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
202 match maybestr { None => ~"(none)", Some(s) => { s } }
205 pub fn str_mode(s: ~str) -> mode {
207 "compile-fail" => mode_compile_fail,
208 "run-fail" => mode_run_fail,
209 "run-pass" => mode_run_pass,
210 "pretty" => mode_pretty,
211 "debug-info" => mode_debug_info,
212 "codegen" => mode_codegen,
213 _ => fail!("invalid mode")
217 pub fn mode_str(mode: mode) -> ~str {
219 mode_compile_fail => ~"compile-fail",
220 mode_run_fail => ~"run-fail",
221 mode_run_pass => ~"run-pass",
222 mode_pretty => ~"pretty",
223 mode_debug_info => ~"debug-info",
224 mode_codegen => ~"codegen",
228 pub fn run_tests(config: &config) {
229 if config.target == ~"arm-linux-androideabi" {
232 println!("arm-linux-androideabi debug-info \
233 test uses tcp 5039 port. please reserve it");
238 //arm-linux-androideabi debug-info test uses remote debugger
239 //so, we test 1 task at once.
240 // also trying to isolate problems with adb_run_wrapper.sh ilooping
241 os::setenv("RUST_TEST_TASKS","1");
244 let opts = test_opts(config);
245 let tests = make_tests(config);
246 // sadly osx needs some file descriptor limits raised for running tests in
247 // parallel (especially when we have lots and lots of child processes).
248 // For context, see #8904
249 io::test::raise_fd_limit();
250 let res = test::run_tests_console(&opts, tests.move_iter().collect());
253 Ok(false) => fail!("Some tests failed"),
255 println!("I/O failure during tests: {}", e);
260 pub fn test_opts(config: &config) -> test::TestOpts {
262 filter: config.filter.clone(),
263 run_ignored: config.run_ignored,
264 logfile: config.logfile.clone(),
266 run_benchmarks: true,
267 ratchet_metrics: config.ratchet_metrics.clone(),
268 ratchet_noise_percent: config.ratchet_noise_percent.clone(),
269 save_metrics: config.save_metrics.clone(),
270 test_shard: config.test_shard.clone()
274 pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
275 debug!("making tests from {}",
276 config.src_base.display());
277 let mut tests = Vec::new();
278 let dirs = fs::readdir(&config.src_base).unwrap();
279 for file in dirs.iter() {
280 let file = file.clone();
281 debug!("inspecting file {}", file.display());
282 if is_test(config, &file) {
283 let t = make_test(config, &file, || {
285 mode_codegen => make_metrics_test_closure(config, &file),
286 _ => make_test_closure(config, &file)
295 pub fn is_test(config: &config, testfile: &Path) -> bool {
296 // Pretty-printer does not work with .rc files yet
297 let valid_extensions =
299 mode_pretty => vec!(~".rs"),
300 _ => vec!(~".rc", ~".rs")
302 let invalid_prefixes = vec!(~".", ~"#", ~"~");
303 let name = testfile.filename_str().unwrap();
305 let mut valid = false;
307 for ext in valid_extensions.iter() {
308 if name.ends_with(*ext) { valid = true; }
311 for pre in invalid_prefixes.iter() {
312 if name.starts_with(*pre) { valid = false; }
318 pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
319 -> test::TestDescAndFn {
320 test::TestDescAndFn {
321 desc: test::TestDesc {
322 name: make_test_name(config, testfile),
323 ignore: header::is_test_ignored(config, testfile),
330 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
332 // Try to elide redundant long paths
333 fn shorten(path: &Path) -> ~str {
334 let filename = path.filename_str();
335 let p = path.dir_path();
336 let dir = p.filename_str();
337 format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
340 test::DynTestName(format!("[{}] {}",
341 mode_str(config.mode),
345 pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
346 let config = (*config).clone();
347 // FIXME (#9639): This needs to handle non-utf8 paths
348 let testfile = testfile.as_str().unwrap().to_owned();
349 test::DynTestFn(proc() { runtest::run(config, testfile) })
352 pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
353 let config = (*config).clone();
354 // FIXME (#9639): This needs to handle non-utf8 paths
355 let testfile = testfile.as_str().unwrap().to_owned();
356 test::DynMetricFn(proc(mm) {
357 runtest::run_metrics(config, testfile, mm)