]> git.proxmox.com Git - rustc.git/blame - src/compiletest/compiletest.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / compiletest / compiletest.rs
CommitLineData
1a4d82fc 1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
970d7e83
LB
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
1a4d82fc 11#![crate_type = "bin"]
85aaf69f 12
1a4d82fc 13#![feature(box_syntax)]
62682a34
SL
14#![feature(dynamic_lib)]
15#![feature(libc)]
62682a34 16#![feature(rustc_private)]
c34b1796 17#![feature(str_char)]
62682a34 18#![feature(test)]
1a4d82fc
JJ
19
20#![deny(warnings)]
21
9346a6ac 22extern crate libc;
1a4d82fc
JJ
23extern crate test;
24extern crate getopts;
25
26#[macro_use]
27extern crate log;
1a4d82fc 28
85aaf69f 29use std::env;
c34b1796
AL
30use std::fs;
31use std::path::{Path, PathBuf};
1a4d82fc
JJ
32use getopts::{optopt, optflag, reqopt};
33use common::Config;
62682a34 34use common::{Pretty, DebugInfoGdb, DebugInfoLldb};
970d7e83
LB
35use util::logv;
36
37pub mod procsrv;
38pub mod util;
39pub mod header;
40pub mod runtest;
41pub mod common;
42pub mod errors;
9346a6ac 43mod raise_fd_limit;
970d7e83 44
970d7e83 45pub fn main() {
85aaf69f 46 let config = parse_config(env::args().collect());
1a4d82fc
JJ
47
48 if config.valgrind_path.is_none() && config.force_valgrind {
49 panic!("Can't find Valgrind to run Valgrind tests");
50 }
51
970d7e83
LB
52 log_config(&config);
53 run_tests(&config);
54}
55
1a4d82fc
JJ
56pub fn parse_config(args: Vec<String> ) -> 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"),
9346a6ac
AL
62 reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"),
63 reqopt("", "python", "path to python to use for doc tests", "PATH"),
1a4d82fc
JJ
64 optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"),
65 optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"),
66 optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
67 reqopt("", "src-base", "directory to scan for test files", "PATH"),
68 reqopt("", "build-base", "directory to deposit test outputs", "PATH"),
69 reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"),
70 reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"),
71 reqopt("", "mode", "which sort of compile tests to run",
85aaf69f 72 "(compile-fail|parse-fail|run-fail|run-pass|run-pass-valgrind|pretty|debug-info)"),
1a4d82fc
JJ
73 optflag("", "ignored", "run tests marked as ignored"),
74 optopt("", "runtool", "supervisor program to run tests under \
75 (eg. emulator, valgrind)", "PROGRAM"),
76 optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
77 optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
78 optflag("", "verbose", "run tests verbosely, showing all output"),
79 optopt("", "logfile", "file to log test execution to", "FILE"),
1a4d82fc
JJ
80 optopt("", "target", "the target to build for", "TARGET"),
81 optopt("", "host", "the host to build for", "HOST"),
82 optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"),
83 optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"),
84 optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
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("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"),
1a4d82fc 88 optflag("h", "help", "show this message"));
970d7e83 89
c1a9b12d 90 let (argv0, args_) = args.split_first().unwrap();
b039eaaf 91 if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
1a4d82fc 92 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
85aaf69f 93 println!("{}", getopts::usage(&message, &groups));
1a4d82fc
JJ
94 println!("");
95 panic!()
96 }
97
970d7e83 98 let matches =
85aaf69f 99 &match getopts::getopts(args_, &groups) {
970d7e83 100 Ok(m) => m,
1a4d82fc 101 Err(f) => panic!("{:?}", f)
970d7e83
LB
102 };
103
1a4d82fc
JJ
104 if matches.opt_present("h") || matches.opt_present("help") {
105 let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
85aaf69f 106 println!("{}", getopts::usage(&message, &groups));
1a4d82fc
JJ
107 println!("");
108 panic!()
109 }
110
c34b1796 111 fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
85aaf69f 112 match m.opt_str(nm) {
c34b1796 113 Some(s) => PathBuf::from(&s),
85aaf69f
SL
114 None => panic!("no option (=path) found for {}", nm),
115 }
970d7e83
LB
116 }
117
1a4d82fc 118 let filter = if !matches.free.is_empty() {
85aaf69f 119 Some(matches.free[0].clone())
1a4d82fc
JJ
120 } else {
121 None
122 };
123
124 Config {
125 compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
126 run_lib_path: matches.opt_str("run-lib-path").unwrap(),
970d7e83 127 rustc_path: opt_path(matches, "rustc-path"),
9346a6ac
AL
128 rustdoc_path: opt_path(matches, "rustdoc-path"),
129 python: matches.opt_str("python").unwrap(),
1a4d82fc
JJ
130 valgrind_path: matches.opt_str("valgrind-path"),
131 force_valgrind: matches.opt_present("force-valgrind"),
c34b1796 132 llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)),
970d7e83
LB
133 src_base: opt_path(matches, "src-base"),
134 build_base: opt_path(matches, "build-base"),
135 aux_base: opt_path(matches, "aux-base"),
1a4d82fc 136 stage_id: matches.opt_str("stage-id").unwrap(),
85aaf69f 137 mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
1a4d82fc
JJ
138 run_ignored: matches.opt_present("ignored"),
139 filter: filter,
c34b1796 140 logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
1a4d82fc
JJ
141 runtool: matches.opt_str("runtool"),
142 host_rustcflags: matches.opt_str("host-rustcflags"),
143 target_rustcflags: matches.opt_str("target-rustcflags"),
1a4d82fc
JJ
144 target: opt_str2(matches.opt_str("target")),
145 host: opt_str2(matches.opt_str("host")),
146 gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
147 lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
148 android_cross_path: opt_path(matches, "android-cross-path"),
149 adb_path: opt_str2(matches.opt_str("adb-path")),
85aaf69f
SL
150 adb_test_dir: format!("{}/{}",
151 opt_str2(matches.opt_str("adb-test-dir")),
152 opt_str2(matches.opt_str("target"))),
970d7e83 153 adb_device_status:
85aaf69f
SL
154 opt_str2(matches.opt_str("target")).contains("android") &&
155 "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
1a4d82fc
JJ
156 !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
157 lldb_python_dir: matches.opt_str("lldb-python-dir"),
1a4d82fc 158 verbose: matches.opt_present("verbose"),
970d7e83
LB
159 }
160}
161
1a4d82fc 162pub fn log_config(config: &Config) {
970d7e83 163 let c = config;
1a4d82fc
JJ
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()));
9346a6ac 168 logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path.display()));
1a4d82fc
JJ
169 logv(c, format!("src_base: {:?}", config.src_base.display()));
170 logv(c, format!("build_base: {:?}", config.build_base.display()));
171 logv(c, format!("stage_id: {}", config.stage_id));
172 logv(c, format!("mode: {}", config.mode));
173 logv(c, format!("run_ignored: {}", config.run_ignored));
174 logv(c, format!("filter: {}",
175 opt_str(&config.filter
176 .as_ref()
e9174d1e 177 .map(|re| re.to_owned()))));
1a4d82fc
JJ
178 logv(c, format!("runtool: {}", opt_str(&config.runtool)));
179 logv(c, format!("host-rustcflags: {}",
180 opt_str(&config.host_rustcflags)));
181 logv(c, format!("target-rustcflags: {}",
182 opt_str(&config.target_rustcflags)));
1a4d82fc
JJ
183 logv(c, format!("target: {}", config.target));
184 logv(c, format!("host: {}", config.host));
185 logv(c, format!("android-cross-path: {:?}",
186 config.android_cross_path.display()));
187 logv(c, format!("adb_path: {:?}", config.adb_path));
188 logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
189 logv(c, format!("adb_device_status: {}",
190 config.adb_device_status));
1a4d82fc
JJ
191 logv(c, format!("verbose: {}", config.verbose));
192 logv(c, format!("\n"));
970d7e83
LB
193}
194
1a4d82fc 195pub fn opt_str<'a>(maybestr: &'a Option<String>) -> &'a str {
970d7e83 196 match *maybestr {
1a4d82fc 197 None => "(none)",
85aaf69f 198 Some(ref s) => s,
970d7e83
LB
199 }
200}
201
1a4d82fc
JJ
202pub fn opt_str2(maybestr: Option<String>) -> String {
203 match maybestr {
e9174d1e 204 None => "(none)".to_owned(),
1a4d82fc
JJ
205 Some(s) => s,
206 }
970d7e83
LB
207}
208
1a4d82fc 209pub fn run_tests(config: &Config) {
85aaf69f 210 if config.target.contains("android") {
e9174d1e
SL
211 if let DebugInfoGdb = config.mode {
212 println!("{} debug-info test uses tcp 5039 port.\
213 please reserve it", config.target);
1a4d82fc 214 }
970d7e83 215
85aaf69f 216 // android debug-info test uses remote debugger
bd371182 217 // so, we test 1 thread at once.
1a4d82fc 218 // also trying to isolate problems with adb_run_wrapper.sh ilooping
c34b1796 219 env::set_var("RUST_TEST_THREADS","1");
970d7e83 220 }
970d7e83 221
1a4d82fc
JJ
222 match config.mode {
223 DebugInfoLldb => {
224 // Some older versions of LLDB seem to have problems with multiple
bd371182 225 // instances running in parallel, so only run one test thread at a
1a4d82fc 226 // time.
c34b1796 227 env::set_var("RUST_TEST_THREADS", "1");
1a4d82fc
JJ
228 }
229 _ => { /* proceed */ }
970d7e83 230 }
970d7e83 231
970d7e83
LB
232 let opts = test_opts(config);
233 let tests = make_tests(config);
1a4d82fc
JJ
234 // sadly osx needs some file descriptor limits raised for running tests in
235 // parallel (especially when we have lots and lots of child processes).
236 // For context, see #8904
9346a6ac 237 unsafe { raise_fd_limit::raise_fd_limit(); }
85aaf69f
SL
238 // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
239 // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
240 env::set_var("__COMPAT_LAYER", "RunAsInvoker");
1a4d82fc
JJ
241 let res = test::run_tests_console(&opts, tests.into_iter().collect());
242 match res {
243 Ok(true) => {}
244 Ok(false) => panic!("Some tests failed"),
245 Err(e) => {
246 println!("I/O failure during tests: {:?}", e);
247 }
248 }
970d7e83
LB
249}
250
1a4d82fc 251pub fn test_opts(config: &Config) -> test::TestOpts {
970d7e83 252 test::TestOpts {
1a4d82fc
JJ
253 filter: match config.filter {
254 None => None,
255 Some(ref filter) => Some(filter.clone()),
256 },
970d7e83 257 run_ignored: config.run_ignored,
1a4d82fc 258 logfile: config.logfile.clone(),
970d7e83 259 run_tests: true,
d9579d0f 260 bench_benchmarks: true,
c34b1796 261 nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
1a4d82fc 262 color: test::AutoColor,
970d7e83
LB
263 }
264}
265
1a4d82fc
JJ
266pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
267 debug!("making tests from {:?}",
268 config.src_base.display());
269 let mut tests = Vec::new();
c34b1796
AL
270 let dirs = fs::read_dir(&config.src_base).unwrap();
271 for file in dirs {
272 let file = file.unwrap().path();
1a4d82fc
JJ
273 debug!("inspecting file {:?}", file.display());
274 if is_test(config, &file) {
62682a34 275 tests.push(make_test(config, &file))
970d7e83
LB
276 }
277 }
278 tests
279}
280
1a4d82fc 281pub fn is_test(config: &Config, testfile: &Path) -> bool {
970d7e83
LB
282 // Pretty-printer does not work with .rc files yet
283 let valid_extensions =
284 match config.mode {
e9174d1e
SL
285 Pretty => vec!(".rs".to_owned()),
286 _ => vec!(".rc".to_owned(), ".rs".to_owned())
970d7e83 287 };
e9174d1e 288 let invalid_prefixes = vec!(".".to_owned(), "#".to_owned(), "~".to_owned());
c34b1796 289 let name = testfile.file_name().unwrap().to_str().unwrap();
970d7e83
LB
290
291 let mut valid = false;
292
85aaf69f
SL
293 for ext in &valid_extensions {
294 if name.ends_with(ext) {
1a4d82fc
JJ
295 valid = true;
296 }
970d7e83
LB
297 }
298
85aaf69f
SL
299 for pre in &invalid_prefixes {
300 if name.starts_with(pre) {
1a4d82fc
JJ
301 valid = false;
302 }
970d7e83
LB
303 }
304
305 return valid;
306}
307
62682a34 308pub fn make_test(config: &Config, testfile: &Path) -> test::TestDescAndFn
1a4d82fc 309{
970d7e83
LB
310 test::TestDescAndFn {
311 desc: test::TestDesc {
312 name: make_test_name(config, testfile),
313 ignore: header::is_test_ignored(config, testfile),
c34b1796 314 should_panic: test::ShouldPanic::No,
970d7e83 315 },
62682a34 316 testfn: make_test_closure(config, &testfile),
970d7e83
LB
317 }
318}
319
1a4d82fc 320pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
970d7e83
LB
321
322 // Try to elide redundant long paths
1a4d82fc 323 fn shorten(path: &Path) -> String {
c34b1796
AL
324 let filename = path.file_name().unwrap().to_str();
325 let p = path.parent().unwrap();
326 let dir = p.file_name().unwrap().to_str();
1a4d82fc 327 format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
970d7e83
LB
328 }
329
1a4d82fc 330 test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
970d7e83
LB
331}
332
1a4d82fc
JJ
333pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
334 let config = (*config).clone();
c34b1796
AL
335 let testfile = testfile.to_path_buf();
336 test::DynTestFn(Box::new(move || {
337 runtest::run(config, &testfile)
1a4d82fc
JJ
338 }))
339}
340
1a4d82fc
JJ
341fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
342 match full_version_line {
343 Some(ref full_version_line)
9346a6ac 344 if !full_version_line.trim().is_empty() => {
85aaf69f
SL
345 let full_version_line = full_version_line.trim();
346
b039eaaf 347 // used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)"
85aaf69f
SL
348 for (pos, c) in full_version_line.char_indices() {
349 if !c.is_digit(10) { continue }
350 if pos + 2 >= full_version_line.len() { continue }
351 if full_version_line.char_at(pos + 1) != '.' { continue }
352 if !full_version_line.char_at(pos + 2).is_digit(10) { continue }
353 if pos > 0 && full_version_line.char_at_reverse(pos).is_digit(10) {
354 continue
1a4d82fc 355 }
b039eaaf
SL
356 let mut end = pos + 3;
357 while end < full_version_line.len() &&
358 full_version_line.char_at(end).is_digit(10) {
359 end += 1;
1a4d82fc 360 }
b039eaaf 361 return Some(full_version_line[pos..end].to_owned());
1a4d82fc 362 }
85aaf69f
SL
363 println!("Could not extract GDB version from line '{}'",
364 full_version_line);
365 None
1a4d82fc
JJ
366 },
367 _ => None
368 }
369}
370
371fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
372 // Extract the major LLDB version from the given version string.
373 // LLDB version strings are different for Apple and non-Apple platforms.
374 // At the moment, this function only supports the Apple variant, which looks
375 // like this:
376 //
377 // LLDB-179.5 (older versions)
378 // lldb-300.2.51 (new versions)
379 //
380 // We are only interested in the major version number, so this function
381 // will return `Some("179")` and `Some("300")` respectively.
382
e9174d1e
SL
383 if let Some(ref full_version_line) = full_version_line {
384 if !full_version_line.trim().is_empty() {
85aaf69f
SL
385 let full_version_line = full_version_line.trim();
386
387 for (pos, l) in full_version_line.char_indices() {
388 if l != 'l' && l != 'L' { continue }
389 if pos + 5 >= full_version_line.len() { continue }
390 let l = full_version_line.char_at(pos + 1);
391 if l != 'l' && l != 'L' { continue }
392 let d = full_version_line.char_at(pos + 2);
393 if d != 'd' && d != 'D' { continue }
394 let b = full_version_line.char_at(pos + 3);
395 if b != 'b' && b != 'B' { continue }
396 let dash = full_version_line.char_at(pos + 4);
397 if dash != '-' { continue }
398
399 let vers = full_version_line[pos + 5..].chars().take_while(|c| {
400 c.is_digit(10)
401 }).collect::<String>();
9346a6ac 402 if !vers.is_empty() { return Some(vers) }
1a4d82fc 403 }
85aaf69f
SL
404 println!("Could not extract LLDB version from line '{}'",
405 full_version_line);
e9174d1e 406 }
1a4d82fc 407 }
e9174d1e 408 None
970d7e83 409}