From 4c2a5f857a6bfb626d63045a00a4b90293c3d5aa Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 1 Feb 2020 11:04:04 +0100 Subject: [PATCH] compile-test: Handle CARGO_TARGET_DIR and transitive deps --- tests/cargo/mod.rs | 75 +++++++++++++++++++++++++++++++ tests/compile-test.rs | 102 +++++++++++++----------------------------- 2 files changed, 106 insertions(+), 71 deletions(-) create mode 100644 tests/cargo/mod.rs diff --git a/tests/cargo/mod.rs b/tests/cargo/mod.rs new file mode 100644 index 00000000000..080c5aa8977 --- /dev/null +++ b/tests/cargo/mod.rs @@ -0,0 +1,75 @@ +use cargo_metadata::{Message::CompilerArtifact, MetadataCommand}; +use std::env; +use std::ffi::OsStr; +use std::mem; +use std::path::PathBuf; +use std::process::Command; + +pub struct BuildInfo { + cargo_target_dir: PathBuf, +} + +impl BuildInfo { + pub fn new() -> Self { + let data = MetadataCommand::new().exec().unwrap(); + Self { + cargo_target_dir: data.target_directory, + } + } + + pub fn host_lib(&self) -> PathBuf { + if let Some(path) = option_env!("HOST_LIBS") { + PathBuf::from(path) + } else { + self.cargo_target_dir.join(env!("PROFILE")) + } + } + + pub fn target_lib(&self) -> PathBuf { + if let Some(path) = option_env!("TARGET_LIBS") { + path.into() + } else { + let mut dir = self.cargo_target_dir.clone(); + if let Some(target) = env::var_os("CARGO_BUILD_TARGET") { + dir.push(target); + } + dir.push(env!("PROFILE")); + dir + } + } + + pub fn clippy_driver_path(&self) -> PathBuf { + if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { + PathBuf::from(path) + } else { + self.target_lib().join("clippy-driver") + } + } + + // When we'll want to use `extern crate ..` for a dependency that is used + // both by the crate and the compiler itself, we can't simply pass -L flags + // as we'll get a duplicate matching versions. Instead, disambiguate with + // `--extern dep=path`. + // See https://github.com/rust-lang/rust-clippy/issues/4015. + pub fn third_party_crates() -> Vec<(&'static str, PathBuf)> { + const THIRD_PARTY_CRATES: [&str; 3] = ["serde", "regex", "clippy_lints"]; + let cargo = env::var_os("CARGO"); + let cargo = cargo.as_deref().unwrap_or_else(|| OsStr::new("cargo")); + let output = Command::new(cargo) + .arg("build") + .arg("--test=compile-test") + .arg("--message-format=json") + .output() + .unwrap(); + + let mut crates = Vec::with_capacity(THIRD_PARTY_CRATES.len()); + for message in cargo_metadata::parse_messages(output.stdout.as_slice()) { + if let CompilerArtifact(mut artifact) = message.unwrap() { + if let Some(&krate) = THIRD_PARTY_CRATES.iter().find(|&&krate| krate == artifact.target.name) { + crates.push((krate, mem::take(&mut artifact.filenames[0]))); + } + } + } + crates + } +} diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 5c05e74dcb6..7cfbfcf16a9 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,36 +1,15 @@ #![feature(test)] use compiletest_rs as compiletest; -extern crate tester as test; +use compiletest_rs::common::Mode as TestMode; -use std::env::{set_var, var}; +use std::env::{self, set_var}; use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; -#[must_use] -fn clippy_driver_path() -> PathBuf { - if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { - PathBuf::from(path) - } else { - PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver")) - } -} - -#[must_use] -fn host_libs() -> PathBuf { - if let Some(path) = option_env!("HOST_LIBS") { - PathBuf::from(path) - } else { - Path::new("target").join(env!("PROFILE")) - } -} - -#[must_use] -fn target_libs() -> Option { - option_env!("TARGET_LIBS").map(PathBuf::from) -} +mod cargo; #[must_use] fn rustc_test_suite() -> Option { @@ -42,73 +21,52 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn config(mode: &str, dir: PathBuf) -> compiletest::Config { +fn default_config() -> compiletest::Config { + let build_info = cargo::BuildInfo::new(); let mut config = compiletest::Config::default(); - let cfg_mode = mode.parse().expect("Invalid mode"); - if let Ok(name) = var::<&str>("TESTNAME") { - config.filter = Some(name) + if let Ok(name) = env::var("TESTNAME") { + config.filter = Some(name); } if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); + let path = rustc_lib_path(); + config.run_lib_path = path.clone(); + config.compile_lib_path = path; } - // When we'll want to use `extern crate ..` for a dependency that is used - // both by the crate and the compiler itself, we can't simply pass -L flags - // as we'll get a duplicate matching versions. Instead, disambiguate with - // `--extern dep=path`. - // See https://github.com/rust-lang/rust-clippy/issues/4015. - let needs_disambiguation = ["serde", "regex", "clippy_lints"]; - // This assumes that deps are compiled (they are for Cargo integration tests). - let deps = fs::read_dir(target_libs().unwrap_or_else(host_libs).join("deps")).unwrap(); - let disambiguated = deps - .filter_map(|dep| { - let path = dep.ok()?.path(); - let name = path.file_name()?.to_string_lossy(); - // NOTE: This only handles a single dep - // https://github.com/laumann/compiletest-rs/issues/101 - needs_disambiguation.iter().find_map(|dep| { - if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") { - Some(format!("--extern {}={}", dep, path.display())) - } else { - None - } - }) - }) - .collect::>(); + let disambiguated: Vec<_> = cargo::BuildInfo::third_party_crates() + .iter() + .map(|(krate, path)| format!("--extern {}={}", krate, path.display())) + .collect(); config.target_rustcflags = Some(format!( - "-L {0} -L {0}/deps {1} -Dwarnings -Zui-testing {2}", - host_libs().display(), - target_libs().map_or_else(String::new, |path| format!("-L {0} -L {0}/deps", path.display())), + "-L {0} -L {1} -Dwarnings -Zui-testing {2}", + build_info.host_lib().join("deps").display(), + build_info.target_lib().join("deps").display(), disambiguated.join(" ") )); - config.mode = cfg_mode; config.build_base = if rustc_test_suite().is_some() { // we don't need access to the stderr files on travis let mut path = PathBuf::from(env!("OUT_DIR")); path.push("test_build_base"); path } else { - let mut path = std::env::current_dir().unwrap(); - path.push("target/debug/test_build_base"); - path + build_info.host_lib().join("test_build_base") }; - config.src_base = dir; - config.rustc_path = clippy_driver_path(); + config.rustc_path = build_info.clippy_driver_path(); config } -fn run_mode(mode: &str, dir: PathBuf) { - let cfg = config(mode, dir); +fn run_mode(cfg: &mut compiletest::Config) { + cfg.mode = TestMode::Ui; + cfg.src_base = Path::new("tests").join("ui"); compiletest::run_tests(&cfg); } #[allow(clippy::identity_conversion)] -fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec) -> Result { +fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec) -> Result { let mut result = true; let opts = compiletest::test_opts(config); for dir in fs::read_dir(&config.src_base)? { @@ -137,15 +95,16 @@ fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec