diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /vendor/compiletest_rs/src/lib.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/compiletest_rs/src/lib.rs')
-rw-r--r-- | vendor/compiletest_rs/src/lib.rs | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/vendor/compiletest_rs/src/lib.rs b/vendor/compiletest_rs/src/lib.rs new file mode 100644 index 000000000..edfc0208d --- /dev/null +++ b/vendor/compiletest_rs/src/lib.rs @@ -0,0 +1,458 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#![cfg_attr(feature = "rustc", feature(rustc_private))] +#![cfg_attr(feature = "rustc", feature(test))] +#![deny(unused_imports)] + +#[cfg(feature = "rustc")] +extern crate rustc_session; + +#[cfg(unix)] +extern crate libc; +#[cfg(feature = "rustc")] +extern crate test; +#[cfg(not(feature = "rustc"))] +extern crate tester as test; + +#[cfg(feature = "tmp")] +extern crate tempfile; + +#[macro_use] +extern crate log; +extern crate diff; +extern crate filetime; +extern crate regex; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; +extern crate rustfix; + +use common::{DebugInfoGdb, DebugInfoLldb, Pretty}; +use common::{Mode, TestPaths}; +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +use self::header::EarlyProps; + +pub mod common; +pub mod errors; +pub mod header; +mod json; +mod read2; +pub mod runtest; +pub mod uidiff; +pub mod util; + +pub use common::Config; + +pub fn run_tests(config: &Config) { + if config.target.contains("android") { + if let DebugInfoGdb = config.mode { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + } + + // android debug-info test uses remote debugger + // so, we test 1 thread at once. + // also trying to isolate problems with adb_run_wrapper.sh ilooping + env::set_var("RUST_TEST_THREADS", "1"); + } + + if let DebugInfoLldb = config.mode { + // Some older versions of LLDB seem to have problems with multiple + // instances running in parallel, so only run one test task at a + // time. + env::set_var("RUST_TEST_TASKS", "1"); + } + + // If we want to collect rustfix coverage information, + // we first make sure that the coverage file does not exist. + // It will be created later on. + if config.rustfix_coverage { + let mut coverage_file_path = config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + if coverage_file_path.exists() { + if let Err(e) = fs::remove_file(&coverage_file_path) { + panic!( + "Could not delete {} due to {}", + coverage_file_path.display(), + e + ) + } + } + } + let opts = test_opts(config); + let tests = make_tests(config); + // sadly osx needs some file descriptor limits raised for running tests in + // parallel (especially when we have lots and lots of child processes). + // For context, see #8904 + // unsafe { raise_fd_limit::raise_fd_limit(); } + // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows + // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary + env::set_var("__COMPAT_LAYER", "RunAsInvoker"); + let res = test::run_tests_console(&opts, tests.into_iter().collect()); + match res { + Ok(true) => {} + Ok(false) => panic!("Some tests failed"), + Err(e) => { + println!("I/O failure during tests: {:?}", e); + } + } +} + +pub fn test_opts(config: &Config) -> test::TestOpts { + test::TestOpts { + filters: config.filters.clone(), + filter_exact: config.filter_exact, + exclude_should_panic: false, + force_run_in_process: false, + run_ignored: if config.run_ignored { + test::RunIgnored::Yes + } else { + test::RunIgnored::No + }, + format: if config.quiet { + test::OutputFormat::Terse + } else { + test::OutputFormat::Pretty + }, + logfile: config.logfile.clone(), + run_tests: true, + bench_benchmarks: true, + nocapture: match env::var("RUST_TEST_NOCAPTURE") { + Ok(val) => &val != "0", + Err(_) => false, + }, + color: test::AutoColor, + test_threads: None, + skip: vec![], + list: false, + options: test::Options::new(), + time_options: None, + #[cfg(feature = "rustc")] + shuffle: false, + #[cfg(feature = "rustc")] + shuffle_seed: None, + } +} + +pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> { + debug!("making tests from {:?}", config.src_base.display()); + let mut tests = Vec::new(); + collect_tests_from_dir( + config, + &config.src_base, + &config.src_base, + &PathBuf::new(), + &mut tests, + ) + .unwrap(); + tests +} + +fn collect_tests_from_dir( + config: &Config, + base: &Path, + dir: &Path, + relative_dir_path: &Path, + tests: &mut Vec<test::TestDescAndFn>, +) -> io::Result<()> { + // Ignore directories that contain a file + // `compiletest-ignore-dir`. + for file in fs::read_dir(dir)? { + let file = file?; + let name = file.file_name(); + if name == *"compiletest-ignore-dir" { + return Ok(()); + } + if name == *"Makefile" && config.mode == Mode::RunMake { + let paths = TestPaths { + file: dir.to_path_buf(), + base: base.to_path_buf(), + relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), + }; + tests.push(make_test(config, &paths)); + return Ok(()); + } + } + + // If we find a test foo/bar.rs, we have to build the + // output directory `$build/foo` so we can write + // `$build/foo/bar` into it. We do this *now* in this + // sequential loop because otherwise, if we do it in the + // tests themselves, they race for the privilege of + // creating the directories and sometimes fail randomly. + let build_dir = config.build_base.join(&relative_dir_path); + fs::create_dir_all(&build_dir).unwrap(); + + // Add each `.rs` file as a test, and recurse further on any + // subdirectories we find, except for `aux` directories. + let dirs = fs::read_dir(dir)?; + for file in dirs { + let file = file?; + let file_path = file.path(); + let file_name = file.file_name(); + if is_test(&file_name) { + debug!("found test file: {:?}", file_path.display()); + // output directory `$build/foo` so we can write + // `$build/foo/bar` into it. We do this *now* in this + // sequential loop because otherwise, if we do it in the + // tests themselves, they race for the privilege of + // creating the directories and sometimes fail randomly. + let build_dir = config.build_base.join(&relative_dir_path); + fs::create_dir_all(&build_dir).unwrap(); + + let paths = TestPaths { + file: file_path, + base: base.to_path_buf(), + relative_dir: relative_dir_path.to_path_buf(), + }; + tests.push(make_test(config, &paths)) + } else if file_path.is_dir() { + let relative_file_path = relative_dir_path.join(file.file_name()); + if &file_name == "auxiliary" { + // `aux` directories contain other crates used for + // cross-crate tests. Don't search them for tests, but + // do create a directory in the build dir for them, + // since we will dump intermediate output in there + // sometimes. + let build_dir = config.build_base.join(&relative_file_path); + fs::create_dir_all(&build_dir).unwrap(); + } else { + debug!("found directory: {:?}", file_path.display()); + collect_tests_from_dir(config, base, &file_path, &relative_file_path, tests)?; + } + } else { + debug!("found other file/directory: {:?}", file_path.display()); + } + } + Ok(()) +} + +pub fn is_test(file_name: &OsString) -> bool { + let file_name = file_name.to_str().unwrap(); + + if !file_name.ends_with(".rs") { + return false; + } + + // `.`, `#`, and `~` are common temp-file prefixes. + let invalid_prefixes = &[".", "#", "~"]; + !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) +} + +pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn { + let early_props = EarlyProps::from_file(config, &testpaths.file); + + // The `should-fail` annotation doesn't apply to pretty tests, + // since we run the pretty printer across all tests by default. + // If desired, we could add a `should-fail-pretty` annotation. + let should_panic = match config.mode { + Pretty => test::ShouldPanic::No, + _ => { + if early_props.should_fail { + test::ShouldPanic::Yes + } else { + test::ShouldPanic::No + } + } + }; + + test::TestDescAndFn { + desc: test::TestDesc { + name: make_test_name(config, testpaths), + ignore: early_props.ignore, + should_panic: should_panic, + #[cfg(not(feature = "rustc"))] + allow_fail: false, + #[cfg(feature = "rustc")] + compile_fail: false, + #[cfg(feature = "rustc")] + no_run: false, + test_type: test::TestType::IntegrationTest, + #[cfg(feature = "rustc")] + ignore_message: None, + }, + testfn: make_test_closure(config, testpaths), + } +} + +fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf { + let stamp_name = format!( + "{}-{}.stamp", + testpaths.file.file_name().unwrap().to_str().unwrap(), + config.stage_id + ); + config + .build_base + .canonicalize() + .unwrap_or_else(|_| config.build_base.clone()) + .join(stamp_name) +} + +pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName { + // Convert a complete path to something like + // + // run-pass/foo/bar/baz.rs + let path = PathBuf::from(config.src_base.file_name().unwrap()) + .join(&testpaths.relative_dir) + .join(&testpaths.file.file_name().unwrap()); + test::DynTestName(format!("[{}] {}", config.mode, path.display())) +} + +pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn { + let config = config.clone(); + let testpaths = testpaths.clone(); + test::DynTestFn(Box::new(move || { + let config = config.clone(); // FIXME: why is this needed? + runtest::run(config, &testpaths) + })) +} + +fn extract_gdb_version(full_version_line: &str) -> Option<u32> { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for minor and patch, ignoring the date + // We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version + + // don't start parsing in the middle of a number + let mut prev_was_digit = false; + for (pos, c) in full_version_line.char_indices() { + if prev_was_digit || !c.is_digit(10) { + prev_was_digit = c.is_digit(10); + continue; + } + + prev_was_digit = true; + + let line = &full_version_line[pos..]; + + let next_split = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => idx, + None => continue, // no minor version + }; + + if line.as_bytes()[next_split] != b'.' { + continue; // no minor version + } + + let major = &line[..next_split]; + let line = &line[next_split + 1..]; + + let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => { + if line.as_bytes()[idx] == b'.' { + let patch = &line[idx + 1..]; + + let patch_len = patch + .find(|c: char| !c.is_digit(10)) + .unwrap_or_else(|| patch.len()); + let patch = &patch[..patch_len]; + let patch = if patch_len > 3 || patch_len == 0 { + None + } else { + Some(patch) + }; + + (&line[..idx], patch) + } else { + (&line[..idx], None) + } + } + None => (line, None), + }; + + if major.len() != 1 || minor.is_empty() { + continue; + } + + let major: u32 = major.parse().unwrap(); + let minor: u32 = minor.parse().unwrap(); + let patch: u32 = patch.unwrap_or("0").parse().unwrap(); + + return Some(((major * 1000) + minor) * 1000 + patch); + } + + None +} + +#[allow(dead_code)] +fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> { + // Extract the major LLDB version from the given version string. + // LLDB version strings are different for Apple and non-Apple platforms. + // At the moment, this function only supports the Apple variant, which looks + // like this: + // + // LLDB-179.5 (older versions) + // lldb-300.2.51 (new versions) + // + // We are only interested in the major version number, so this function + // will return `Some("179")` and `Some("300")` respectively. + + if let Some(ref full_version_line) = full_version_line { + if !full_version_line.trim().is_empty() { + let full_version_line = full_version_line.trim(); + + for (pos, l) in full_version_line.char_indices() { + if l != 'l' && l != 'L' { + continue; + } + if pos + 5 >= full_version_line.len() { + continue; + } + let l = full_version_line[pos + 1..].chars().next().unwrap(); + if l != 'l' && l != 'L' { + continue; + } + let d = full_version_line[pos + 2..].chars().next().unwrap(); + if d != 'd' && d != 'D' { + continue; + } + let b = full_version_line[pos + 3..].chars().next().unwrap(); + if b != 'b' && b != 'B' { + continue; + } + let dash = full_version_line[pos + 4..].chars().next().unwrap(); + if dash != '-' { + continue; + } + + let vers = full_version_line[pos + 5..] + .chars() + .take_while(|c| c.is_digit(10)) + .collect::<String>(); + if !vers.is_empty() { + return Some(vers); + } + } + println!( + "Could not extract LLDB version from line '{}'", + full_version_line + ); + } + } + None +} + +#[allow(dead_code)] +fn is_blacklisted_lldb_version(version: &str) -> bool { + version == "350" +} |