]> git.lizzy.rs Git - rust.git/blob - src/compiletest/compiletest.rs
Get rid of the android-cross-path flag to rustc.
[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 // we use our own (green) start below; do not link in libnative; issue #13247.
15 #![no_start]
16
17 #![deny(warnings)]
18
19 extern crate test;
20 extern crate getopts;
21 #[phase(link, syntax)]
22 extern crate log;
23 extern crate green;
24 extern crate rustuv;
25
26 use std::os;
27 use std::io;
28 use std::io::fs;
29 use std::from_str::FromStr;
30 use getopts::{optopt, optflag, reqopt};
31 use common::Config;
32 use common::{Pretty, DebugInfoGdb, Codegen};
33 use util::logv;
34
35 pub mod procsrv;
36 pub mod util;
37 pub mod header;
38 pub mod runtest;
39 pub mod common;
40 pub mod errors;
41
42 #[start]
43 fn start(argc: int, argv: **u8) -> int {
44     green::start(argc, argv, rustuv::event_loop, main)
45 }
46
47 pub fn main() {
48     let args = os::args();
49     let config = parse_config(args.move_iter().collect());
50     log_config(&config);
51     run_tests(&config);
52 }
53
54 pub fn parse_config(args: Vec<~str> ) -> Config {
55
56     let groups : Vec<getopts::OptGroup> =
57         vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
58           reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
59           reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
60           optopt("", "clang-path", "path to  executable for codegen tests", "PATH"),
61           optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
62           reqopt("", "src-base", "directory to scan for test files", "PATH"),
63           reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
64           reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
65           reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
66           reqopt("", "mode", "which sort of compile tests to run",
67                  "(compile-fail|run-fail|run-pass|pretty|debug-info)"),
68           optflag("", "ignored", "run tests marked as ignored"),
69           optopt("", "runtool", "supervisor program to run tests under \
70                                  (eg. emulator, valgrind)", "PROGRAM"),
71           optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
72           optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
73           optflag("", "verbose", "run tests verbosely, showing all output"),
74           optopt("", "logfile", "file to log test execution to", "FILE"),
75           optopt("", "save-metrics", "file to save metrics to", "FILE"),
76           optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
77           optopt("", "ratchet-noise-percent",
78                  "percent change in metrics to consider noise", "N"),
79           optflag("", "jit", "run tests under the JIT"),
80           optopt("", "target", "the target to build for", "TARGET"),
81           optopt("", "host", "the host to build for", "HOST"),
82           optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
83           optopt("", "adb-path", "path to the android debugger", "PATH"),
84           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
85           optopt("", "lldb-python-dir", "directory containing LLDB's python module", "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".to_owned() || *args.get(1) == "--help".to_owned() {
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: FromStr::from_str(matches.opt_str("mode").unwrap()).expect("invalid mode"),
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         android_cross_path: opt_path(matches, "android-cross-path"),
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         lldb_python_dir: matches.opt_str("lldb-python-dir"),
155         test_shard: test::opt_shard(matches.opt_str("test-shard")),
156         verbose: matches.opt_present("verbose")
157     }
158 }
159
160 pub fn log_config(config: &Config) {
161     let c = config;
162     logv(c, format!("configuration:"));
163     logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
164     logv(c, format!("run_lib_path: {}", config.run_lib_path));
165     logv(c, format!("rustc_path: {}", config.rustc_path.display()));
166     logv(c, format!("src_base: {}", config.src_base.display()));
167     logv(c, format!("build_base: {}", config.build_base.display()));
168     logv(c, format!("stage_id: {}", config.stage_id));
169     logv(c, format!("mode: {}", config.mode));
170     logv(c, format!("run_ignored: {}", config.run_ignored));
171     logv(c, format!("filter: {}", opt_str(&config.filter)));
172     logv(c, format!("runtool: {}", opt_str(&config.runtool)));
173     logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
174     logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
175     logv(c, format!("jit: {}", config.jit));
176     logv(c, format!("target: {}", config.target));
177     logv(c, format!("host: {}", config.host));
178     logv(c, format!("android-cross-path: {}", config.android_cross_path.display()));
179     logv(c, format!("adb_path: {}", config.adb_path));
180     logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
181     logv(c, format!("adb_device_status: {}", config.adb_device_status));
182     match config.test_shard {
183         None => logv(c, "test_shard: (all)".to_owned()),
184         Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
185     }
186     logv(c, format!("verbose: {}", config.verbose));
187     logv(c, format!("\n"));
188 }
189
190 pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
191     match *maybestr {
192         None => "(none)",
193         Some(ref s) => {
194             let s: &'a str = *s;
195             s
196         }
197     }
198 }
199
200 pub fn opt_str2(maybestr: Option<~str>) -> ~str {
201     match maybestr { None => "(none)".to_owned(), Some(s) => { s } }
202 }
203
204 pub fn run_tests(config: &Config) {
205     if config.target == "arm-linux-androideabi".to_owned() {
206         match config.mode {
207             DebugInfoGdb => {
208                 println!("arm-linux-androideabi debug-info \
209                          test uses tcp 5039 port. please reserve it");
210             }
211             _ =>{}
212         }
213
214         //arm-linux-androideabi debug-info test uses remote debugger
215         //so, we test 1 task at once.
216         // also trying to isolate problems with adb_run_wrapper.sh ilooping
217         os::setenv("RUST_TEST_TASKS","1");
218     }
219
220     let opts = test_opts(config);
221     let tests = make_tests(config);
222     // sadly osx needs some file descriptor limits raised for running tests in
223     // parallel (especially when we have lots and lots of child processes).
224     // For context, see #8904
225     io::test::raise_fd_limit();
226     let res = test::run_tests_console(&opts, tests.move_iter().collect());
227     match res {
228         Ok(true) => {}
229         Ok(false) => fail!("Some tests failed"),
230         Err(e) => {
231             println!("I/O failure during tests: {}", e);
232         }
233     }
234 }
235
236 pub fn test_opts(config: &Config) -> test::TestOpts {
237     test::TestOpts {
238         filter: config.filter.clone(),
239         run_ignored: config.run_ignored,
240         logfile: config.logfile.clone(),
241         run_tests: true,
242         run_benchmarks: true,
243         ratchet_metrics: config.ratchet_metrics.clone(),
244         ratchet_noise_percent: config.ratchet_noise_percent.clone(),
245         save_metrics: config.save_metrics.clone(),
246         test_shard: config.test_shard.clone(),
247         nocapture: false,
248     }
249 }
250
251 pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
252     debug!("making tests from {}",
253            config.src_base.display());
254     let mut tests = Vec::new();
255     let dirs = fs::readdir(&config.src_base).unwrap();
256     for file in dirs.iter() {
257         let file = file.clone();
258         debug!("inspecting file {}", file.display());
259         if is_test(config, &file) {
260             let t = make_test(config, &file, || {
261                 match config.mode {
262                     Codegen => make_metrics_test_closure(config, &file),
263                     _ => make_test_closure(config, &file)
264                 }
265             });
266             tests.push(t)
267         }
268     }
269     tests
270 }
271
272 pub fn is_test(config: &Config, testfile: &Path) -> bool {
273     // Pretty-printer does not work with .rc files yet
274     let valid_extensions =
275         match config.mode {
276           Pretty => vec!(".rs".to_owned()),
277           _ => vec!(".rc".to_owned(), ".rs".to_owned())
278         };
279     let invalid_prefixes = vec!(".".to_owned(), "#".to_owned(), "~".to_owned());
280     let name = testfile.filename_str().unwrap();
281
282     let mut valid = false;
283
284     for ext in valid_extensions.iter() {
285         if name.ends_with(*ext) { valid = true; }
286     }
287
288     for pre in invalid_prefixes.iter() {
289         if name.starts_with(*pre) { valid = false; }
290     }
291
292     return valid;
293 }
294
295 pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
296                  -> test::TestDescAndFn {
297     test::TestDescAndFn {
298         desc: test::TestDesc {
299             name: make_test_name(config, testfile),
300             ignore: header::is_test_ignored(config, testfile),
301             should_fail: false
302         },
303         testfn: f(),
304     }
305 }
306
307 pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
308
309     // Try to elide redundant long paths
310     fn shorten(path: &Path) -> ~str {
311         let filename = path.filename_str();
312         let p = path.dir_path();
313         let dir = p.filename_str();
314         format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
315     }
316
317     test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
318 }
319
320 pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
321     let config = (*config).clone();
322     // FIXME (#9639): This needs to handle non-utf8 paths
323     let testfile = testfile.as_str().unwrap().to_owned();
324     test::DynTestFn(proc() { runtest::run(config, testfile) })
325 }
326
327 pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
328     let config = (*config).clone();
329     // FIXME (#9639): This needs to handle non-utf8 paths
330     let testfile = testfile.as_str().unwrap().to_owned();
331     test::DynMetricFn(proc(mm) {
332         runtest::run_metrics(config, testfile, mm)
333     })
334 }