]> git.lizzy.rs Git - rust.git/blob - src/compiletest/compiletest.rs
auto merge of #12875 : alexcrichton/rust/demangle-more-things, r=brson
[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 #[allow(deprecated_owned_vector)];
16
17 extern crate test;
18 extern crate getopts;
19
20 use std::os;
21 use std::io;
22 use std::io::fs;
23 use getopts::{optopt, optflag, reqopt};
24 use common::config;
25 use common::mode_run_pass;
26 use common::mode_run_fail;
27 use common::mode_compile_fail;
28 use common::mode_pretty;
29 use common::mode_debug_info;
30 use common::mode_codegen;
31 use common::mode;
32 use util::logv;
33
34 pub mod procsrv;
35 pub mod util;
36 pub mod header;
37 pub mod runtest;
38 pub mod common;
39 pub mod errors;
40
41 pub fn main() {
42     let args = os::args();
43     let config = parse_config(args);
44     log_config(&config);
45     run_tests(&config);
46 }
47
48 pub fn parse_config(args: ~[~str]) -> config {
49
50     let groups : ~[getopts::OptGroup] =
51         ~[reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
52           reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
53           reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
54           optopt("", "clang-path", "path to  executable for codegen tests", "PATH"),
55           optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
56           reqopt("", "src-base", "directory to scan for test files", "PATH"),
57           reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
58           reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
59           reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
60           reqopt("", "mode", "which sort of compile tests to run",
61                  "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
62           optflag("", "ignored", "run tests marked as ignored"),
63           optopt("", "runtool", "supervisor program to run tests under \
64                                  (eg. emulator, valgrind)", "PROGRAM"),
65           optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
66           optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
67           optflag("", "verbose", "run tests verbosely, showing all output"),
68           optopt("", "logfile", "file to log test execution to", "FILE"),
69           optopt("", "save-metrics", "file to save metrics to", "FILE"),
70           optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
71           optopt("", "ratchet-noise-percent",
72                  "percent change in metrics to consider noise", "N"),
73           optflag("", "jit", "run tests under the JIT"),
74           optopt("", "target", "the target to build for", "TARGET"),
75           optopt("", "host", "the host to build for", "HOST"),
76           optopt("", "adb-path", "path to the android debugger", "PATH"),
77           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
78           optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
79           optflag("h", "help", "show this message"),
80          ];
81
82     assert!(!args.is_empty());
83     let argv0 = args[0].clone();
84     let args_ = args.tail();
85     if args[1] == ~"-h" || args[1] == ~"--help" {
86         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
87         println!("{}", getopts::usage(message, groups));
88         println!("");
89         fail!()
90     }
91
92     let matches =
93         &match getopts::getopts(args_, groups) {
94           Ok(m) => m,
95           Err(f) => fail!("{}", f.to_err_msg())
96         };
97
98     if matches.opt_present("h") || matches.opt_present("help") {
99         let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
100         println!("{}", getopts::usage(message, groups));
101         println!("");
102         fail!()
103     }
104
105     fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
106         Path::new(m.opt_str(nm).unwrap())
107     }
108
109     config {
110         compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
111         run_lib_path: matches.opt_str("run-lib-path").unwrap(),
112         rustc_path: opt_path(matches, "rustc-path"),
113         clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
114         llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
115         src_base: opt_path(matches, "src-base"),
116         build_base: opt_path(matches, "build-base"),
117         aux_base: opt_path(matches, "aux-base"),
118         stage_id: matches.opt_str("stage-id").unwrap(),
119         mode: str_mode(matches.opt_str("mode").unwrap()),
120         run_ignored: matches.opt_present("ignored"),
121         filter:
122             if !matches.free.is_empty() {
123                  Some(matches.free[0].clone())
124             } else {
125                 None
126             },
127         logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
128         save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
129         ratchet_metrics:
130             matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
131         ratchet_noise_percent:
132             matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
133         runtool: matches.opt_str("runtool"),
134         host_rustcflags: matches.opt_str("host-rustcflags"),
135         target_rustcflags: matches.opt_str("target-rustcflags"),
136         jit: matches.opt_present("jit"),
137         target: opt_str2(matches.opt_str("target")).to_str(),
138         host: opt_str2(matches.opt_str("host")).to_str(),
139         adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
140         adb_test_dir:
141             opt_str2(matches.opt_str("adb-test-dir")).to_str(),
142         adb_device_status:
143             "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
144             "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
145             !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
146         test_shard: test::opt_shard(matches.opt_str("test-shard")),
147         verbose: matches.opt_present("verbose")
148     }
149 }
150
151 pub fn log_config(config: &config) {
152     let c = config;
153     logv(c, format!("configuration:"));
154     logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
155     logv(c, format!("run_lib_path: {}", config.run_lib_path));
156     logv(c, format!("rustc_path: {}", config.rustc_path.display()));
157     logv(c, format!("src_base: {}", config.src_base.display()));
158     logv(c, format!("build_base: {}", config.build_base.display()));
159     logv(c, format!("stage_id: {}", config.stage_id));
160     logv(c, format!("mode: {}", mode_str(config.mode)));
161     logv(c, format!("run_ignored: {}", config.run_ignored));
162     logv(c, format!("filter: {}", opt_str(&config.filter)));
163     logv(c, format!("runtool: {}", opt_str(&config.runtool)));
164     logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
165     logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
166     logv(c, format!("jit: {}", config.jit));
167     logv(c, format!("target: {}", config.target));
168     logv(c, format!("host: {}", config.host));
169     logv(c, format!("adb_path: {}", config.adb_path));
170     logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
171     logv(c, format!("adb_device_status: {}", config.adb_device_status));
172     match config.test_shard {
173         None => logv(c, ~"test_shard: (all)"),
174         Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
175     }
176     logv(c, format!("verbose: {}", config.verbose));
177     logv(c, format!("\n"));
178 }
179
180 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
181     match *maybestr {
182         None => "(none)",
183         Some(ref s) => {
184             let s: &'a str = *s;
185             s
186         }
187     }
188 }
189
190 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
191     match maybestr { None => ~"(none)", Some(s) => { s } }
192 }
193
194 pub fn str_mode(s: ~str) -> mode {
195     match s.as_slice() {
196       "compile-fail" => mode_compile_fail,
197       "run-fail" => mode_run_fail,
198       "run-pass" => mode_run_pass,
199       "pretty" => mode_pretty,
200       "debug-info" => mode_debug_info,
201       "codegen" => mode_codegen,
202       _ => fail!("invalid mode")
203     }
204 }
205
206 pub fn mode_str(mode: mode) -> ~str {
207     match mode {
208       mode_compile_fail => ~"compile-fail",
209       mode_run_fail => ~"run-fail",
210       mode_run_pass => ~"run-pass",
211       mode_pretty => ~"pretty",
212       mode_debug_info => ~"debug-info",
213       mode_codegen => ~"codegen",
214     }
215 }
216
217 pub fn run_tests(config: &config) {
218     if config.target == ~"arm-linux-androideabi" {
219         match config.mode{
220             mode_debug_info => {
221                 println!("arm-linux-androideabi debug-info \
222                          test uses tcp 5039 port. please reserve it");
223             }
224             _ =>{}
225         }
226
227         //arm-linux-androideabi debug-info test uses remote debugger
228         //so, we test 1 task at once.
229         // also trying to isolate problems with adb_run_wrapper.sh ilooping
230         os::setenv("RUST_TEST_TASKS","1");
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 }