Skip to content

Commit 185b11f

Browse files
committed
Auto merge of #5121 - lzutao:comptest, r=flip1995
Improve compile_test and dogfood tests * Hopefully this finally resolves the "multiple matching crates" error, e.g. #4015 * This handle some convenient CARGO env like CARGO_TARGET_DIR and CARGO_BUILD_TARGET changelog: none
2 parents a7b3b9f + c4b4dd2 commit 185b11f

File tree

3 files changed

+124
-83
lines changed

3 files changed

+124
-83
lines changed

tests/cargo/mod.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use cargo_metadata::{Message::CompilerArtifact, MetadataCommand};
2+
use std::env;
3+
use std::ffi::OsStr;
4+
use std::mem;
5+
use std::path::PathBuf;
6+
use std::process::Command;
7+
8+
pub struct BuildInfo {
9+
cargo_target_dir: PathBuf,
10+
}
11+
12+
impl BuildInfo {
13+
pub fn new() -> Self {
14+
let data = MetadataCommand::new().exec().unwrap();
15+
Self {
16+
cargo_target_dir: data.target_directory,
17+
}
18+
}
19+
20+
pub fn host_lib(&self) -> PathBuf {
21+
if let Some(path) = option_env!("HOST_LIBS") {
22+
PathBuf::from(path)
23+
} else {
24+
self.cargo_target_dir.join(env!("PROFILE"))
25+
}
26+
}
27+
28+
pub fn target_lib(&self) -> PathBuf {
29+
if let Some(path) = option_env!("TARGET_LIBS") {
30+
path.into()
31+
} else {
32+
let mut dir = self.cargo_target_dir.clone();
33+
if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
34+
dir.push(target);
35+
}
36+
dir.push(env!("PROFILE"));
37+
dir
38+
}
39+
}
40+
41+
pub fn clippy_driver_path(&self) -> PathBuf {
42+
if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
43+
PathBuf::from(path)
44+
} else {
45+
self.target_lib().join("clippy-driver")
46+
}
47+
}
48+
49+
// When we'll want to use `extern crate ..` for a dependency that is used
50+
// both by the crate and the compiler itself, we can't simply pass -L flags
51+
// as we'll get a duplicate matching versions. Instead, disambiguate with
52+
// `--extern dep=path`.
53+
// See https://github.com/rust-lang/rust-clippy/issues/4015.
54+
pub fn third_party_crates() -> Vec<(&'static str, PathBuf)> {
55+
const THIRD_PARTY_CRATES: [&str; 4] = ["serde", "serde_derive", "regex", "clippy_lints"];
56+
let cargo = env::var_os("CARGO");
57+
let cargo = cargo.as_deref().unwrap_or_else(|| OsStr::new("cargo"));
58+
let output = Command::new(cargo)
59+
.arg("build")
60+
.arg("--test=compile-test")
61+
.arg("--message-format=json")
62+
.output()
63+
.unwrap();
64+
65+
let mut crates = Vec::with_capacity(THIRD_PARTY_CRATES.len());
66+
for message in cargo_metadata::parse_messages(output.stdout.as_slice()) {
67+
if let CompilerArtifact(mut artifact) = message.unwrap() {
68+
if let Some(&krate) = THIRD_PARTY_CRATES.iter().find(|&&krate| krate == artifact.target.name) {
69+
crates.push((krate, mem::take(&mut artifact.filenames[0])));
70+
}
71+
}
72+
}
73+
crates
74+
}
75+
}

tests/compile-test.rs

+31-71
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,15 @@
11
#![feature(test)]
22

33
use compiletest_rs as compiletest;
4-
extern crate tester as test;
4+
use compiletest_rs::common::Mode as TestMode;
55

6-
use std::env::{set_var, var};
6+
use std::env::{self, set_var};
77
use std::ffi::OsStr;
88
use std::fs;
99
use std::io;
1010
use std::path::{Path, PathBuf};
1111

