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