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