12-
#[must_use]
13-
fn clippy_driver_path() -> PathBuf {
14-
if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
15-
PathBuf::from(path)
16-
} else {
17-
PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
18-
}
19-
}
20-
21-
#[must_use]
22-
fn host_libs() -> PathBuf {
23-
if let Some(path) = option_env!("HOST_LIBS") {
24-
PathBuf::from(path)
25-
} else {
26-
Path::new("target").join(env!("PROFILE"))
27-
}
28-
}
29-
30-
#[must_use]
31-
fn target_libs() -> Option<PathBuf> {
32-
option_env!("TARGET_LIBS").map(PathBuf::from)
33-
}
12+
mod cargo;
3413

3514
#[must_use]
3615
fn rustc_test_suite() -> Option<PathBuf> {
@@ -42,73 +21,52 @@ fn rustc_lib_path() -> PathBuf {
4221
option_env!("RUSTC_LIB_PATH").unwrap().into()
4322
}
4423

45-
fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
24+
fn default_config() -> compiletest::Config {
25+
let build_info = cargo::BuildInfo::new();
4626
let mut config = compiletest::Config::default();
4727

48-
let cfg_mode = mode.parse().expect("Invalid mode");
49-
if let Ok(name) = var::<&str>("TESTNAME") {
50-
config.filter = Some(name)
28+
if let Ok(name) = env::var("TESTNAME") {
29+
config.filter = Some(name);
5130
}
5231

5332
if rustc_test_suite().is_some() {
54-
config.run_lib_path = rustc_lib_path();
55-
config.compile_lib_path = rustc_lib_path();
33+
let path = rustc_lib_path();
34+
config.run_lib_path = path.clone();
35+
config.compile_lib_path = path;
5636
}
5737

58-
// When we'll want to use `extern crate ..` for a dependency that is used
59-
// both by the crate and the compiler itself, we can't simply pass -L flags
60-
// as we'll get a duplicate matching versions. Instead, disambiguate with
61-
// `--extern dep=path`.
62-
// See https://github.com/rust-lang/rust-clippy/issues/4015.
63-
let needs_disambiguation = ["serde", "regex", "clippy_lints"];
64-
// This assumes that deps are compiled (they are for Cargo integration tests).
65-
let deps = fs::read_dir(target_libs().unwrap_or_else(host_libs).join("deps")).unwrap();
66-
let disambiguated = deps
67-
.filter_map(|dep| {
68-
let path = dep.ok()?.path();
69-
let name = path.file_name()?.to_string_lossy();
70-
// NOTE: This only handles a single dep
71-
// https://github.com/laumann/compiletest-rs/issues/101
72-
needs_disambiguation.iter().find_map(|dep| {
73-
if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
74-
Some(format!("--extern {}={}", dep, path.display()))
75-
} else {
76-
None
77-
}
78-
})
79-
})
80-
.collect::<Vec<_>>();
38+
let disambiguated: Vec<_> = cargo::BuildInfo::third_party_crates()
39+
.iter()
40+
.map(|(krate, path)| format!("--extern {}={}", krate, path.display()))
41+
.collect();
8142

8243
config.target_rustcflags = Some(format!(
83-
"-L {0} -L {0}/deps {1} -Dwarnings -Zui-testing {2}",
84-
host_libs().display(),
85-
target_libs().map_or_else(String::new, |path| format!("-L {0} -L {0}/deps", path.display())),
44+
"-L {0} -L {1} -Dwarnings -Zui-testing {2}",
45+
build_info.host_lib().join("deps").display(),
46+
build_info.target_lib().join("deps").display(),
8647
disambiguated.join(" ")
8748
));
8849

89-
config.mode = cfg_mode;
9050
config.build_base = if rustc_test_suite().is_some() {
9151
// we don't need access to the stderr files on travis
9252
let mut path = PathBuf::from(env!("OUT_DIR"));
9353
path.push("test_build_base");
9454
path
9555
} else {
96-
let mut path = std::env::current_dir().unwrap();
97-
path.push("target/debug/test_build_base");
98-
path
56+
build_info.host_lib().join("test_build_base")
9957
};
100-
config.src_base = dir;
101-
config.rustc_path = clippy_driver_path();
58+
config.rustc_path = build_info.clippy_driver_path();
10259
config
10360
}
10461

105-
fn run_mode(mode: &str, dir: PathBuf) {
106-
let cfg = config(mode, dir);
62+
fn run_mode(cfg: &mut compiletest::Config) {
63+
cfg.mode = TestMode::Ui;
64+
cfg.src_base = Path::new("tests").join("ui");
10765
compiletest::run_tests(&cfg);
10866
}
10967

11068
#[allow(clippy::identity_conversion)]
111-
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
69+
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
11270
let mut result = true;
11371
let opts = compiletest::test_opts(config);
11472
for dir in fs::read_dir(&config.src_base)? {
@@ -137,15 +95,16 @@ fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDesc
13795
.iter()
13896
.position(|test| test.desc.name == test_name)
13997
.expect("The test should be in there");
140-
result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
98+
result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
14199
}
142100
}
143101
Ok(result)
144102
}
145103

