|
| 1 | +//! Test suites of the various devtools (cargo, rustfmt, rust-analyzer, etc.). Note that rustdoc is |
| 2 | +//! not here because it has special logic that isn't required by other devtool tests. |
| 3 | +
|
| 4 | +use std::ffi::OsString; |
| 5 | +use std::{env, fs, iter}; |
| 6 | + |
| 7 | +use super::test_helpers::{prepare_cargo_test, run_cargo_test}; |
| 8 | +use crate::core::build_steps::compile; |
| 9 | +use crate::core::build_steps::tool::{self, SourceType}; |
| 10 | +use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; |
| 11 | +use crate::core::config::TargetSelection; |
| 12 | +use crate::utils::helpers; |
| 13 | +use crate::utils::render_tests::add_flags_and_try_run_tests; |
| 14 | +use crate::{Mode, t}; |
| 15 | + |
| 16 | +/// Runs `cargo test` for cargo itself. |
| 17 | +#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| 18 | +pub struct Cargo { |
| 19 | + stage: u32, |
| 20 | + host: TargetSelection, |
| 21 | +} |
| 22 | + |
| 23 | +impl Cargo { |
| 24 | + const CRATE_PATH: &str = "src/tools/cargo"; |
| 25 | +} |
| 26 | + |
| 27 | +impl Step for Cargo { |
| 28 | + type Output = (); |
| 29 | + const ONLY_HOSTS: bool = true; |
| 30 | + |
| 31 | + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
| 32 | + run.path(Self::CRATE_PATH) |
| 33 | + } |
| 34 | + |
| 35 | + fn make_run(run: RunConfig<'_>) { |
| 36 | + run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target }); |
| 37 | + } |
| 38 | + |
| 39 | + /// Runs `cargo test` for `cargo` packaged with Rust. |
| 40 | + fn run(self, builder: &Builder<'_>) { |
| 41 | + let compiler = builder.compiler(self.stage, self.host); |
| 42 | + |
| 43 | + builder.ensure(tool::Cargo { compiler, target: self.host }); |
| 44 | + let cargo = tool::prepare_tool_cargo( |
| 45 | + builder, |
| 46 | + compiler, |
| 47 | + Mode::ToolRustc, |
| 48 | + self.host, |
| 49 | + Kind::Test, |
| 50 | + Self::CRATE_PATH, |
| 51 | + SourceType::Submodule, |
| 52 | + &[], |
| 53 | + ); |
| 54 | + |
| 55 | + // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH` |
| 56 | + let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder); |
| 57 | + |
| 58 | + // Don't run cross-compile tests, we may not have cross-compiled libstd libs |
| 59 | + // available. |
| 60 | + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); |
| 61 | + // Forcibly disable tests using nightly features since any changes to |
| 62 | + // those features won't be able to land. |
| 63 | + cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1"); |
| 64 | + |
| 65 | + fn path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString { |
| 66 | + // Configure PATH to find the right rustc. NB. we have to use PATH |
| 67 | + // and not RUSTC because the Cargo test suite has tests that will |
| 68 | + // fail if rustc is not spelled `rustc`. |
| 69 | + let path = builder.sysroot(compiler).join("bin"); |
| 70 | + let old_path = env::var_os("PATH").unwrap_or_default(); |
| 71 | + env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") |
| 72 | + } |
| 73 | + |
| 74 | + cargo.env("PATH", path_for_cargo(builder, compiler)); |
| 75 | + // Cargo's test suite uses `CARGO_RUSTC_CURRENT_DIR` to determine the path that `file!` is |
| 76 | + // relative to. Cargo no longer sets this env var, so we have to do that. This has to be the |
| 77 | + // same value as `-Zroot-dir`. |
| 78 | + cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string()); |
| 79 | + |
| 80 | + #[cfg(feature = "build-metrics")] |
| 81 | + builder.metrics.begin_test_suite( |
| 82 | + build_helper::metrics::TestSuiteMetadata::CargoPackage { |
| 83 | + crates: vec!["cargo".into()], |
| 84 | + target: self.host.triple.to_string(), |
| 85 | + host: self.host.triple.to_string(), |
| 86 | + stage: self.stage, |
| 87 | + }, |
| 88 | + builder, |
| 89 | + ); |
| 90 | + |
| 91 | + let _time = helpers::timeit(builder); |
| 92 | + add_flags_and_try_run_tests(builder, &mut cargo); |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/// Runs `cargo test` for rustfmt. |
| 97 | +#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| 98 | +pub struct Rustfmt { |
| 99 | + stage: u32, |
| 100 | + host: TargetSelection, |
| 101 | +} |
| 102 | + |
| 103 | +impl Step for Rustfmt { |
| 104 | + type Output = (); |
| 105 | + const ONLY_HOSTS: bool = true; |
| 106 | + |
| 107 | + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
| 108 | + run.path("src/tools/rustfmt") |
| 109 | + } |
| 110 | + |
| 111 | + fn make_run(run: RunConfig<'_>) { |
| 112 | + run.builder.ensure(Rustfmt { stage: run.builder.top_stage, host: run.target }); |
| 113 | + } |
| 114 | + |
| 115 | + /// Runs `cargo test` for rustfmt. |
| 116 | + fn run(self, builder: &Builder<'_>) { |
| 117 | + let stage = self.stage; |
| 118 | + let host = self.host; |
| 119 | + let compiler = builder.compiler(stage, host); |
| 120 | + |
| 121 | + builder.ensure(tool::Rustfmt { compiler, target: self.host }); |
| 122 | + |
| 123 | + let mut cargo = tool::prepare_tool_cargo( |
| 124 | + builder, |
| 125 | + compiler, |
| 126 | + Mode::ToolRustc, |
| 127 | + host, |
| 128 | + Kind::Test, |
| 129 | + "src/tools/rustfmt", |
| 130 | + SourceType::InTree, |
| 131 | + &[], |
| 132 | + ); |
| 133 | + |
| 134 | + let dir = builder.test_out(compiler.host); |
| 135 | + t!(fs::create_dir_all(&dir)); |
| 136 | + cargo.env("RUSTFMT_TEST_DIR", dir); |
| 137 | + |
| 138 | + cargo.add_rustc_lib_path(builder); |
| 139 | + |
| 140 | + run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder); |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| 145 | +pub struct RustAnalyzer { |
| 146 | + stage: u32, |
| 147 | + host: TargetSelection, |
| 148 | +} |
| 149 | + |
| 150 | +impl Step for RustAnalyzer { |
| 151 | + type Output = (); |
| 152 | + const ONLY_HOSTS: bool = true; |
| 153 | + const DEFAULT: bool = true; |
| 154 | + |
| 155 | + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
| 156 | + run.path("src/tools/rust-analyzer") |
| 157 | + } |
| 158 | + |
| 159 | + fn make_run(run: RunConfig<'_>) { |
| 160 | + run.builder.ensure(Self { stage: run.builder.top_stage, host: run.target }); |
| 161 | + } |
| 162 | + |
| 163 | + /// Runs `cargo test` for rust-analyzer |
| 164 | + fn run(self, builder: &Builder<'_>) { |
| 165 | + let stage = self.stage; |
| 166 | + let host = self.host; |
| 167 | + let compiler = builder.compiler(stage, host); |
| 168 | + |
| 169 | + // We don't need to build the whole Rust Analyzer for the proc-macro-srv test suite, |
| 170 | + // but we do need the standard library to be present. |
| 171 | + builder.ensure(compile::Rustc::new(compiler, host)); |
| 172 | + |
| 173 | + let workspace_path = "src/tools/rust-analyzer"; |
| 174 | + // until the whole RA test suite runs on `i686`, we only run |
| 175 | + // `proc-macro-srv` tests |
| 176 | + let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv"; |
| 177 | + let mut cargo = tool::prepare_tool_cargo( |
| 178 | + builder, |
| 179 | + compiler, |
| 180 | + Mode::ToolRustc, |
| 181 | + host, |
| 182 | + Kind::Test, |
| 183 | + crate_path, |
| 184 | + SourceType::InTree, |
| 185 | + &["in-rust-tree".to_owned()], |
| 186 | + ); |
| 187 | + cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES); |
| 188 | + |
| 189 | + let dir = builder.src.join(workspace_path); |
| 190 | + // needed by rust-analyzer to find its own text fixtures, cf. |
| 191 | + // https://github.com/rust-analyzer/expect-test/issues/33 |
| 192 | + cargo.env("CARGO_WORKSPACE_DIR", &dir); |
| 193 | + |
| 194 | + // RA's test suite tries to write to the source directory, that can't |
| 195 | + // work in Rust CI |
| 196 | + cargo.env("SKIP_SLOW_TESTS", "1"); |
| 197 | + |
| 198 | + cargo.add_rustc_lib_path(builder); |
| 199 | + run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder); |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +#[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| 204 | +pub struct Clippy { |
| 205 | + stage: u32, |
| 206 | + host: TargetSelection, |
| 207 | +} |
| 208 | + |
| 209 | +impl Step for Clippy { |
| 210 | + type Output = (); |
| 211 | + const ONLY_HOSTS: bool = true; |
| 212 | + const DEFAULT: bool = false; |
| 213 | + |
| 214 | + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
| 215 | + run.path("src/tools/clippy") |
| 216 | + } |
| 217 | + |
| 218 | + fn make_run(run: RunConfig<'_>) { |
| 219 | + run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target }); |
| 220 | + } |
| 221 | + |
| 222 | + /// Runs `cargo test` for clippy. |
| 223 | + fn run(self, builder: &Builder<'_>) { |
| 224 | + let stage = self.stage; |
| 225 | + let host = self.host; |
| 226 | + let compiler = builder.compiler(stage, host); |
| 227 | + |
| 228 | + builder.ensure(tool::Clippy { compiler, target: self.host }); |
| 229 | + let mut cargo = tool::prepare_tool_cargo( |
| 230 | + builder, |
| 231 | + compiler, |
| 232 | + Mode::ToolRustc, |
| 233 | + host, |
| 234 | + Kind::Test, |
| 235 | + "src/tools/clippy", |
| 236 | + SourceType::InTree, |
| 237 | + &[], |
| 238 | + ); |
| 239 | + |
| 240 | + cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); |
| 241 | + cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); |
| 242 | + let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); |
| 243 | + cargo.env("HOST_LIBS", host_libs); |
| 244 | + |
| 245 | + cargo.add_rustc_lib_path(builder); |
| 246 | + let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder); |
| 247 | + |
| 248 | + let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); |
| 249 | + |
| 250 | + // Clippy reports errors if it blessed the outputs |
| 251 | + if cargo.allow_failure().run(builder) { |
| 252 | + // The tests succeeded; nothing to do. |
| 253 | + return; |
| 254 | + } |
| 255 | + |
| 256 | + if !builder.config.cmd.bless() { |
| 257 | + crate::exit!(1); |
| 258 | + } |
| 259 | + } |
| 260 | +} |
0 commit comments