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