146-
fn run_ui_toml() {
147-
let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
148-
let config = config("ui", path);
104+
fn run_ui_toml(config: &mut compiletest::Config) {
105+
config.mode = TestMode::Ui;
106+
config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();
107+
149108
let tests = compiletest::make_tests(&config);
150109

151110
let res = run_ui_toml_tests(&config, tests);
@@ -167,6 +126,7 @@ fn prepare_env() {
167126
#[test]
168127
fn compile_test() {
169128
prepare_env();
170-
run_mode("ui", "tests/ui".into());
171-
run_ui_toml();
129+
let mut config = default_config();
130+
run_mode(&mut config);
131+
run_ui_toml(&mut config);
172132
}

tests/dogfood.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1+
use lazy_static::lazy_static;
2+
use std::path::PathBuf;
3+
use std::process::Command;
4+
5+
#[allow(dead_code)]
6+
mod cargo;
7+
8+
lazy_static! {
9+
static ref CLIPPY_PATH: PathBuf = {
10+
let build_info = cargo::BuildInfo::new();
11+
build_info.target_lib().join("cargo-clippy")
12+
};
13+
}
14+
115
#[test]
216
fn dogfood_clippy() {
317
// run clippy on itself and fail the test if lint warnings are reported
418
if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
519
return;
620
}
7-
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
8-
let clippy_binary = std::path::Path::new(&root_dir)
9-
.join("target")
10-
.join(env!("PROFILE"))
11-
.join("cargo-clippy");
21+
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1222

13-
let output = std::process::Command::new(clippy_binary)
23+
let output = Command::new(&*CLIPPY_PATH)
1424
.current_dir(root_dir)
1525
.env("CLIPPY_DOGFOOD", "1")
1626
.env("CARGO_INCREMENTAL", "0")
@@ -37,11 +47,7 @@ fn dogfood_subprojects() {
3747
if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) {
3848
return;
3949
}
40-
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
41-
let clippy_binary = std::path::Path::new(&root_dir)
42-
.join("target")
43-
.join(env!("PROFILE"))
44-
.join("cargo-clippy");
50+
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
4551

4652
for d in &[
4753
"clippy_workspace_tests",
@@ -51,7 +57,7 @@ fn dogfood_subprojects() {
5157
"clippy_dev",
5258
"rustc_tools_util",
5359
] {
54-
let output = std::process::Command::new(&clippy_binary)
60+
let output = Command::new(&*CLIPPY_PATH)
5561
.current_dir(root_dir.join(d))
5662
.env("CLIPPY_DOGFOOD", "1")
5763
.env("CARGO_INCREMENTAL", "0")

0 commit comments

Comments
 (0)