]> git.lizzy.rs Git - rust.git/blob - src/compiletest/compiletest.rs
mk: Fix non-android cross builds.
[rust.git] / src / compiletest / compiletest.rs
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.
4 //
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.
10
11 #[crate_type = "bin"];
12
13 #[allow(non_camel_case_types)];
14 #[deny(warnings)];
15
16 extern mod extra;
17 extern mod getopts;
18
19 use std::os;
20 use std::io;
21 use std::io::fs;
22
23 use getopts::{optopt, optflag, reqopt};
24 use extra::test;
25
26 use common::config;
27 use common::mode_run_pass;
28 use common::mode_run_fail;
29 use common::mode_compile_fail;
30 use common::mode_pretty;
31 use common::mode_debug_info;
32 use common::mode_codegen;
33 use common::mode;
34 use util::logv;
35
36 pub mod procsrv;
37 pub mod util;
38 pub mod header;
39 pub mod runtest;
40 pub mod common;
41 pub mod errors;
42
43 pub fn main() {
44     let args = os::args();
45     let config = parse_config(args);
46     log_config(&config);
47     run_tests(&config);
48 }
49
50 pub fn parse_config(args: ~[~str]) -> config {
51
52     let groups : ~[getopts::OptGroup] =
53         ~[reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
54           reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
55           reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
56           optopt("", "clang-path", "path to  executable for codegen tests", "PATH"),
57           optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
58           reqopt("", "src-base", "directory to scan for test files", "PATH"),
59           reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
60           reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
61           reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
62           reqopt("", "mode", "which sort of compile tests to run",
63                  "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
64           optflag("", "ignored", "run tests marked as ignored"),
65           optopt("", "runtool", "supervisor program to run tests under \
66                                  (eg. emulator, valgrind)", "PROGRAM"),
67           optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
68           optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
69           optflag("", "verbose", "run tests verbosely, showing all output"),
70           optopt("", "logfile", "file to log test execution to", "FILE"),
71           optopt("", "save-metrics", "file to save metrics to", "FILE"),
72           optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
73           optopt("", "ratchet-noise-percent",
74                  "percent change in metrics to consider noise", "N"),
75           optflag("", "jit", "run tests under the JIT"),
76           optopt("", "target", "the target to build for", "TARGET"),
77           optopt("", "host", "the host to build for", "HOST"),
78           optopt("", "adb-path", "path to the android debugger", "PATH"),
79           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
80           optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
81           optflag("h", "help", "show this message"),
82          ];
83
84     assert!(!args.is_empty());
85     let argv0 = args[0].clone();
86     let args_ = args.tail();
87     if args[1] == ~"-h" || args[1] == ~"--help" {
88         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
89         println!("{}", getopts::usage(message, groups));
90         println!("");
91         fail!()
92     }
93
94     let matches =
95         &match getopts::getopts(args_, groups) {
96           Ok(m) => m,
97           Err(f) => fail!("{}", f.to_err_msg())
98         };
99
100     if matches.opt_present("h") || matches.opt_present("help") {
101         let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
102         println!("{}", getopts::usage(message, groups));
103         println!("");
104         fail!()
105     }
106
107     fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
108         Path::new(m.opt_str(nm).unwrap())
109     }
110
111     config {
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"),
123         filter:
124             if !matches.free.is_empty() {
125                  Some(matches.free[0].clone())
126             } else {
127                 None
128             },
129         logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
130         save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
131         ratchet_metrics:
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(),
142         adb_test_dir:
143             opt_str2(matches.opt_str("adb-test-dir")).to_str(),
144         adb_device_status:
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")
150     }
151 }
152
153 pub fn log_config(config: &config) {
154     let c = 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))
177     }
178     logv(c, format!("verbose: {}", config.verbose));
179     logv(c, format!("\n"));
180 }
181
182 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
183     match *maybestr {
184         None => "(none)",
185         Some(ref s) => {
186             let s: &'a str = *s;
187             s
188         }
189     }
190 }
191
192 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
193     match maybestr { None => ~"(none)", Some(s) => { s } }
194 }
195
196 pub fn str_mode(s: ~str) -> mode {
197     match s {
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")
205     }
206 }
207
208 pub fn mode_str(mode: mode) -> ~str {
209     match mode {
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",
216     }
217 }
218
219 pub fn run_tests(config: &config) {
220     if config.target == ~"arm-linux-androideabi" {
221         match config.mode{
222             mode_debug_info => {
223                 println!("arm-linux-androideabi debug-info \
224                          test uses tcp 5039 port. please reserve it");
225                 //arm-linux-androideabi debug-info test uses remote debugger
226                 //so, we test 1 task at once
227                 os::setenv("RUST_TEST_TASKS","1");
228             }
229             _ =>{}
230         }
231     }
232
233     let opts = test_opts(config);
234     let tests = make_tests(config);
235     // sadly osx needs some file descriptor limits raised for running tests in
236     // parallel (especially when we have lots and lots of child processes).
237     // For context, see #8904
238     io::test::raise_fd_limit();
239     let res = test::run_tests_console(&opts, tests);
240     match res {
241         Ok(true) => {}
242         Ok(false) => fail!("Some tests failed"),
243         Err(e) => {
244             println!("I/O failure during tests: {}", e);
245         }
246     }
247 }
248
249 pub fn test_opts(config: &config) -> test::TestOpts {
250     test::TestOpts {
251         filter: config.filter.clone(),
252         run_ignored: config.run_ignored,
253         logfile: config.logfile.clone(),
254         run_tests: true,
255         run_benchmarks: true,
256         ratchet_metrics: config.ratchet_metrics.clone(),
257         ratchet_noise_percent: config.ratchet_noise_percent.clone(),
258         save_metrics: config.save_metrics.clone(),
259         test_shard: config.test_shard.clone()
260     }
261 }
262
263 pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
264     debug!("making tests from {}",
265            config.src_base.display());
266     let mut tests = ~[];
267     let dirs = fs::readdir(&config.src_base).unwrap();
268     for file in dirs.iter() {
269         let file = file.clone();
270         debug!("inspecting file {}", file.display());
271         if is_test(config, &file) {
272             let t = make_test(config, &file, || {
273                 match config.mode {
274                     mode_codegen => make_metrics_test_closure(config, &file),
275                     _ => make_test_closure(config, &file)
276                 }
277             });
278             tests.push(t)
279         }
280     }
281     tests
282 }
283
284 pub fn is_test(config: &config, testfile: &Path) -> bool {
285     // Pretty-printer does not work with .rc files yet
286     let valid_extensions =
287         match config.mode {
288           mode_pretty => ~[~".rs"],
289           _ => ~[~".rc", ~".rs"]
290         };
291     let invalid_prefixes = ~[~".", ~"#", ~"~"];
292     let name = testfile.filename_str().unwrap();
293
294     let mut valid = false;
295
296     for ext in valid_extensions.iter() {
297         if name.ends_with(*ext) { valid = true; }
298     }
299
300     for pre in invalid_prefixes.iter() {
301         if name.starts_with(*pre) { valid = false; }
302     }
303
304     return valid;
305 }
306
307 pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
308                  -> test::TestDescAndFn {
309     test::TestDescAndFn {
310         desc: test::TestDesc {
311             name: make_test_name(config, testfile),
312             ignore: header::is_test_ignored(config, testfile),
313             should_fail: false
314         },
315         testfn: f(),
316     }
317 }
318
319 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
320
321     // Try to elide redundant long paths
322     fn shorten(path: &Path) -> ~str {
323         let filename = path.filename_str();
324         let p = path.dir_path();
325         let dir = p.filename_str();
326         format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
327     }
328
329     test::DynTestName(format!("[{}] {}",
330                               mode_str(config.mode),
331                               shorten(testfile)))
332 }
333
334 pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
335     let config = (*config).clone();
336     // FIXME (#9639): This needs to handle non-utf8 paths
337     let testfile = testfile.as_str().unwrap().to_owned();
338     test::DynTestFn(proc() { runtest::run(config, testfile) })
339 }
340
341 pub fn make_metrics_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::DynMetricFn(proc(mm) {
346         runtest::run_metrics(config, testfile, mm)
347     })
348 }