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.
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.
11 #![crate_type = "lib"]
13 #![cfg_attr(feature = "rustc", feature(rustc_private))]
14 #![cfg_attr(feature = "rustc", feature(test))]
16 #![deny(unused_imports)]
18 #[cfg(feature = "rustc")]
19 extern crate rustc_session
;
23 #[cfg(feature = "rustc")]
25 #[cfg(not(feature = "rustc"))]
26 extern crate tester
as test
;
28 #[cfg(feature = "tmp")] extern crate tempfile;
33 extern crate filetime
;
35 extern crate serde_json
;
37 extern crate serde_derive
;
41 use std
::ffi
::OsString
;
44 use std
::path
::{Path, PathBuf}
;
45 use common
::{Mode, TestPaths}
;
46 use common
::{Pretty, DebugInfoGdb, DebugInfoLldb}
;
48 use self::header
::EarlyProps
;
59 pub use common
::Config
;
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
);
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");
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
78 env
::set_var("RUST_TEST_TASKS", "1");
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
)
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());
105 Ok(false) => panic
!("Some tests failed"),
107 println
!("I/O failure during tests: {:?}", e
);
112 pub fn test_opts(config
: &Config
) -> 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(),
122 bench_benchmarks
: true,
123 nocapture
: match env
::var("RUST_TEST_NOCAPTURE") {
124 Ok(val
) => &val
!= "0",
127 color
: test
::AutoColor
,
131 options
: test
::Options
::new(),
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
,
149 fn collect_tests_from_dir(config
: &Config
,
152 relative_dir_path
: &Path
,
153 tests
: &mut Vec
<test
::TestDescAndFn
>)
155 // Ignore directories that contain a file
156 // `compiletest-ignore-dir`.
157 for file
in fs
::read_dir(dir
)?
{
159 let name
= file
.file_name();
160 if name
== *"compiletest-ignore-dir" {
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(),
169 tests
.push(make_test(config
, &paths
));
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();
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
)?
;
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();
200 let paths
= TestPaths
{
202 base
: base
.to_path_buf(),
203 relative_dir
: relative_dir_path
.to_path_buf(),
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
214 let build_dir
= config
.build_base
.join(&relative_file_path
);
215 fs
::create_dir_all(&build_dir
).unwrap();
217 debug
!("found directory: {:?}", file_path
.display());
218 collect_tests_from_dir(config
,
225 debug
!("found other file/directory: {:?}", file_path
.display());
231 pub fn is_test(file_name
: &OsString
) -> bool
{
232 let file_name
= file_name
.to_str().unwrap();
234 if !file_name
.ends_with(".rs") {
238 // `.`, `#`, and `~` are common temp-file prefixes.
239 let invalid_prefixes
= &[".", "#", "~"];
240 !invalid_prefixes
.iter().any(|p
| file_name
.starts_with(p
))
243 pub fn make_test(config
: &Config
, testpaths
: &TestPaths
) -> test
::TestDescAndFn
{
244 let early_props
= EarlyProps
::from_file(config
, &testpaths
.file
);
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
254 test
::ShouldPanic
::No
258 test
::TestDescAndFn
{
259 desc
: test
::TestDesc
{
260 name
: make_test_name(config
, testpaths
),
261 ignore
: early_props
.ignore
,
262 should_panic
: should_panic
,
264 #[cfg(feature = "rustc")]
266 #[cfg(feature = "rustc")]
268 test_type
: test
::TestType
::IntegrationTest
,
270 testfn
: make_test_closure(config
, testpaths
),
274 fn stamp(config
: &Config
, testpaths
: &TestPaths
) -> PathBuf
{
275 let stamp_name
= format
!("{}-{}.stamp",
276 testpaths
.file
.file_name().unwrap()
279 config
.build_base
.canonicalize()
280 .unwrap_or_else(|_
| config
.build_base
.clone())
284 pub fn make_test_name(config
: &Config
, testpaths
: &TestPaths
) -> test
::TestName
{
285 // Convert a complete path to something like
287 // run-pass/foo/bar/baz.rs
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()))
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
)
304 fn extract_gdb_version(full_version_line
: &str) -> Option
<u32> {
305 let full_version_line
= full_version_line
.trim();
307 // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
308 // of the ? sections being optional
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
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);
321 prev_was_digit
= true;
323 let line
= &full_version_line
[pos
..];
325 let next_split
= match line
.find(|c
: char| !c
.is_digit(10)) {
327 None
=> continue, // no minor version
330 if line
.as_bytes()[next_split
] != b'
.'
{
331 continue; // no minor version
334 let major
= &line
[..next_split
];
335 let line
= &line
[next_split
+ 1..];
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..];
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) }
;
346 (&line
[..idx
], patch
)
350 None
=> (line
, None
),
353 if major
.len() != 1 || minor
.is_empty() {
357 let major
: u32 = major
.parse().unwrap();
358 let minor
: u32 = minor
.parse().unwrap();
359 let patch
: u32 = patch
.unwrap_or("0").parse().unwrap();
361 return Some(((major
* 1000) + minor
) * 1000 + patch
);
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
374 // LLDB-179.5 (older versions)
375 // lldb-300.2.51 (new versions)
377 // We are only interested in the major version number, so this function
378 // will return `Some("179")` and `Some("300")` respectively.
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();
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 }
396 let vers
= full_version_line
[pos
+ 5..].chars().take_while(|c
| {
398 }).collect
::<String
>();
399 if !vers
.is_empty() { return Some(vers) }
401 println
!("Could not extract LLDB version from line '{}'",
409 fn is_blacklisted_lldb_version(version
: &str) -> bool
{