Skip to content

Improve compile_test and dogfood tests #5121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions tests/cargo/mod.rs
Original file line number Diff line number Diff line change
@@ -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; 4] = ["serde", "serde_derive", "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
}
}
102 changes: 31 additions & 71 deletions tests/compile-test.rs
Original file line number Diff line number Diff line change
@@ -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<PathBuf> {
option_env!("TARGET_LIBS").map(PathBuf::from)
}
mod cargo;

#[must_use]
fn rustc_test_suite() -> Option<PathBuf> {
Expand All @@ -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::<Vec<_>>();
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<test::TestDescAndFn>) -> Result<bool, io::Error> {
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
let mut result = true;
let opts = compiletest::test_opts(config);
for dir in fs::read_dir(&config.src_base)? {
Expand Down Expand Up @@ -137,15 +95,16 @@ fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDesc
.iter()
.position(|test| test.desc.name == test_name)
.expect("The test should be in there");
result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
}
}
Ok(result)
}

fn run_ui_toml() {
let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
let config = config("ui", path);
fn run_ui_toml(config: &mut compiletest::Config) {
config.mode = TestMode::Ui;
config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

let tests = compiletest::make_tests(&config);

let res = run_ui_toml_tests(&config, tests);
Expand All @@ -167,6 +126,7 @@ fn prepare_env() {
#[test]
fn compile_test() {
prepare_env();
run_mode("ui", "tests/ui".into());
run_ui_toml();
let mut config = default_config();
run_mode(&mut config);
run_ui_toml(&mut config);
}
30 changes: 18 additions & 12 deletions tests/dogfood.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
use lazy_static::lazy_static;
use std::path::PathBuf;
use std::process::Command;

#[allow(dead_code)]
mod cargo;

lazy_static! {
static ref CLIPPY_PATH: PathBuf = {
let build_info = cargo::BuildInfo::new();
build_info.target_lib().join("cargo-clippy")
};
}

#[test]
fn dogfood_clippy() {
// run clippy on itself and fail the test if lint warnings are reported
if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
return;
}
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let clippy_binary = std::path::Path::new(&root_dir)
.join("target")
.join(env!("PROFILE"))
.join("cargo-clippy");
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));

let output = std::process::Command::new(clippy_binary)
let output = Command::new(&*CLIPPY_PATH)
.current_dir(root_dir)
.env("CLIPPY_DOGFOOD", "1")
.env("CARGO_INCREMENTAL", "0")
Expand All @@ -37,11 +47,7 @@ fn dogfood_subprojects() {
if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
return;
}
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let clippy_binary = std::path::Path::new(&root_dir)
.join("target")
.join(env!("PROFILE"))
.join("cargo-clippy");
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));

for d in &[
"clippy_workspace_tests",
Expand All @@ -51,7 +57,7 @@ fn dogfood_subprojects() {
"clippy_dev",
"rustc_tools_util",
] {
let output = std::process::Command::new(&clippy_binary)
let output = Command::new(&*CLIPPY_PATH)
.current_dir(root_dir.join(d))
.env("CLIPPY_DOGFOOD", "1")
.env("CARGO_INCREMENTAL", "0")
Expand Down