]> git.lizzy.rs Git - rust.git/blob - src/compiletest/compiletest.rs
auto merge of #13052 : sfackler/rust/clean-refcell, r=alexcrichton
[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 #[feature(phase)];
13
14 #[allow(non_camel_case_types)];
15 #[allow(deprecated_owned_vector)]; // NOTE: remove after stage0
16 #[deny(warnings)];
17
18 extern crate test;
19 extern crate getopts;
20 #[phase(link, syntax)]
21 extern crate log;
22 extern crate green;
23 extern crate rustuv;
24
25 use std::os;
26 use std::io;
27 use std::io::fs;
28 use getopts::{optopt, optflag, reqopt};
29 use common::config;
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;
36 use common::mode;
37 use util::logv;
38
39 pub mod procsrv;
40 pub mod util;
41 pub mod header;
42 pub mod runtest;
43 pub mod common;
44 pub mod errors;
45
46 #[start]
47 fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }
48
49 pub fn main() {
50     let args = os::args();
51     let config = parse_config(args.move_iter().collect());
52     log_config(&config);
53     run_tests(&config);
54 }
55
56 pub fn parse_config(args: Vec<~str> ) -> config {
57
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"));
88
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()));
95         println!("");
96         fail!()
97     }
98
99     let matches =
100         &match getopts::getopts(args_, groups.as_slice()) {
101           Ok(m) => m,
102           Err(f) => fail!("{}", f.to_err_msg())
103         };
104
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()));
108         println!("");
109         fail!()
110     }
111
112     fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
113         Path::new(m.opt_str(nm).unwrap())
114     }
115
116     config {
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"),
128         filter:
129             if !matches.free.is_empty() {
130                  Some((*matches.free.get(0)).clone())
131             } else {
132                 None
133             },
134         logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
135         save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
136         ratchet_metrics:
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(),
147         adb_test_dir:
148             opt_str2(matches.opt_str("adb-test-dir")).to_str(),
149         adb_device_status:
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")
155     }
156 }
157
158 pub fn log_config(config: &config) {
159     let c = 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))
182     }
183     logv(c, format!("verbose: {}", config.verbose));
184     logv(c, format!("\n"));
185 }
186
187 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
188     match *maybestr {
189         None => "(none)",
190         Some(ref s) => {
191             let s: &'a str = *s;
192             s
193         }
194     }
195 }
196
197 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
198     match maybestr { None => ~"(none)", Some(s) => { s } }
199 }
200
201 pub fn str_mode(s: ~str) -> mode {
202     match s.as_slice() {
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")
210     }
211 }
212
213 pub fn mode_str(mode: mode) -> ~str {
214     match mode {
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",
221     }
222 }
223
224 pub fn run_tests(config: &config) {
225     if config.target == ~"arm-linux-androideabi" {
226         match config.mode{
227             mode_debug_info => {
228                 println!("arm-linux-androideabi debug-info \
229                          test uses tcp 5039 port. please reserve it");
230             }
231             _ =>{}
232         }
233
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");
238     }
239
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());
247     match res {
248         Ok(true) => {}
249         Ok(false) => fail!("Some tests failed"),
250         Err(e) => {
251             println!("I/O failure during tests: {}", e);
252         }
253     }
254 }
255
256 pub fn test_opts(config: &config) -> test::TestOpts {
257     test::TestOpts {
258         filter: config.filter.clone(),
259         run_ignored: config.run_ignored,
260         logfile: config.logfile.clone(),
261         run_tests: true,
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()
267     }
268 }
269
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, || {
280                 match config.mode {
281                     mode_codegen => make_metrics_test_closure(config, &file),
282                     _ => make_test_closure(config, &file)
283                 }
284             });
285             tests.push(t)
286         }
287     }
288     tests
289 }
290
291 pub fn is_test(config: &config, testfile: &Path) -> bool {
292     // Pretty-printer does not work with .rc files yet
293     let valid_extensions =
294         match config.mode {
295           mode_pretty => vec!(~".rs"),
296           _ => vec!(~".rc", ~".rs")
297         };
298     let invalid_prefixes = vec!(~".", ~"#", ~"~");
299     let name = testfile.filename_str().unwrap();
300
301     let mut valid = false;
302
303     for ext in valid_extensions.iter() {
304         if name.ends_with(*ext) { valid = true; }
305     }
306
307     for pre in invalid_prefixes.iter() {
308         if name.starts_with(*pre) { valid = false; }
309     }
310
311     return valid;
312 }
313
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),
320             should_fail: false
321         },
322         testfn: f(),
323     }
324 }
325
326 pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
327
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(""))
334     }
335
336     test::DynTestName(format!("[{}] {}",
337                               mode_str(config.mode),
338                               shorten(testfile)))
339 }
340
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) })
346 }
347
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)
354     })
355 }