Skip to content

Commit c3b40bb

Browse files
committed
compile-test: Handle CARGO_TARGET_DIR and transitive deps
1 parent f3e2ccd commit c3b40bb

File tree

2 files changed

+124
-71
lines changed

2 files changed

+124
-71
lines changed

tests/cargo/mod.rs

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

tests/compile-test.rs

Lines changed: 32 additions & 71 deletions
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(build_info: cargo::BuildInfo) -> compiletest::Config {
4625
let mut config = compiletest::Config::default();
4726

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

5331
if rustc_test_suite().is_some() {
54-
config.run_lib_path = rustc_lib_path();
55-
config.compile_lib_path = rustc_lib_path();
32+
let path = rustc_lib_path();
33+
config.run_lib_path = path.clone();
34+
config.compile_lib_path = path;
5635
}
5736

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<_>>();
37+
let disambiguated: Vec<_> = build_info
38+
.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,8 @@ 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 build_info = cargo::BuildInfo::new();
130+
let mut config = default_config(build_info);
131+
run_mode(&mut config);
132+
run_ui_toml(&mut config);
172133
}

0 commit comments

Comments
 (0)