]> git.proxmox.com Git - rustc.git/blame - src/vendor/compiletest_rs/src/lib.rs
New upstream version 1.25.0+dfsg1
[rustc.git] / src / vendor / compiletest_rs / src / lib.rs
CommitLineData
abe05a73
XL
1// Copyright 2012-2014 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 = "lib"]
12
13#![feature(rustc_private)]
14#![feature(test)]
ff7c6d11 15#![feature(slice_rotate)]
abe05a73
XL
16
17#![deny(unused_imports)]
18
ff7c6d11 19#[cfg(unix)]
abe05a73
XL
20extern crate libc;
21extern crate test;
22extern crate rustc;
23extern crate rustc_serialize;
24
25#[cfg(feature = "tmp")] extern crate tempdir;
26
27#[macro_use]
28extern crate log;
29extern crate filetime;
30extern crate diff;
31
32use std::env;
33use std::ffi::OsString;
34use std::fs;
35use std::io;
36use std::path::{Path, PathBuf};
2c00a5a8 37use common::{Mode, TestPaths};
abe05a73 38use common::{Pretty, DebugInfoGdb, DebugInfoLldb};
abe05a73
XL
39
40use self::header::EarlyProps;
41
42pub mod uidiff;
abe05a73 43pub mod util;
ff7c6d11 44mod json;
abe05a73
XL
45pub mod header;
46pub mod runtest;
47pub mod common;
48pub mod errors;
ff7c6d11 49mod read2;
abe05a73
XL
50
51pub use common::Config;
52
abe05a73
XL
53pub fn run_tests(config: &Config) {
54 if config.target.contains("android") {
55 if let DebugInfoGdb = config.mode {
56 println!("{} debug-info test uses tcp 5039 port.\
57 please reserve it", config.target);
58 }
59
60 // android debug-info test uses remote debugger
61 // so, we test 1 thread at once.
62 // also trying to isolate problems with adb_run_wrapper.sh ilooping
63 env::set_var("RUST_TEST_THREADS","1");
64 }
65
66 if let DebugInfoLldb = config.mode {
67 // Some older versions of LLDB seem to have problems with multiple
68 // instances running in parallel, so only run one test task at a
69 // time.
70 env::set_var("RUST_TEST_TASKS", "1");
71 }
72
73 let opts = test_opts(config);
74 let tests = make_tests(config);
75 // sadly osx needs some file descriptor limits raised for running tests in
76 // parallel (especially when we have lots and lots of child processes).
77 // For context, see #8904
78 // unsafe { raise_fd_limit::raise_fd_limit(); }
79 // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
80 // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
81 env::set_var("__COMPAT_LAYER", "RunAsInvoker");
82 let res = test::run_tests_console(&opts, tests.into_iter().collect());
83 match res {
84 Ok(true) => {}
85 Ok(false) => panic!("Some tests failed"),
86 Err(e) => {
87 println!("I/O failure during tests: {:?}", e);
88 }
89 }
90}
91
92pub fn test_opts(config: &Config) -> test::TestOpts {
93 test::TestOpts {
94 filter: config.filter.clone(),
95 filter_exact: config.filter_exact,
96 run_ignored: config.run_ignored,
2c00a5a8 97 format: if config.quiet { test::OutputFormat::Terse } else { test::OutputFormat::Pretty },
abe05a73
XL
98 logfile: config.logfile.clone(),
99 run_tests: true,
100 bench_benchmarks: true,
101 nocapture: match env::var("RUST_TEST_NOCAPTURE") {
102 Ok(val) => &val != "0",
103 Err(_) => false
104 },
105 color: test::AutoColor,
106 test_threads: None,
107 skip: vec![],
108 list: false,
109 options: test::Options::new(),
110 }
111}
112
113pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
114 debug!("making tests from {:?}",
115 config.src_base.display());
116 let mut tests = Vec::new();
117 collect_tests_from_dir(config,
118 &config.src_base,
119 &config.src_base,
120 &PathBuf::new(),
121 &mut tests)
122 .unwrap();
123 tests
124}
125
126fn collect_tests_from_dir(config: &Config,
127 base: &Path,
128 dir: &Path,
129 relative_dir_path: &Path,
130 tests: &mut Vec<test::TestDescAndFn>)
131 -> io::Result<()> {
132 // Ignore directories that contain a file
133 // `compiletest-ignore-dir`.
134 for file in try!(fs::read_dir(dir)) {
135 let file = try!(file);
136 let name = file.file_name();
137 if name == *"compiletest-ignore-dir" {
138 return Ok(());
139 }
140 if name == *"Makefile" && config.mode == Mode::RunMake {
141 let paths = TestPaths {
142 file: dir.to_path_buf(),
143 base: base.to_path_buf(),
144 relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
145 };
146 tests.push(make_test(config, &paths));
147 return Ok(())
148 }
149 }
150
151 // If we find a test foo/bar.rs, we have to build the
152 // output directory `$build/foo` so we can write
153 // `$build/foo/bar` into it. We do this *now* in this
154 // sequential loop because otherwise, if we do it in the
155 // tests themselves, they race for the privilege of
156 // creating the directories and sometimes fail randomly.
157 let build_dir = config.build_base.join(&relative_dir_path);
158 fs::create_dir_all(&build_dir).unwrap();
159
160 // Add each `.rs` file as a test, and recurse further on any
161 // subdirectories we find, except for `aux` directories.
162 let dirs = try!(fs::read_dir(dir));
163 for file in dirs {
164 let file = try!(file);
165 let file_path = file.path();
166 let file_name = file.file_name();
167 if is_test(&file_name) {
168 debug!("found test file: {:?}", file_path.display());
169 // output directory `$build/foo` so we can write
170 // `$build/foo/bar` into it. We do this *now* in this
171 // sequential loop because otherwise, if we do it in the
172 // tests themselves, they race for the privilege of
173 // creating the directories and sometimes fail randomly.
174 let build_dir = config.build_base.join(&relative_dir_path);
175 fs::create_dir_all(&build_dir).unwrap();
176
177 let paths = TestPaths {
178 file: file_path,
179 base: base.to_path_buf(),
180 relative_dir: relative_dir_path.to_path_buf(),
181 };
182 tests.push(make_test(config, &paths))
183 } else if file_path.is_dir() {
184 let relative_file_path = relative_dir_path.join(file.file_name());
185 if &file_name == "auxiliary" {
186 // `aux` directories contain other crates used for
187 // cross-crate tests. Don't search them for tests, but
188 // do create a directory in the build dir for them,
189 // since we will dump intermediate output in there
190 // sometimes.
191 let build_dir = config.build_base.join(&relative_file_path);
192 fs::create_dir_all(&build_dir).unwrap();
193 } else {
194 debug!("found directory: {:?}", file_path.display());
195 try!(collect_tests_from_dir(config,
196 base,
197 &file_path,
198 &relative_file_path,
199 tests));
200 }
201 } else {
202 debug!("found other file/directory: {:?}", file_path.display());
203 }
204 }
205 Ok(())
206}
207
208pub fn is_test(file_name: &OsString) -> bool {
209 let file_name = file_name.to_str().unwrap();
210
211 if !file_name.ends_with(".rs") {
212 return false;
213 }
214
215 // `.`, `#`, and `~` are common temp-file prefixes.
216 let invalid_prefixes = &[".", "#", "~"];
217 !invalid_prefixes.iter().any(|p| file_name.starts_with(p))
218}
219
220pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn {
221 let early_props = EarlyProps::from_file(config, &testpaths.file);
222
223 // The `should-fail` annotation doesn't apply to pretty tests,
224 // since we run the pretty printer across all tests by default.
225 // If desired, we could add a `should-fail-pretty` annotation.
226 let should_panic = match config.mode {
227 Pretty => test::ShouldPanic::No,
228 _ => if early_props.should_fail {
229 test::ShouldPanic::Yes
230 } else {
231 test::ShouldPanic::No
232 }
233 };
234
235 test::TestDescAndFn {
236 desc: test::TestDesc {
237 name: make_test_name(config, testpaths),
238 ignore: early_props.ignore,
239 should_panic: should_panic,
240 allow_fail: false,
241 },
242 testfn: make_test_closure(config, testpaths),
243 }
244}
245
246fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf {
247 let stamp_name = format!("{}-{}.stamp",
248 testpaths.file.file_name().unwrap()
249 .to_str().unwrap(),
250 config.stage_id);
251 config.build_base.canonicalize()
252 .unwrap_or_else(|_| config.build_base.clone())
253 .join(stamp_name)
254}
255
256pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName {
257 // Convert a complete path to something like
258 //
259 // run-pass/foo/bar/baz.rs
260 let path =
261 PathBuf::from(config.src_base.file_name().unwrap())
262 .join(&testpaths.relative_dir)
263 .join(&testpaths.file.file_name().unwrap());
264 test::DynTestName(format!("[{}] {}", config.mode, path.display()))
265}
266
267pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn {
268 let config = config.clone();
269 let testpaths = testpaths.clone();
2c00a5a8 270 test::DynTestFn(Box::new(move || {
abe05a73
XL
271 runtest::run(config, &testpaths)
272 }))
273}
274
275fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
276 let full_version_line = full_version_line.trim();
277
278 // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
279 // of the ? sections being optional
280
281 // We will parse up to 3 digits for minor and patch, ignoring the date
282 // We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version
283
284 // don't start parsing in the middle of a number
285 let mut prev_was_digit = false;
286 for (pos, c) in full_version_line.char_indices() {
287 if prev_was_digit || !c.is_digit(10) {
288 prev_was_digit = c.is_digit(10);
289 continue
290 }
291
292 prev_was_digit = true;
293
294 let line = &full_version_line[pos..];
295
296 let next_split = match line.find(|c: char| !c.is_digit(10)) {
297 Some(idx) => idx,
298 None => continue, // no minor version
299 };
300
301 if line.as_bytes()[next_split] != b'.' {
302 continue; // no minor version
303 }
304
305 let major = &line[..next_split];
306 let line = &line[next_split + 1..];
307
308 let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
309 Some(idx) => if line.as_bytes()[idx] == b'.' {
310 let patch = &line[idx + 1..];
311
312 let patch_len = patch.find(|c: char| !c.is_digit(10))
313 .unwrap_or_else(|| patch.len());
314 let patch = &patch[..patch_len];
315 let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
316
317 (&line[..idx], patch)
318 } else {
319 (&line[..idx], None)
320 },
321 None => (line, None),
322 };
323
324 if major.len() != 1 || minor.is_empty() {
325 continue;
326 }
327
328 let major: u32 = major.parse().unwrap();
329 let minor: u32 = minor.parse().unwrap();
330 let patch: u32 = patch.unwrap_or("0").parse().unwrap();
331
332 return Some(((major * 1000) + minor) * 1000 + patch);
333 }
334
335 None
336}
337
338#[allow(dead_code)]
339fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
340 // Extract the major LLDB version from the given version string.
341 // LLDB version strings are different for Apple and non-Apple platforms.
342 // At the moment, this function only supports the Apple variant, which looks
343 // like this:
344 //
345 // LLDB-179.5 (older versions)
346 // lldb-300.2.51 (new versions)
347 //
348 // We are only interested in the major version number, so this function
349 // will return `Some("179")` and `Some("300")` respectively.
350
351 if let Some(ref full_version_line) = full_version_line {
352 if !full_version_line.trim().is_empty() {
353 let full_version_line = full_version_line.trim();
354
355 for (pos, l) in full_version_line.char_indices() {
356 if l != 'l' && l != 'L' { continue }
357 if pos + 5 >= full_version_line.len() { continue }
358 let l = full_version_line[pos + 1..].chars().next().unwrap();
359 if l != 'l' && l != 'L' { continue }
360 let d = full_version_line[pos + 2..].chars().next().unwrap();
361 if d != 'd' && d != 'D' { continue }
362 let b = full_version_line[pos + 3..].chars().next().unwrap();
363 if b != 'b' && b != 'B' { continue }
364 let dash = full_version_line[pos + 4..].chars().next().unwrap();
365 if dash != '-' { continue }
366
367 let vers = full_version_line[pos + 5..].chars().take_while(|c| {
368 c.is_digit(10)
369 }).collect::<String>();
370 if !vers.is_empty() { return Some(vers) }
371 }
372 println!("Could not extract LLDB version from line '{}'",
373 full_version_line);
374 }
375 }
376 None
377}
378
379#[allow(dead_code)]
380fn is_blacklisted_lldb_version(version: &str) -> bool {
381 version == "350"
382}