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