From 1f7be5ea3260f9b10958791d3550280bd339c7f7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 11:27:14 +0200 Subject: [PATCH 1/9] Start separating out rustc-specific logic into a cargo feature --- .github/workflows/rust.yml | 2 ++ Cargo.toml | 4 ++++ src/config.rs | 17 +++++++++++------ src/custom_flags.rs | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 67fc5d2c..bb3b615c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -58,3 +58,5 @@ jobs: run: cargo test --verbose --test integration -- --check - name: Run unit tests run: cargo test --verbose + - name: Test no-rustc mode + run: cargo check --no-default-features diff --git a/Cargo.toml b/Cargo.toml index e3ad5e1e..a9f90d00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,3 +44,7 @@ features = ["capture-spantrace"] [[test]] name = "integration" harness = false + +[features] +default = ["rustc"] +rustc = [] diff --git a/src/config.rs b/src/config.rs index ec8386e9..d85d86ca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,15 +1,18 @@ use regex::bytes::Regex; +#[cfg(feature = "rustc")] use spanned::Spanned; +#[cfg(feature = "rustc")] +use crate::{ + aux_builds::AuxBuilder, build_manager::BuildManager, custom_flags::run::Run, + custom_flags::rustfix::RustfixMode, custom_flags::Flag, filter::Match, + per_test_config::TestConfig, Errored, Mode, +}; use crate::{ - aux_builds::AuxBuilder, - build_manager::BuildManager, - custom_flags::{run::Run, rustfix::RustfixMode, Flag}, dependencies::build_dependencies, - filter::Match, parser::CommandParserFunc, - per_test_config::{Comments, Condition, TestConfig}, - CommandBuilder, Errored, Mode, + per_test_config::{Comments, Condition}, + CommandBuilder, }; pub use color_eyre; use color_eyre::eyre::Result; @@ -67,6 +70,7 @@ pub struct Config { impl Config { /// Create a configuration for testing the output of running /// `rustc` on the test files. + #[cfg(feature = "rustc")] pub fn rustc(root_dir: impl Into) -> Self { let mut comment_defaults = Comments::default(); @@ -235,6 +239,7 @@ impl Config { /// Create a configuration for testing the output of running /// `cargo` on the test `Cargo.toml` files. + #[cfg(feature = "rustc")] pub fn cargo(root_dir: impl Into) -> Self { let mut this = Self { program: CommandBuilder::cargo(), diff --git a/src/custom_flags.rs b/src/custom_flags.rs index 20d153b6..f3d10550 100644 --- a/src/custom_flags.rs +++ b/src/custom_flags.rs @@ -7,6 +7,7 @@ use std::{ use crate::{build_manager::BuildManager, per_test_config::TestConfig, Config, Errored}; +#[cfg(feature = "rustc")] pub mod run; pub mod rustfix; From ad579d960562d7109ba9e37ddf8cd8065b19b772 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 11:39:01 +0200 Subject: [PATCH 2/9] Move `dependencies` entirely into "rustc" cargo feature --- src/config.rs | 23 ----------------------- src/dependencies.rs | 38 ++++++++++++++++++++++++++++---------- src/lib.rs | 14 ++++++++++---- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/config.rs b/src/config.rs index d85d86ca..6bf3872b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,6 @@ use crate::{ per_test_config::TestConfig, Errored, Mode, }; use crate::{ - dependencies::build_dependencies, parser::CommandParserFunc, per_test_config::{Comments, Condition}, CommandBuilder, @@ -18,7 +17,6 @@ pub use color_eyre; use color_eyre::eyre::Result; use std::{ collections::BTreeMap, - ffi::OsString, num::NonZeroUsize, path::{Path, PathBuf}, }; @@ -348,27 +346,6 @@ impl Config { )); } - /// Compile dependencies and return the right flags - /// to find the dependencies. - pub fn build_dependencies(&self) -> Result> { - let dependencies = build_dependencies(self)?; - let mut args = vec![]; - for (name, artifacts) in dependencies.dependencies { - for dependency in artifacts { - args.push("--extern".into()); - let mut dep = OsString::from(&name); - dep.push("="); - dep.push(dependency); - args.push(dep); - } - } - for import_path in dependencies.import_paths { - args.push("-L".into()); - args.push(import_path.into()); - } - Ok(args) - } - /// Make sure we have the host and target triples. pub fn fill_host_and_target(&mut self) -> Result<()> { if self.host.is_none() { diff --git a/src/dependencies.rs b/src/dependencies.rs index 693c2b46..ebd29a10 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -50,7 +50,7 @@ fn cfgs(config: &Config) -> Result> { } /// Compiles dependencies and returns the crate names and corresponding rmeta files. -pub(crate) fn build_dependencies(config: &Config) -> Result { +fn build_dependencies_inner(config: &Config) -> Result { let manifest_path = match &config.dependencies_crate_manifest_path { Some(path) => path.to_owned(), None => return Ok(Default::default()), @@ -213,18 +213,36 @@ pub struct DependencyBuilder; impl Build for DependencyBuilder { fn build(&self, build_manager: &BuildManager<'_>) -> Result, Errored> { - build_manager - .config() - .build_dependencies() - .map_err(|e| Errored { - command: Command::new(format!("{:?}", self.description())), - errors: vec![], - stderr: format!("{e:?}").into_bytes(), - stdout: vec![], - }) + build_dependencies(build_manager.config()).map_err(|e| Errored { + command: Command::new(format!("{:?}", self.description())), + errors: vec![], + stderr: format!("{e:?}").into_bytes(), + stdout: vec![], + }) } fn description(&self) -> String { "Building dependencies".into() } } + +/// Compile dependencies and return the right flags +/// to find the dependencies. +pub fn build_dependencies(config: &Config) -> Result> { + let dependencies = build_dependencies_inner(config)?; + let mut args = vec![]; + for (name, artifacts) in dependencies.dependencies { + for dependency in artifacts { + args.push("--extern".into()); + let mut dep = OsString::from(&name); + dep.push("="); + dep.push(dependency); + args.push(dep); + } + } + for import_path in dependencies.import_paths { + args.push("-L".into()); + args.push(import_path.into()); + } + Ok(args) +} diff --git a/src/lib.rs b/src/lib.rs index fafe86f5..cb294bfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ use build_manager::BuildManager; pub use color_eyre; use color_eyre::eyre::eyre; +#[cfg(feature = "rustc")] use color_eyre::eyre::Context as _; pub use color_eyre::eyre::Result; pub use core::run_and_collect; @@ -25,7 +26,6 @@ use std::process::Command; use test_result::TestRun; pub use test_result::{Errored, TestOk}; -use crate::dependencies::DependencyBuilder; use crate::parser::Comments; pub mod aux_builds; @@ -34,6 +34,8 @@ mod cmd; mod config; pub mod core; pub mod custom_flags; + +#[cfg(feature = "rustc")] mod dependencies; mod diff; mod error; @@ -127,9 +129,10 @@ pub fn default_per_file_config(config: &mut Config, _path: &Path, file_contents: /// Create a command for running a single file, with the settings from the `config` argument. /// Ignores various settings from `Config` that relate to finding test files. +#[cfg(feature = "rustc")] pub fn test_command(mut config: Config, path: &Path) -> Result { config.fill_host_and_target()?; - let extra_args = config.build_dependencies()?; + let extra_args = dependencies::build_dependencies(&config)?; let content = std::fs::read(path).wrap_err_with(|| format!("failed to read {}", path.display()))?; @@ -310,7 +313,7 @@ pub fn run_tests_generic( fn parse_and_test_file( build_manager: &BuildManager<'_>, status: &dyn TestStatus, - mut config: Config, + #[allow(unused_mut)] mut config: Config, file_contents: Vec, ) -> Result, Errored> { let comments = Comments::parse(&file_contents, &config, status.path()) @@ -318,6 +321,7 @@ fn parse_and_test_file( const EMPTY: &[String] = &[String::new()]; // Run the test for all revisions let revisions = comments.revisions.as_deref().unwrap_or(EMPTY); + #[cfg(feature = "rustc")] let mut built_deps = false; Ok(revisions .iter() @@ -331,9 +335,11 @@ fn parse_and_test_file( }; } + #[cfg(feature = "rustc")] + // FIXME: move this into custom comments if !built_deps { status.update_status("waiting for dependencies to finish building".into()); - match build_manager.build(DependencyBuilder) { + match build_manager.build(dependencies::DependencyBuilder) { Ok(extra_args) => config.program.args.extend(extra_args), Err(err) => { return TestRun { From 13e29919527179c4b502e70b7807071443e2d34d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 17:00:29 +0200 Subject: [PATCH 3/9] Make dependency building a custom flag --- src/aux_builds.rs | 10 +++-- src/config.rs | 4 ++ src/custom_flags/run.rs | 8 ++-- src/custom_flags/rustfix.rs | 23 +++++------ src/dependencies.rs | 23 +++++++++++ src/lib.rs | 32 ++++----------- src/per_test_config.rs | 39 +++++++++--------- src/status_emitter.rs | 47 +++++++++++++++++++--- src/tests.rs | 6 ++- tests/integrations/basic-fail/Cargo.stdout | 36 ++++++++--------- tests/integrations/cargo-run/Cargo.stdout | 1 - 11 files changed, 141 insertions(+), 88 deletions(-) diff --git a/src/aux_builds.rs b/src/aux_builds.rs index c62b09b1..a9a1de0d 100644 --- a/src/aux_builds.rs +++ b/src/aux_builds.rs @@ -10,7 +10,9 @@ use crate::{ custom_flags::Flag, default_per_file_config, per_test_config::{Comments, TestConfig}, - rustc_stderr, CrateType, Error, Errored, + rustc_stderr, + status_emitter::SilentStatus, + CrateType, Error, Errored, }; impl Flag for AuxBuilder { @@ -106,10 +108,12 @@ impl Build for AuxBuilder { let mut config = TestConfig { config, - revision: "", comments: &comments, - path: &self.aux_file, aux_dir: self.aux_file.parent().unwrap(), + status: &SilentStatus { + revision: String::new(), + path: self.aux_file.content.clone(), + }, }; config.patch_out_dir(); diff --git a/src/config.rs b/src/config.rs index 6bf3872b..430e2d40 100644 --- a/src/config.rs +++ b/src/config.rs @@ -118,6 +118,10 @@ impl Config { "rustfix", Spanned::dummy(vec![Box::new(RustfixMode::MachineApplicable)]), ); + let _ = comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(crate::dependencies::DependencyBuilder)]), + ); let filters = vec![ (Match::PathBackslash, b"/".to_vec()), #[cfg(windows)] diff --git a/src/custom_flags/run.rs b/src/custom_flags/run.rs index 6f6f2018..571f1bde 100644 --- a/src/custom_flags/run.rs +++ b/src/custom_flags/run.rs @@ -29,10 +29,9 @@ impl Flag for Run { let revision = config.extension("run"); let config = TestConfig { config: config.config.clone(), - revision: &revision, comments: config.comments, - path: config.path, aux_dir: config.aux_dir, + status: &config.status.for_revision(&revision), }; cmd.arg("--print").arg("file-names"); let output = cmd.output().unwrap(); @@ -44,7 +43,10 @@ impl Flag for Run { let file = std::str::from_utf8(file).unwrap(); let exe_file = config.config.out_dir.join(file); let mut exe = Command::new(&exe_file); - let stdin = config.path.with_extension(format!("{revision}.stdin")); + let stdin = config + .status + .path() + .with_extension(format!("{revision}.stdin")); if stdin.exists() { exe.stdin(std::fs::File::open(stdin).unwrap()); } diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 9b58863e..500b83d9 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -79,7 +79,7 @@ impl Flag for RustfixMode { if suggestions.is_empty() { None } else { - let path_str = config.path.display().to_string(); + let path_str = config.status.path().display().to_string(); for sugg in &suggestions { for snip in &sugg.snippets { if snip.file_name != path_str { @@ -88,14 +88,14 @@ impl Flag for RustfixMode { } } Some(rustfix::apply_suggestions( - &std::fs::read_to_string(config.path).unwrap(), + &std::fs::read_to_string(config.status.path()).unwrap(), &suggestions, )) } }) .transpose() .map_err(|err| Errored { - command: Command::new(format!("rustfix {}", config.path.display())), + command: Command::new(format!("rustfix {}", config.status.path().display())), errors: vec![Error::Rustfix(err)], stderr: output.stderr, stdout: output.stdout, @@ -119,21 +119,16 @@ impl Flag for RustfixMode { require_annotations_for_level: Default::default(), mode: OptWithLine::new(Mode::Pass, Span::default()), diagnostic_code_prefix: OptWithLine::new(String::new(), Span::default()), - custom: config - .comments - .for_revision(config.revision) - .flat_map(|r| r.custom.clone()) - .collect(), + custom: config.comments().flat_map(|r| r.custom.clone()).collect(), }, )) .collect(), }; let config = TestConfig { config: config.config.clone(), - revision: config.revision, comments: &rustfix_comments, - path: config.path, aux_dir: config.aux_dir, + status: config.status, }; let run = fixed_code.is_some(); @@ -148,7 +143,8 @@ impl Flag for RustfixMode { // picking the crate name from the file name is problematic when `.revision_name` is inserted, // so we compute it here before replacing the path. let crate_name = config - .path + .status + .path() .file_stem() .unwrap() .to_str() @@ -156,14 +152,13 @@ impl Flag for RustfixMode { .replace('-', "_"); let config = TestConfig { config: config.config, - revision: config.revision, comments: &rustfix_comments, - path: &rustfix_path, aux_dir: config.aux_dir, + status: &config.status.for_path(&rustfix_path), }; if !errors.is_empty() { return Err(Errored { - command: Command::new(format!("checking {}", config.path.display())), + command: Command::new(format!("checking {}", config.status.path().display())), errors, stderr: vec![], stdout: vec![], diff --git a/src/dependencies.rs b/src/dependencies.rs index ebd29a10..9d877b7e 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -11,6 +11,8 @@ use std::{ use crate::{ build_manager::{Build, BuildManager}, + custom_flags::Flag, + per_test_config::TestConfig, test_result::Errored, Config, Mode, OutputConflictHandling, }; @@ -209,8 +211,29 @@ fn build_dependencies_inner(config: &Config) -> Result { } /// Build the dependencies. +#[derive(Debug)] pub struct DependencyBuilder; +impl Flag for DependencyBuilder { + fn clone_inner(&self) -> Box { + Box::new(DependencyBuilder) + } + fn apply( + &self, + cmd: &mut Command, + config: &TestConfig<'_>, + build_manager: &BuildManager<'_>, + ) -> Result<(), Errored> { + config + .status + .update_status("waiting for dependencies to finish building".into()); + let extra_args = build_manager.build(DependencyBuilder)?; + cmd.args(extra_args); + config.status.update_status(String::new()); + Ok(()) + } +} + impl Build for DependencyBuilder { fn build(&self, build_manager: &BuildManager<'_>) -> Result, Errored> { build_dependencies(build_manager.config()).map_err(|e| Errored { diff --git a/src/lib.rs b/src/lib.rs index cb294bfe..aa5baa15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,6 +131,8 @@ pub fn default_per_file_config(config: &mut Config, _path: &Path, file_contents: /// Ignores various settings from `Config` that relate to finding test files. #[cfg(feature = "rustc")] pub fn test_command(mut config: Config, path: &Path) -> Result { + use status_emitter::SilentStatus; + config.fill_host_and_target()?; let extra_args = dependencies::build_dependencies(&config)?; @@ -140,10 +142,12 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { .map_err(|errors| color_eyre::eyre::eyre!("{errors:#?}"))?; let config = TestConfig { config, - revision: "", comments: &comments, aux_dir: &path.parent().unwrap().join("auxiliary"), - path, + status: &SilentStatus { + revision: String::new(), + path: path.to_path_buf(), + }, }; let build_manager = BuildManager::new(&(), config.config.clone()); let mut result = config.build_command(&build_manager).unwrap(); @@ -313,7 +317,7 @@ pub fn run_tests_generic( fn parse_and_test_file( build_manager: &BuildManager<'_>, status: &dyn TestStatus, - #[allow(unused_mut)] mut config: Config, + config: Config, file_contents: Vec, ) -> Result, Errored> { let comments = Comments::parse(&file_contents, &config, status.path()) @@ -321,8 +325,6 @@ fn parse_and_test_file( const EMPTY: &[String] = &[String::new()]; // Run the test for all revisions let revisions = comments.revisions.as_deref().unwrap_or(EMPTY); - #[cfg(feature = "rustc")] - let mut built_deps = false; Ok(revisions .iter() .map(|revision| { @@ -335,29 +337,11 @@ fn parse_and_test_file( }; } - #[cfg(feature = "rustc")] - // FIXME: move this into custom comments - if !built_deps { - status.update_status("waiting for dependencies to finish building".into()); - match build_manager.build(dependencies::DependencyBuilder) { - Ok(extra_args) => config.program.args.extend(extra_args), - Err(err) => { - return TestRun { - result: Err(err), - status, - } - } - } - status.update_status(String::new()); - built_deps = true; - } - let test_config = TestConfig { config: config.clone(), - revision, comments: &comments, - path: status.path(), aux_dir: &status.path().parent().unwrap().join("auxiliary"), + status: &status, }; let result = test_config.run_test(build_manager); diff --git a/src/per_test_config.rs b/src/per_test_config.rs index ffaf4e1e..7886827a 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -15,6 +15,7 @@ pub use crate::parser::{Comments, Condition, Revisioned}; use crate::parser::{ErrorMatch, ErrorMatchKind, OptWithLine}; pub use crate::rustc_stderr::Level; use crate::rustc_stderr::Message; +use crate::status_emitter::TestStatus; use crate::test_result::{Errored, TestOk, TestResult}; use crate::{ core::strip_path_prefix, rustc_stderr, Config, Error, Errors, Mode, OutputConflictHandling, @@ -24,35 +25,35 @@ use crate::{ pub struct TestConfig<'a> { /// The generic config for all tests pub config: Config, - pub(crate) revision: &'a str, pub(crate) comments: &'a Comments, - /// The path to the current file - pub path: &'a Path, /// The path to the folder where to look for aux files pub aux_dir: &'a Path, + /// When doing long-running operations, you can inform the user about it here. + pub status: &'a dyn TestStatus, } impl TestConfig<'_> { pub(crate) fn patch_out_dir(&mut self) { // Put aux builds into a separate directory per path so that multiple aux files // from different directories (but with the same file name) don't collide. - let relative = strip_path_prefix(self.path.parent().unwrap(), &self.config.out_dir); + let relative = + strip_path_prefix(self.status.path().parent().unwrap(), &self.config.out_dir); self.config.out_dir.extend(relative); } /// Create a file extension that includes the current revision if necessary. pub fn extension(&self, extension: &str) -> String { - if self.revision.is_empty() { + if self.status.revision().is_empty() { extension.to_string() } else { - format!("{}.{extension}", self.revision) + format!("{}.{extension}", self.status.revision()) } } /// The test's mode after applying all comments pub fn mode(&self) -> Result, Errored> { - self.comments.mode(self.revision) + self.comments.mode(self.status.revision()) } pub(crate) fn find_one<'a, T: 'a>( @@ -60,12 +61,13 @@ impl TestConfig<'_> { kind: &str, f: impl Fn(&'a Revisioned) -> OptWithLine, ) -> Result, Errored> { - self.comments.find_one_for_revision(self.revision, kind, f) + self.comments + .find_one_for_revision(self.status.revision(), kind, f) } /// All comments that apply to the current test. pub fn comments(&self) -> impl Iterator { - self.comments.for_revision(self.revision) + self.comments.for_revision(self.status.revision()) } pub(crate) fn collect<'a, T, I: Iterator, R: FromIterator>( @@ -80,7 +82,7 @@ impl TestConfig<'_> { cmd: &mut Command, build_manager: &BuildManager<'_>, ) -> Result<(), Errored> { - for rev in self.comments.for_revision(self.revision) { + for rev in self.comments.for_revision(self.status.revision()) { for flags in rev.custom.values() { for flag in &flags.content { flag.apply(cmd, self, build_manager)?; @@ -95,9 +97,9 @@ impl TestConfig<'_> { build_manager: &BuildManager<'_>, ) -> Result { let mut cmd = self.config.program.build(&self.config.out_dir); - cmd.arg(self.path); - if !self.revision.is_empty() { - cmd.arg(format!("--cfg={}", self.revision)); + cmd.arg(self.status.path()); + if !self.status.revision().is_empty() { + cmd.arg(format!("--cfg={}", self.status.revision())); } for r in self.comments() { cmd.args(&r.compile_flags); @@ -130,10 +132,11 @@ impl TestConfig<'_> { let ext = self.extension(kind); if self.comments().any(|r| r.stderr_per_bitwidth) { return self - .path + .status + .path() .with_extension(format!("{}bit.{ext}", self.config.get_pointer_width())); } - self.path.with_extension(ext) + self.status.path().with_extension(ext) } pub(crate) fn normalize(&self, text: &[u8], kind: &'static str) -> Vec { @@ -197,7 +200,7 @@ impl TestConfig<'_> { let mut errors = vec![]; errors.extend(self.mode()?.ok(output.status).err()); // Always remove annotation comments from stderr. - let diagnostics = rustc_stderr::process(self.path, &output.stderr); + let diagnostics = rustc_stderr::process(self.status.path(), &output.stderr); self.check_test_output(&mut errors, &output.stdout, &diagnostics.rendered); // Check error annotations in the source against output self.check_annotations( @@ -347,7 +350,7 @@ impl TestConfig<'_> { let line = NonZeroUsize::new(line).expect("line 0 is always empty"); errors.push(Error::ErrorsWithoutPattern { path: Some(Spanned::new( - self.path.to_path_buf(), + self.status.path().to_path_buf(), spanned::Span { line_start: line, ..spanned::Span::default() @@ -382,7 +385,7 @@ impl TestConfig<'_> { self.patch_out_dir(); let mut cmd = self.build_command(build_manager)?; - let stdin = self.path.with_extension(self.extension("stdin")); + let stdin = self.status.path().with_extension(self.extension("stdin")); if stdin.exists() { cmd.stdin(std::fs::File::open(stdin).unwrap()); } diff --git a/src/status_emitter.rs b/src/status_emitter.rs index 3bbafbcc..9a7d791a 100644 --- a/src/status_emitter.rs +++ b/src/status_emitter.rs @@ -45,6 +45,9 @@ pub trait TestStatus: Send + Sync + RefUnwindSafe { /// Create a copy of this test for a new revision. fn for_revision(&self, revision: &str) -> Box; + /// Create a copy of this test for a new path. + fn for_path(&self, path: &Path) -> Box; + /// Invoked before each failed test prints its errors along with a drop guard that can /// gets invoked afterwards. fn failed_test<'a>( @@ -96,9 +99,12 @@ impl StatusEmitter for () { } } -struct SilentStatus { - revision: String, - path: PathBuf, +/// When you need a dummy value that doesn't actually print anything +pub struct SilentStatus { + /// Forwarded to `TestStatus::revision` + pub revision: String, + /// Forwarded to `TestStatus::path` + pub path: PathBuf, } impl TestStatus for SilentStatus { @@ -109,6 +115,13 @@ impl TestStatus for SilentStatus { }) } + fn for_path(&self, path: &Path) -> Box { + Box::new(SilentStatus { + revision: self.revision.clone(), + path: path.to_path_buf(), + }) + } + fn failed_test<'a>( &'a self, _cmd: &'a Command, @@ -324,7 +337,6 @@ impl TestStatus for TextTest { } fn for_revision(&self, revision: &str) -> Box { - assert_eq!(self.revision, ""); if !self.first.swap(false, std::sync::atomic::Ordering::Relaxed) && self.text.progress { self.text.sender.send(Msg::IncLength).unwrap(); } @@ -339,6 +351,17 @@ impl TestStatus for TextTest { Box::new(text) } + fn for_path(&self, path: &Path) -> Box { + let text = Self { + text: self.text.clone(), + path: path.to_path_buf(), + revision: self.revision.clone(), + first: AtomicBool::new(false), + }; + self.text.sender.send(Msg::Push(text.msg())).unwrap(); + Box::new(text) + } + fn revision(&self) -> &str { &self.revision } @@ -885,13 +908,19 @@ impl TestStatus for PathAndRev { } fn for_revision(&self, revision: &str) -> Box { - assert_eq!(self.revision, ""); Box::new(Self { path: self.path.clone(), revision: revision.to_owned(), }) } + fn for_path(&self, path: &Path) -> Box { + Box::new(Self { + path: path.to_path_buf(), + revision: self.revision.clone(), + }) + } + fn failed_test(&self, _cmd: &Command, _stderr: &[u8], _stdout: &[u8]) -> Box { if GROUP { Box::new(github_actions::group(format_args!( @@ -1015,6 +1044,10 @@ impl TestStatus for (T, U) { Box::new((self.0.for_revision(revision), self.1.for_revision(revision))) } + fn for_path(&self, path: &Path) -> Box { + Box::new((self.0.for_path(path), self.1.for_path(path))) + } + fn update_status(&self, msg: String) { self.0.update_status(msg.clone()); self.1.update_status(msg) @@ -1060,6 +1093,10 @@ impl TestStatus for Box { (**self).for_revision(revision) } + fn for_path(&self, path: &Path) -> Box { + (**self).for_path(path) + } + fn failed_test<'a>( &'a self, cmd: &'a Command, diff --git a/src/tests.rs b/src/tests.rs index 954f4562..0d468172 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -22,10 +22,12 @@ macro_rules! config { #[allow(unused_mut)] let mut $config = TestConfig { config: $config, - path, comments: &comments, - revision: "", aux_dir: Path::new("unused_doesnt_exist"), + status: &crate::status_emitter::SilentStatus { + path: path.to_path_buf(), + revision: String::new(), + }, }; }; } diff --git a/tests/integrations/basic-fail/Cargo.stdout b/tests/integrations/basic-fail/Cargo.stdout index 071cc023..f7f3d9be 100644 --- a/tests/integrations/basic-fail/Cargo.stdout +++ b/tests/integrations/basic-fail/Cargo.stdout @@ -21,7 +21,7 @@ tests/actual_tests/touching_above_below.rs ... FAILED tests/actual_tests/touching_above_below_chain.rs ... FAILED FAILED TEST: tests/actual_tests/bad_pattern.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/bad_pattern.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/bad_pattern.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: actual output differed from expected Execute `DO NOT BLESS. These are meant to fail` to update `tests/actual_tests/bad_pattern.stderr` to the actual output @@ -93,7 +93,7 @@ full stdout: FAILED TEST: tests/actual_tests/executable_compile_err.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/executable_compile_err.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/executable_compile_err.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: pass test got exit status: 1, but expected 0 @@ -137,7 +137,7 @@ full stdout: FAILED TEST: tests/actual_tests/exit_code_fail.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/exit_code_fail.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/exit_code_fail.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: fail test got exit status: 0, but expected 1 @@ -166,7 +166,7 @@ full stdout: FAILED TEST: tests/actual_tests/foomp.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/foomp.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/foomp.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: actual output differed from expected Execute `DO NOT BLESS. These are meant to fail` to update `tests/actual_tests/foomp.stderr` to the actual output @@ -218,7 +218,7 @@ full stdout: FAILED TEST: tests/actual_tests/foomp2.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/foomp2.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/foomp2.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: actual output differed from expected Execute `DO NOT BLESS. These are meant to fail` to update `tests/actual_tests/foomp2.stderr` to the actual output @@ -346,7 +346,7 @@ full stdout: FAILED TEST: tests/actual_tests/rustc_ice.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests/rustc_ice.rs" "-Ztreat-err-as-bug" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests/rustc_ice.rs" "-Ztreat-err-as-bug" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: fail test got exit status: 101, but expected 1 @@ -450,9 +450,9 @@ FAILURES: test result: FAIL. 15 failed; -Building dependencies ... ok tests/actual_tests_bless/aux_build_not_found.rs ... FAILED tests/actual_tests_bless/aux_proc_macro_misuse.rs ... FAILED +Building dependencies ... ok Building aux file tests/actual_tests_bless/auxiliary/the_proc_macro.rs ... ok tests/actual_tests_bless/aux_proc_macro_no_main.rs ... FAILED tests/actual_tests_bless/compile_flags_quotes.rs ... FAILED @@ -519,7 +519,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/aux_proc_macro_no_main.rs -command: "rustc" "--error-format=json" "--crate-type=lib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/aux_proc_macro_no_main.rs" "--extern" "the_proc_macro=$DIR/tests/integrations/basic-fail/../../../target/$TMP/tests/actual_tests_bless/auxiliary/libthe_proc_macro.so" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/tests/actual_tests_bless/auxiliary" "--edition" "2021" +command: "rustc" "--error-format=json" "--crate-type=lib" "--out-dir" "$TMP "tests/actual_tests_bless/aux_proc_macro_no_main.rs" "--extern" "the_proc_macro=$DIR/tests/integrations/basic-fail/../../../target/$TMP/tests/actual_tests_bless/auxiliary/libthe_proc_macro.so" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/tests/actual_tests_bless/auxiliary" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: there were 1 unmatched diagnostics --> tests/actual_tests_bless/aux_proc_macro_no_main.rs:7:8 @@ -615,7 +615,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/no_main.rs -command: "rustc" "--error-format=json" "--crate-type=lib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/no_main.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--crate-type=lib" "--out-dir" "$TMP "tests/actual_tests_bless/no_main.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: fail test got exit status: 0, but expected 1 @@ -628,7 +628,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/no_main_manual.rs -command: "rustc" "--error-format=json" "--crate-type=lib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/no_main_manual.rs" "--crate-type=bin" "--edition" "2021" +command: "rustc" "--error-format=json" "--crate-type=lib" "--out-dir" "$TMP "tests/actual_tests_bless/no_main_manual.rs" "--crate-type=bin" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: there were 1 unmatched diagnostics that occurred outside the testfile and had no pattern Error: cannot mix `bin` crate type with others @@ -660,7 +660,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/no_test.rs -command: "rustc" "--error-format=json" "--test" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/no_test.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--test" "--out-dir" "$TMP "tests/actual_tests_bless/no_test.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: fail test got exit status: 0, but expected 1 @@ -700,7 +700,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/pass_with_annotation.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/pass_with_annotation.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/pass_with_annotation.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: `the cake is a lie` not found in diagnostics on line 3 --> tests/actual_tests_bless/pass_with_annotation.rs:3:12 @@ -766,7 +766,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/revisions_bad.rs (revision `bar`) -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/revisions_bad.rs" "--cfg=bar" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/revisions_bad.rs" "--cfg=bar" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: ``main` function not found in crate `revisions_bad`` not found in diagnostics outside the testfile --> tests/actual_tests_bless/revisions_bad.rs:4:31 @@ -798,7 +798,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `a`) -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.a.fixed" "--cfg=a" "--edition" "2021" "--crate-name" "rustfix_fail_revisions" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.a.fixed" "--cfg=a" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" "--crate-name" "rustfix_fail_revisions" error: rustfix failed with exit status: 1 @@ -828,7 +828,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `b`) -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.b.fixed" "--cfg=b" "--edition" "2021" "--crate-name" "rustfix_fail_revisions" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.b.fixed" "--cfg=b" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" "--crate-name" "rustfix_fail_revisions" error: rustfix failed with exit status: 1 @@ -858,7 +858,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/rustfix-fail.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail.fixed" "--edition" "2021" "--crate-name" "rustfix_fail" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail.fixed" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" "--crate-name" "rustfix_fail" error: rustfix failed with exit status: 1 @@ -920,7 +920,7 @@ full stdout: FAILED TEST: tests/actual_tests_bless/wrong_diagnostic_code.rs -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless/wrong_diagnostic_code.rs" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/wrong_diagnostic_code.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: diagnostic code `should_be_dead_code` not found on line 3 --> tests/actual_tests_bless/wrong_diagnostic_code.rs:4:10 @@ -1000,7 +1000,7 @@ tests/actual_tests_bless_yolo/revisions_bad.rs (revision `bar`) ... FAILED tests/actual_tests_bless_yolo/rustfix-maybe-incorrect.rs ... ok FAILED TEST: tests/actual_tests_bless_yolo/revisions_bad.rs (revision `bar`) -command: "rustc" "--error-format=json" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--out-dir" "$TMP "tests/actual_tests_bless_yolo/revisions_bad.rs" "--cfg=bar" "--edition" "2021" +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless_yolo/revisions_bad.rs" "--cfg=bar" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" error: ``main` function not found in crate `revisions_bad`` not found in diagnostics outside the testfile --> tests/actual_tests_bless_yolo/revisions_bad.rs:4:31 diff --git a/tests/integrations/cargo-run/Cargo.stdout b/tests/integrations/cargo-run/Cargo.stdout index 043e9e39..daf5a3f6 100644 --- a/tests/integrations/cargo-run/Cargo.stdout +++ b/tests/integrations/cargo-run/Cargo.stdout @@ -3,7 +3,6 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished -Building dependencies ... ok tests/actual_tests/empty_no_stdin.rs ... ok tests/actual_tests/matching_stdin.rs ... ok tests/actual_tests/mismatching_stdin.rs ... ok From a338c71597d9b59e47a04717d8f9f0d01b4ca389 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 18:46:09 +0200 Subject: [PATCH 4/9] Move general diagnostics data types into their own module --- src/diagnostics.rs | 58 ++++++++++++++++++++++++++++++++++++++++++ src/error.rs | 2 +- src/lib.rs | 3 +-- src/parser.rs | 2 +- src/per_test_config.rs | 4 +-- src/rustc_stderr.rs | 56 +++------------------------------------- src/status_emitter.rs | 7 +++-- 7 files changed, 71 insertions(+), 61 deletions(-) create mode 100644 src/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 00000000..e36292cd --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,58 @@ +//! Data structures for handling diagnostic output from tests. + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +/// The different levels of diagnostic messages and their relative ranking. +pub enum Level { + /// internal compiler errors + Ice = 5, + /// ´error´ level messages + Error = 4, + /// ´warn´ level messages + Warn = 3, + /// ´help´ level messages + Help = 2, + /// ´note´ level messages + Note = 1, + /// Only used for "For more information about this error, try `rustc --explain EXXXX`". + FailureNote = 0, +} + +impl std::str::FromStr for Level { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "ERROR" | "error" => Ok(Self::Error), + "WARN" | "warning" => Ok(Self::Warn), + "HELP" | "help" => Ok(Self::Help), + "NOTE" | "note" => Ok(Self::Note), + "failure-note" => Ok(Self::FailureNote), + "error: internal compiler error" => Ok(Self::Ice), + _ => Err(format!("unknown level `{s}`")), + } + } +} + +#[derive(Debug)] +/// A diagnostic message. +pub struct Message { + /// The diagnostic level at which this message was emitted + pub level: Level, + /// The main message of the diagnostic (what will be matched for with `//~`) + pub message: String, + /// Information about where in the file the message was emitted + pub line_col: Option, + /// Identifier of the message (E0XXX for rustc errors, or lint names) + pub code: Option, +} + +#[derive(Debug)] +/// All the diagnostics that were emitted in a test +pub struct Diagnostics { + /// Rendered and concatenated version of all diagnostics. + /// This is equivalent to non-json diagnostics. + pub rendered: Vec, + /// Per line, a list of messages for that line. + pub messages: Vec>, + /// Messages not on any line (usually because they are from libstd) + pub messages_from_unknown_file_or_line: Vec, +} diff --git a/src/error.rs b/src/error.rs index 06d95832..0e2896a4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use crate::{ + diagnostics::Message, parser::{Pattern, Span, Spanned}, - rustc_stderr::Message, }; use std::{num::NonZeroUsize, path::PathBuf, process::ExitStatus}; diff --git a/src/lib.rs b/src/lib.rs index aa5baa15..a51392de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ pub use core::run_and_collect; pub use core::CrateType; pub use filter::Match; use per_test_config::TestConfig; -use rustc_stderr::Message; use status_emitter::{StatusEmitter, TestStatus}; use std::collections::VecDeque; use std::path::Path; @@ -34,9 +33,9 @@ mod cmd; mod config; pub mod core; pub mod custom_flags; - #[cfg(feature = "rustc")] mod dependencies; +pub mod diagnostics; mod diff; mod error; pub mod filter; diff --git a/src/parser.rs b/src/parser.rs index 5a463b35..698e7eba 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -9,7 +9,7 @@ use bstr::{ByteSlice, Utf8Error}; use regex::bytes::Regex; use crate::{ - custom_flags::Flag, filter::Match, rustc_stderr::Level, test_result::Errored, Config, Error, + custom_flags::Flag, diagnostics::Level, filter::Match, test_result::Errored, Config, Error, Mode, }; diff --git a/src/per_test_config.rs b/src/per_test_config.rs index 7886827a..eba23771 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -11,10 +11,10 @@ use spanned::Spanned; use crate::build_manager::BuildManager; use crate::custom_flags::Flag; +pub use crate::diagnostics::Level; +use crate::diagnostics::Message; pub use crate::parser::{Comments, Condition, Revisioned}; use crate::parser::{ErrorMatch, ErrorMatchKind, OptWithLine}; -pub use crate::rustc_stderr::Level; -use crate::rustc_stderr::Message; use crate::status_emitter::TestStatus; use crate::test_result::{Errored, TestOk, TestResult}; use crate::{ diff --git a/src/rustc_stderr.rs b/src/rustc_stderr.rs index 2680fb1f..f243c286 100644 --- a/src/rustc_stderr.rs +++ b/src/rustc_stderr.rs @@ -5,6 +5,8 @@ use std::{ path::{Path, PathBuf}, }; +use crate::diagnostics::{Diagnostics, Message}; + #[derive(serde::Deserialize, Debug)] struct RustcDiagnosticCode { code: String, @@ -20,32 +22,6 @@ struct RustcMessage { code: Option, } -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -/// The different levels of diagnostic messages and their relative ranking. -pub enum Level { - /// internal compiler errors - Ice = 5, - /// ´error´ level messages - Error = 4, - /// ´warn´ level messages - Warn = 3, - /// ´help´ level messages - Help = 2, - /// ´note´ level messages - Note = 1, - /// Only used for "For more information about this error, try `rustc --explain EXXXX`". - FailureNote = 0, -} - -#[derive(Debug)] -/// A diagnostic message. -pub struct Message { - pub(crate) level: Level, - pub(crate) message: String, - pub(crate) line_col: Option, - pub(crate) code: Option, -} - /// Information about macro expansion. #[derive(serde::Deserialize, Debug)] struct Expansion { @@ -69,32 +45,6 @@ struct Span { column_end: NonZeroUsize, } -impl std::str::FromStr for Level { - type Err = String; - fn from_str(s: &str) -> Result { - match s { - "ERROR" | "error" => Ok(Self::Error), - "WARN" | "warning" => Ok(Self::Warn), - "HELP" | "help" => Ok(Self::Help), - "NOTE" | "note" => Ok(Self::Note), - "failure-note" => Ok(Self::FailureNote), - "error: internal compiler error" => Ok(Self::Ice), - _ => Err(format!("unknown level `{s}`")), - } - } -} - -#[derive(Debug)] -pub(crate) struct Diagnostics { - /// Rendered and concatenated version of all diagnostics. - /// This is equivalent to non-json diagnostics. - pub rendered: Vec, - /// Per line, a list of messages for that line. - pub messages: Vec>, - /// Messages not on any line (usually because they are from libstd) - pub messages_from_unknown_file_or_line: Vec, -} - impl RustcMessage { fn line(&self, file: &Path) -> Option { let span = |primary| self.spans.iter().find_map(|span| span.line(file, primary)); @@ -164,7 +114,7 @@ impl RustcSpan { } } -pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { +fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { let annotations = Regex::new(r" *//(\[[a-z,]+\])?~.*").unwrap(); annotations.replace_all(rendered, "") } diff --git a/src/status_emitter.rs b/src/status_emitter.rs index 9a7d791a..e1917d05 100644 --- a/src/status_emitter.rs +++ b/src/status_emitter.rs @@ -8,8 +8,11 @@ use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle}; use spanned::Span; use crate::{ - github_actions, parser::Pattern, rustc_stderr::Level, test_result::Errored, - test_result::TestOk, test_result::TestResult, Error, Errors, Format, Message, + diagnostics::{Level, Message}, + github_actions, + parser::Pattern, + test_result::{Errored, TestOk, TestResult}, + Error, Errors, Format, }; use std::{ collections::HashMap, From b508c3fbdfea3ae49a3f4991270d54660cfddc47 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 18:56:47 +0200 Subject: [PATCH 5/9] Allow overriding the test output parser --- src/aux_builds.rs | 3 +-- src/config.rs | 6 ++++++ src/custom_flags/rustfix.rs | 4 ++-- src/lib.rs | 1 + src/per_test_config.rs | 13 ++++++++----- src/tests.rs | 4 ++-- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/aux_builds.rs b/src/aux_builds.rs index a9a1de0d..8f869bfa 100644 --- a/src/aux_builds.rs +++ b/src/aux_builds.rs @@ -10,7 +10,6 @@ use crate::{ custom_flags::Flag, default_per_file_config, per_test_config::{Comments, TestConfig}, - rustc_stderr, status_emitter::SilentStatus, CrateType, Error, Errored, }; @@ -131,7 +130,7 @@ impl Build for AuxBuilder { return Err(Errored { command: aux_cmd, errors: vec![error], - stderr: rustc_stderr::process(&self.aux_file, &output.stderr).rendered, + stderr: config.process(&output.stderr).rendered, stdout: output.stdout, }); } diff --git a/src/config.rs b/src/config.rs index 430e2d40..1f5e35dd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,6 +9,7 @@ use crate::{ per_test_config::TestConfig, Errored, Mode, }; use crate::{ + diagnostics::Diagnostics, parser::CommandParserFunc, per_test_config::{Comments, Condition}, CommandBuilder, @@ -63,6 +64,8 @@ pub struct Config { pub comment_defaults: Comments, /// Custom comment parsers pub custom_comments: BTreeMap<&'static str, CommandParserFunc>, + /// Custom diagnostic extractor (invoked on the output of tests) + pub diagnostic_extractor: fn(&Path, &[u8]) -> Diagnostics, } impl Config { @@ -70,6 +73,8 @@ impl Config { /// `rustc` on the test files. #[cfg(feature = "rustc")] pub fn rustc(root_dir: impl Into) -> Self { + use crate::rustc_stderr; + let mut comment_defaults = Comments::default(); #[derive(Debug)] @@ -156,6 +161,7 @@ impl Config { filter_exact: false, comment_defaults, custom_comments: Default::default(), + diagnostic_extractor: rustc_stderr::process, }; config .custom_comments diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 500b83d9..91e378ad 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -11,7 +11,7 @@ use crate::{ build_manager::BuildManager, parser::OptWithLine, per_test_config::{Comments, Revisioned, TestConfig}, - rustc_stderr, Error, Errored, Mode, + Error, Errored, Mode, }; use super::Flag; @@ -181,7 +181,7 @@ impl Flag for RustfixMode { kind: "rustfix".into(), status: output.status, }], - stderr: rustc_stderr::process(&rustfix_path, &output.stderr).rendered, + stderr: config.process(&output.stderr).rendered, stdout: output.stdout, }) } diff --git a/src/lib.rs b/src/lib.rs index a51392de..40257deb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,7 @@ mod mode; pub mod nextest; mod parser; pub mod per_test_config; +#[cfg(feature = "rustc")] mod rustc_stderr; pub mod status_emitter; pub mod test_result; diff --git a/src/per_test_config.rs b/src/per_test_config.rs index eba23771..384ddf7e 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -12,14 +12,12 @@ use spanned::Spanned; use crate::build_manager::BuildManager; use crate::custom_flags::Flag; pub use crate::diagnostics::Level; -use crate::diagnostics::Message; +use crate::diagnostics::{Diagnostics, Message}; pub use crate::parser::{Comments, Condition, Revisioned}; use crate::parser::{ErrorMatch, ErrorMatchKind, OptWithLine}; use crate::status_emitter::TestStatus; use crate::test_result::{Errored, TestOk, TestResult}; -use crate::{ - core::strip_path_prefix, rustc_stderr, Config, Error, Errors, Mode, OutputConflictHandling, -}; +use crate::{core::strip_path_prefix, Config, Error, Errors, Mode, OutputConflictHandling}; /// All information needed to run a single test pub struct TestConfig<'a> { @@ -192,6 +190,11 @@ impl TestConfig<'_> { path } + /// Read diagnostics from a test's output. + pub fn process(&self, stderr: &[u8]) -> Diagnostics { + (self.config.diagnostic_extractor)(self.status.path(), stderr) + } + fn check_test_result( &self, command: Command, @@ -200,7 +203,7 @@ impl TestConfig<'_> { let mut errors = vec![]; errors.extend(self.mode()?.ok(output.status).err()); // Always remove annotation comments from stderr. - let diagnostics = rustc_stderr::process(self.status.path(), &output.stderr); + let diagnostics = self.process(&output.stderr); self.check_test_output(&mut errors, &output.stdout, &diagnostics.rendered); // Check error annotations in the source against output self.check_annotations( diff --git a/src/tests.rs b/src/tests.rs index 0d468172..d9194e49 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2,8 +2,8 @@ use std::path::{Path, PathBuf}; use spanned::Spanned; -use crate::rustc_stderr::Level; -use crate::rustc_stderr::Message; +use crate::diagnostics::Level; +use crate::diagnostics::Message; use super::*; From ba7b1fdb392cfc4fef44839e1cfb4556c956e92d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 22:07:54 +0200 Subject: [PATCH 6/9] Remove manual dependency building now that it is automatically done in `build_command` --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 40257deb..bb0c244a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,6 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { use status_emitter::SilentStatus; config.fill_host_and_target()?; - let extra_args = dependencies::build_dependencies(&config)?; let content = std::fs::read(path).wrap_err_with(|| format!("failed to read {}", path.display()))?; @@ -150,10 +149,8 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { }, }; let build_manager = BuildManager::new(&(), config.config.clone()); - let mut result = config.build_command(&build_manager).unwrap(); - result.args(extra_args); - Ok(result) + Ok(config.build_command(&build_manager).unwrap()) } /// A version of `run_tests` that allows more fine-grained control over running tests. From f99d8d7b35815d7080bd43307ba1745b63642d43 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 22:17:35 +0200 Subject: [PATCH 7/9] Move dependency building entirely into rustc specific stuff --- CHANGELOG.md | 1 + src/config.rs | 11 ----- src/dependencies.rs | 42 +++++++++++++------ src/lib.rs | 2 +- .../integrations/basic-bin/tests/ui_tests.rs | 10 ++++- .../basic-fail-mode/tests/run_file.rs | 10 ++++- .../basic-fail-mode/tests/ui_tests.rs | 11 +++-- tests/integrations/basic-fail/Cargo.stderr | 2 +- tests/integrations/basic-fail/Cargo.stdout | 1 - .../integrations/basic-fail/tests/ui_tests.rs | 11 ++++- .../basic-fail/tests/ui_tests_bless.rs | 13 +++++- tests/integrations/basic/tests/run_file.rs | 10 ++++- tests/integrations/basic/tests/ui_tests.rs | 10 ++++- 13 files changed, 95 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b79a7c64..e0acf5a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * aux builds and dependencies are now built *per* `Config` instead of being built just for the first `Config` and the result shared by the others * the configs could be different enough that aux builds built with a different config are incompatible (e.g. different targets). * replaced `Revisioned::aux_builds` with a rustc-specific custom flag +* replaced `dependency_builder` and `dependency_manifest_path` with `DependencyBuilder` `Flag` that you an add to the default comments. ### Removed diff --git a/src/config.rs b/src/config.rs index 1f5e35dd..7a8e6293 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,11 +40,6 @@ pub struct Config { pub output_conflict_handling: OutputConflictHandling, /// The recommended command to bless failing tests. pub bless_command: Option, - /// Path to a `Cargo.toml` that describes which dependencies the tests can access. - pub dependencies_crate_manifest_path: Option, - /// The command to run can be changed from `cargo` to any custom command to build the - /// dependencies in `dependencies_crate_manifest_path`. - pub dependency_builder: CommandBuilder, /// Where to dump files like the binaries compiled from tests. /// Defaults to `target/ui` in the current directory. pub out_dir: PathBuf, @@ -123,10 +118,6 @@ impl Config { "rustfix", Spanned::dummy(vec![Box::new(RustfixMode::MachineApplicable)]), ); - let _ = comment_defaults.base().custom.insert( - "dependencies", - Spanned::dummy(vec![Box::new(crate::dependencies::DependencyBuilder)]), - ); let filters = vec![ (Match::PathBackslash, b"/".to_vec()), #[cfg(windows)] @@ -147,8 +138,6 @@ impl Config { program: CommandBuilder::rustc(), output_conflict_handling: OutputConflictHandling::Bless, bless_command: None, - dependencies_crate_manifest_path: None, - dependency_builder: CommandBuilder::cargo(), out_dir: std::env::var_os("CARGO_TARGET_DIR") .map(PathBuf::from) .unwrap_or_else(|| std::env::current_dir().unwrap().join("target")) diff --git a/src/dependencies.rs b/src/dependencies.rs index 9d877b7e..760f1af1 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -1,3 +1,5 @@ +//! Use `cargo` to build dependencies and make them available in your tests + use cargo_metadata::{camino::Utf8PathBuf, DependencyKind}; use cargo_platform::Cfg; use color_eyre::eyre::{bail, eyre, Result}; @@ -14,10 +16,11 @@ use crate::{ custom_flags::Flag, per_test_config::TestConfig, test_result::Errored, - Config, Mode, OutputConflictHandling, + CommandBuilder, Config, Mode, OutputConflictHandling, }; #[derive(Default, Debug)] +/// Describes where to find the binaries built for the dependencies pub struct Dependencies { /// All paths that must be imported with `-L dependency=`. This is for /// finding proc macros run on the host and dependencies for the target. @@ -52,13 +55,13 @@ fn cfgs(config: &Config) -> Result> { } /// Compiles dependencies and returns the crate names and corresponding rmeta files. -fn build_dependencies_inner(config: &Config) -> Result { - let manifest_path = match &config.dependencies_crate_manifest_path { +fn build_dependencies_inner(config: &Config, info: &DependencyBuilder) -> Result { + let manifest_path = match &info.crate_manifest_path { Some(path) => path.to_owned(), None => return Ok(Default::default()), }; let manifest_path = &manifest_path; - let mut build = config.dependency_builder.build(&config.out_dir); + let mut build = info.program.build(&config.out_dir); build.arg(manifest_path); if let Some(target) = &config.target { @@ -125,7 +128,7 @@ fn build_dependencies_inner(config: &Config) -> Result { // Check which crates are mentioned in the crate itself let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); metadata.arg("--manifest-path").arg(manifest_path); - config.dependency_builder.apply_env(&mut metadata); + info.program.apply_env(&mut metadata); set_locking(&mut metadata); let output = metadata.output()?; @@ -211,12 +214,27 @@ fn build_dependencies_inner(config: &Config) -> Result { } /// Build the dependencies. -#[derive(Debug)] -pub struct DependencyBuilder; +#[derive(Debug, Clone)] +pub struct DependencyBuilder { + /// Path to a `Cargo.toml` that describes which dependencies the tests can access. + pub crate_manifest_path: Option, + /// The command to run can be changed from `cargo` to any custom command to build the + /// dependencies in `crate_manifest_path`. + pub program: CommandBuilder, +} + +impl Default for DependencyBuilder { + fn default() -> Self { + Self { + crate_manifest_path: None, + program: CommandBuilder::cargo(), + } + } +} impl Flag for DependencyBuilder { fn clone_inner(&self) -> Box { - Box::new(DependencyBuilder) + Box::new(self.clone()) } fn apply( &self, @@ -227,7 +245,7 @@ impl Flag for DependencyBuilder { config .status .update_status("waiting for dependencies to finish building".into()); - let extra_args = build_manager.build(DependencyBuilder)?; + let extra_args = build_manager.build(self.clone())?; cmd.args(extra_args); config.status.update_status(String::new()); Ok(()) @@ -236,7 +254,7 @@ impl Flag for DependencyBuilder { impl Build for DependencyBuilder { fn build(&self, build_manager: &BuildManager<'_>) -> Result, Errored> { - build_dependencies(build_manager.config()).map_err(|e| Errored { + build_dependencies(build_manager.config(), self).map_err(|e| Errored { command: Command::new(format!("{:?}", self.description())), errors: vec![], stderr: format!("{e:?}").into_bytes(), @@ -251,8 +269,8 @@ impl Build for DependencyBuilder { /// Compile dependencies and return the right flags /// to find the dependencies. -pub fn build_dependencies(config: &Config) -> Result> { - let dependencies = build_dependencies_inner(config)?; +pub fn build_dependencies(config: &Config, info: &DependencyBuilder) -> Result> { + let dependencies = build_dependencies_inner(config, info)?; let mut args = vec![]; for (name, artifacts) in dependencies.dependencies { for dependency in artifacts { diff --git a/src/lib.rs b/src/lib.rs index bb0c244a..36b9aeca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ mod config; pub mod core; pub mod custom_flags; #[cfg(feature = "rustc")] -mod dependencies; +pub mod dependencies; pub mod diagnostics; mod diff; mod error; diff --git a/tests/integrations/basic-bin/tests/ui_tests.rs b/tests/integrations/basic-bin/tests/ui_tests.rs index 156bb10c..b6444e0d 100644 --- a/tests/integrations/basic-bin/tests/ui_tests.rs +++ b/tests/integrations/basic-bin/tests/ui_tests.rs @@ -1,9 +1,8 @@ -use ui_test::*; +use ui_test::{dependencies::DependencyBuilder, spanned::Spanned, *}; fn main() -> ui_test::color_eyre::Result<()> { let path = "../../../target"; let mut config = Config { - dependencies_crate_manifest_path: Some("Cargo.toml".into()), output_conflict_handling: if std::env::var_os("BLESS").is_some() { OutputConflictHandling::Bless } else { @@ -12,6 +11,13 @@ fn main() -> ui_test::color_eyre::Result<()> { bless_command: Some("cargo test".to_string()), ..Config::rustc("tests/actual_tests") }; + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); config.stderr_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stderr_filter(r"[^ ]*/\.?cargo/registry/.*/", "$$CARGO_REGISTRY"); diff --git a/tests/integrations/basic-fail-mode/tests/run_file.rs b/tests/integrations/basic-fail-mode/tests/run_file.rs index 7b3a9c9e..37cb0d77 100644 --- a/tests/integrations/basic-fail-mode/tests/run_file.rs +++ b/tests/integrations/basic-fail-mode/tests/run_file.rs @@ -1,5 +1,7 @@ use std::path::{Path, PathBuf}; use ui_test::color_eyre::{eyre::ensure, Result}; +use ui_test::dependencies::DependencyBuilder; +use ui_test::spanned::Spanned; use ui_test::*; #[test] @@ -53,7 +55,13 @@ fn run_file_no_deps() -> Result<()> { // Don't build a binary, we only provide .rmeta dependencies for now config.program.args.push("--emit=metadata".into()); - config.dependencies_crate_manifest_path = Some("Cargo.toml".into()); + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); let mut result = ui_test::test_command( config, diff --git a/tests/integrations/basic-fail-mode/tests/ui_tests.rs b/tests/integrations/basic-fail-mode/tests/ui_tests.rs index 0d8c7d4b..448a2b7f 100644 --- a/tests/integrations/basic-fail-mode/tests/ui_tests.rs +++ b/tests/integrations/basic-fail-mode/tests/ui_tests.rs @@ -1,10 +1,8 @@ -use ui_test::{spanned::Spanned, *}; +use ui_test::{dependencies::DependencyBuilder, spanned::Spanned, *}; fn main() -> ui_test::color_eyre::Result<()> { let path = "../../../target"; let mut config = Config { - dependencies_crate_manifest_path: Some("Cargo.toml".into()), - output_conflict_handling: if std::env::var_os("BLESS").is_some() { OutputConflictHandling::Bless } else { @@ -17,6 +15,13 @@ fn main() -> ui_test::color_eyre::Result<()> { require_patterns: true, }) .into(); + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); config.stderr_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stderr_filter(r"[^ ]*/\.?cargo/registry/.*/", "$$CARGO_REGISTRY"); diff --git a/tests/integrations/basic-fail/Cargo.stderr b/tests/integrations/basic-fail/Cargo.stderr index 11f88adf..6039a950 100644 --- a/tests/integrations/basic-fail/Cargo.stderr +++ b/tests/integrations/basic-fail/Cargo.stderr @@ -6,7 +6,7 @@ error: test failed, to rerun pass `--test ui_tests` Caused by: process didn't exit successfully: `$DIR/target/ui/tests/integrations/basic-fail/debug/deps/ui_tests-HASH` (exit status: 1) -thread 'main' panicked at tests/ui_tests_bless.rs:58:18: +thread 'main' panicked at tests/ui_tests_bless.rs:67:18: invalid mode/result combo: yolo: Err(tests failed Location: diff --git a/tests/integrations/basic-fail/Cargo.stdout b/tests/integrations/basic-fail/Cargo.stdout index f7f3d9be..7043e6eb 100644 --- a/tests/integrations/basic-fail/Cargo.stdout +++ b/tests/integrations/basic-fail/Cargo.stdout @@ -1028,7 +1028,6 @@ FAILURES: test result: FAIL. 1 failed; 2 passed; -Building dependencies ... ok tests/actual_tests/bad_pattern.rs ... FAILED tests/actual_tests/executable.rs ... FAILED tests/actual_tests/executable_compile_err.rs ... FAILED diff --git a/tests/integrations/basic-fail/tests/ui_tests.rs b/tests/integrations/basic-fail/tests/ui_tests.rs index 55262c4c..63447780 100644 --- a/tests/integrations/basic-fail/tests/ui_tests.rs +++ b/tests/integrations/basic-fail/tests/ui_tests.rs @@ -1,15 +1,22 @@ -use ui_test::*; +use ui_test::{dependencies::DependencyBuilder, spanned::Spanned, *}; fn main() -> ui_test::color_eyre::Result<()> { let path = "../../../target"; let mut config = Config { - dependencies_crate_manifest_path: Some("Cargo.toml".into()), // Never bless integrations-fail tests, we want to see stderr mismatches output_conflict_handling: OutputConflictHandling::Error, bless_command: Some("DO NOT BLESS. These are meant to fail".to_string()), ..Config::rustc("tests/actual_tests") }; + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); + // hide binaries generated for successfully passing tests let tmp_dir = tempfile::tempdir_in(path)?; let tmp_dir = tmp_dir.path(); diff --git a/tests/integrations/basic-fail/tests/ui_tests_bless.rs b/tests/integrations/basic-fail/tests/ui_tests_bless.rs index 87897675..d1f2ad2f 100644 --- a/tests/integrations/basic-fail/tests/ui_tests_bless.rs +++ b/tests/integrations/basic-fail/tests/ui_tests_bless.rs @@ -1,4 +1,6 @@ -use ui_test::{custom_flags::rustfix::RustfixMode, spanned::Spanned, *}; +use ui_test::{ + custom_flags::rustfix::RustfixMode, dependencies::DependencyBuilder, spanned::Spanned, *, +}; fn main() -> ui_test::color_eyre::Result<()> { for (mode, rustfix) in [ @@ -19,7 +21,6 @@ fn main() -> ui_test::color_eyre::Result<()> { }; let mut config = Config { - dependencies_crate_manifest_path: Some("Cargo.toml".into()), output_conflict_handling: if std::env::var_os("BLESS").is_some() { OutputConflictHandling::Bless } else { @@ -35,6 +36,14 @@ fn main() -> ui_test::color_eyre::Result<()> { .custom .insert("rustfix", Spanned::dummy(vec![Box::new(rustfix)])); + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); + // hide binaries generated for successfully passing tests let tmp_dir = tempfile::tempdir_in(path)?; let tmp_dir = tmp_dir.path(); diff --git a/tests/integrations/basic/tests/run_file.rs b/tests/integrations/basic/tests/run_file.rs index d5dfb79a..ed275912 100644 --- a/tests/integrations/basic/tests/run_file.rs +++ b/tests/integrations/basic/tests/run_file.rs @@ -1,5 +1,7 @@ use std::path::{Path, PathBuf}; use ui_test::color_eyre::{eyre::ensure, Result}; +use ui_test::dependencies::DependencyBuilder; +use ui_test::spanned::Spanned; use ui_test::*; #[test] @@ -35,7 +37,13 @@ fn run_file_with_deps() -> Result<()> { // Don't build a binary, we only provide .rmeta dependencies for now config.program.args.push("--emit=metadata".into()); - config.dependencies_crate_manifest_path = Some("Cargo.toml".into()); + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); let mut result = ui_test::test_command( config, diff --git a/tests/integrations/basic/tests/ui_tests.rs b/tests/integrations/basic/tests/ui_tests.rs index 45129138..fe5a6193 100644 --- a/tests/integrations/basic/tests/ui_tests.rs +++ b/tests/integrations/basic/tests/ui_tests.rs @@ -1,9 +1,8 @@ -use ui_test::*; +use ui_test::{dependencies::DependencyBuilder, spanned::Spanned, *}; fn main() -> ui_test::color_eyre::Result<()> { let path = "../../../target"; let mut config = Config { - dependencies_crate_manifest_path: Some("Cargo.toml".into()), output_conflict_handling: if std::env::var_os("BLESS").is_some() { OutputConflictHandling::Bless } else { @@ -16,6 +15,13 @@ fn main() -> ui_test::color_eyre::Result<()> { config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stderr_filter(r"[^ ]*/\.?cargo/registry/.*/", "$$CARGO_REGISTRY"); config.path_stderr_filter(&std::path::Path::new(path), "$DIR"); + config.comment_defaults.base().custom.insert( + "dependencies", + Spanned::dummy(vec![Box::new(DependencyBuilder { + crate_manifest_path: Some("Cargo.toml".into()), + ..Default::default() + })]), + ); if let Ok(target) = std::env::var("UITEST_TEST_TARGET") { config.target = Some(target); From ca47311369f341adfc7f82206f98ee81992f0983 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 22:22:20 +0200 Subject: [PATCH 8/9] Now that we make the decision on whether to build deps depend on whether the `DependencyBuilder` flag is set, we don't need to make the manifest path optional anymore. --- src/dependencies.rs | 17 +++++++---------- tests/integrations/basic-bin/tests/ui_tests.rs | 5 +---- .../basic-fail-mode/tests/run_file.rs | 5 +---- .../basic-fail-mode/tests/ui_tests.rs | 5 +---- tests/integrations/basic-fail/Cargo.stderr | 2 +- tests/integrations/basic-fail/tests/ui_tests.rs | 5 +---- .../basic-fail/tests/ui_tests_bless.rs | 5 +---- tests/integrations/basic/tests/run_file.rs | 5 +---- tests/integrations/basic/tests/ui_tests.rs | 5 +---- 9 files changed, 15 insertions(+), 39 deletions(-) diff --git a/src/dependencies.rs b/src/dependencies.rs index 760f1af1..823d9368 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -56,13 +56,8 @@ fn cfgs(config: &Config) -> Result> { /// Compiles dependencies and returns the crate names and corresponding rmeta files. fn build_dependencies_inner(config: &Config, info: &DependencyBuilder) -> Result { - let manifest_path = match &info.crate_manifest_path { - Some(path) => path.to_owned(), - None => return Ok(Default::default()), - }; - let manifest_path = &manifest_path; let mut build = info.program.build(&config.out_dir); - build.arg(manifest_path); + build.arg(&info.crate_manifest_path); if let Some(target) = &config.target { build.arg(format!("--target={target}")); @@ -127,7 +122,9 @@ fn build_dependencies_inner(config: &Config, info: &DependencyBuilder) -> Result // Check which crates are mentioned in the crate itself let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); - metadata.arg("--manifest-path").arg(manifest_path); + metadata + .arg("--manifest-path") + .arg(&info.crate_manifest_path); info.program.apply_env(&mut metadata); set_locking(&mut metadata); let output = metadata.output()?; @@ -156,7 +153,7 @@ fn build_dependencies_inner(config: &Config, info: &DependencyBuilder) -> Result .iter() .find(|package| { package.manifest_path.as_std_path().canonicalize().unwrap() - == manifest_path.canonicalize().unwrap() + == info.crate_manifest_path.canonicalize().unwrap() }) .unwrap(); @@ -217,7 +214,7 @@ fn build_dependencies_inner(config: &Config, info: &DependencyBuilder) -> Result #[derive(Debug, Clone)] pub struct DependencyBuilder { /// Path to a `Cargo.toml` that describes which dependencies the tests can access. - pub crate_manifest_path: Option, + pub crate_manifest_path: PathBuf, /// The command to run can be changed from `cargo` to any custom command to build the /// dependencies in `crate_manifest_path`. pub program: CommandBuilder, @@ -226,7 +223,7 @@ pub struct DependencyBuilder { impl Default for DependencyBuilder { fn default() -> Self { Self { - crate_manifest_path: None, + crate_manifest_path: PathBuf::from("Cargo.toml"), program: CommandBuilder::cargo(), } } diff --git a/tests/integrations/basic-bin/tests/ui_tests.rs b/tests/integrations/basic-bin/tests/ui_tests.rs index b6444e0d..5afc5d70 100644 --- a/tests/integrations/basic-bin/tests/ui_tests.rs +++ b/tests/integrations/basic-bin/tests/ui_tests.rs @@ -13,10 +13,7 @@ fn main() -> ui_test::color_eyre::Result<()> { }; config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); config.stderr_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); diff --git a/tests/integrations/basic-fail-mode/tests/run_file.rs b/tests/integrations/basic-fail-mode/tests/run_file.rs index 37cb0d77..8f09be22 100644 --- a/tests/integrations/basic-fail-mode/tests/run_file.rs +++ b/tests/integrations/basic-fail-mode/tests/run_file.rs @@ -57,10 +57,7 @@ fn run_file_no_deps() -> Result<()> { config.program.args.push("--emit=metadata".into()); config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); let mut result = ui_test::test_command( diff --git a/tests/integrations/basic-fail-mode/tests/ui_tests.rs b/tests/integrations/basic-fail-mode/tests/ui_tests.rs index 448a2b7f..eeb69753 100644 --- a/tests/integrations/basic-fail-mode/tests/ui_tests.rs +++ b/tests/integrations/basic-fail-mode/tests/ui_tests.rs @@ -17,10 +17,7 @@ fn main() -> ui_test::color_eyre::Result<()> { .into(); config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); config.stderr_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); diff --git a/tests/integrations/basic-fail/Cargo.stderr b/tests/integrations/basic-fail/Cargo.stderr index 6039a950..e8e8b363 100644 --- a/tests/integrations/basic-fail/Cargo.stderr +++ b/tests/integrations/basic-fail/Cargo.stderr @@ -6,7 +6,7 @@ error: test failed, to rerun pass `--test ui_tests` Caused by: process didn't exit successfully: `$DIR/target/ui/tests/integrations/basic-fail/debug/deps/ui_tests-HASH` (exit status: 1) -thread 'main' panicked at tests/ui_tests_bless.rs:67:18: +thread 'main' panicked at tests/ui_tests_bless.rs:64:18: invalid mode/result combo: yolo: Err(tests failed Location: diff --git a/tests/integrations/basic-fail/tests/ui_tests.rs b/tests/integrations/basic-fail/tests/ui_tests.rs index 63447780..7143af0e 100644 --- a/tests/integrations/basic-fail/tests/ui_tests.rs +++ b/tests/integrations/basic-fail/tests/ui_tests.rs @@ -11,10 +11,7 @@ fn main() -> ui_test::color_eyre::Result<()> { config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); // hide binaries generated for successfully passing tests diff --git a/tests/integrations/basic-fail/tests/ui_tests_bless.rs b/tests/integrations/basic-fail/tests/ui_tests_bless.rs index d1f2ad2f..f498c604 100644 --- a/tests/integrations/basic-fail/tests/ui_tests_bless.rs +++ b/tests/integrations/basic-fail/tests/ui_tests_bless.rs @@ -38,10 +38,7 @@ fn main() -> ui_test::color_eyre::Result<()> { config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); // hide binaries generated for successfully passing tests diff --git a/tests/integrations/basic/tests/run_file.rs b/tests/integrations/basic/tests/run_file.rs index ed275912..b78fafa1 100644 --- a/tests/integrations/basic/tests/run_file.rs +++ b/tests/integrations/basic/tests/run_file.rs @@ -39,10 +39,7 @@ fn run_file_with_deps() -> Result<()> { config.program.args.push("--emit=metadata".into()); config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); let mut result = ui_test::test_command( diff --git a/tests/integrations/basic/tests/ui_tests.rs b/tests/integrations/basic/tests/ui_tests.rs index fe5a6193..d993c213 100644 --- a/tests/integrations/basic/tests/ui_tests.rs +++ b/tests/integrations/basic/tests/ui_tests.rs @@ -17,10 +17,7 @@ fn main() -> ui_test::color_eyre::Result<()> { config.path_stderr_filter(&std::path::Path::new(path), "$DIR"); config.comment_defaults.base().custom.insert( "dependencies", - Spanned::dummy(vec![Box::new(DependencyBuilder { - crate_manifest_path: Some("Cargo.toml".into()), - ..Default::default() - })]), + Spanned::dummy(vec![Box::new(DependencyBuilder::default())]), ); if let Ok(target) = std::env::var("UITEST_TEST_TARGET") { From 386c8ccca434f7f9e9c73b430f77afabd9fb7309 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 7 Apr 2024 23:02:36 +0200 Subject: [PATCH 9/9] Separate cargo and rustc output processing also re-use cargo_metadata data structures instead of rolling our own --- src/config.rs | 5 +- src/diagnostics.rs | 16 ++++ src/rustc_stderr.rs | 227 +++++++++++++++++++++----------------------- 3 files changed, 127 insertions(+), 121 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7a8e6293..2e8201ce 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,7 +6,7 @@ use spanned::Spanned; use crate::{ aux_builds::AuxBuilder, build_manager::BuildManager, custom_flags::run::Run, custom_flags::rustfix::RustfixMode, custom_flags::Flag, filter::Match, - per_test_config::TestConfig, Errored, Mode, + per_test_config::TestConfig, rustc_stderr, Errored, Mode, }; use crate::{ diagnostics::Diagnostics, @@ -68,8 +68,6 @@ impl Config { /// `rustc` on the test files. #[cfg(feature = "rustc")] pub fn rustc(root_dir: impl Into) -> Self { - use crate::rustc_stderr; - let mut comment_defaults = Comments::default(); #[derive(Debug)] @@ -241,6 +239,7 @@ impl Config { let mut this = Self { program: CommandBuilder::cargo(), custom_comments: Default::default(), + diagnostic_extractor: rustc_stderr::process_cargo, ..Self::rustc(root_dir) }; this.comment_defaults.base().custom.clear(); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e36292cd..fbaeefd5 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,5 +1,7 @@ //! Data structures for handling diagnostic output from tests. +use cargo_metadata::diagnostic::DiagnosticLevel; + #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] /// The different levels of diagnostic messages and their relative ranking. pub enum Level { @@ -17,6 +19,20 @@ pub enum Level { FailureNote = 0, } +impl From for Level { + fn from(value: DiagnosticLevel) -> Self { + match value { + DiagnosticLevel::Ice => Level::Ice, + DiagnosticLevel::Error => Level::Error, + DiagnosticLevel::Warning => Level::Warn, + DiagnosticLevel::FailureNote => Level::FailureNote, + DiagnosticLevel::Note => Level::Note, + DiagnosticLevel::Help => Level::Help, + other => panic!("rustc got a new kind of diagnostic level: {other:?}"), + } + } +} + impl std::str::FromStr for Level { type Err = String; fn from_str(s: &str) -> Result { diff --git a/src/rustc_stderr.rs b/src/rustc_stderr.rs index f243c286..f95a1756 100644 --- a/src/rustc_stderr.rs +++ b/src/rustc_stderr.rs @@ -1,117 +1,79 @@ use bstr::ByteSlice; +use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan}; use regex::Regex; -use std::{ - num::NonZeroUsize, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; use crate::diagnostics::{Diagnostics, Message}; -#[derive(serde::Deserialize, Debug)] -struct RustcDiagnosticCode { - code: String, +fn diag_line(diag: &Diagnostic, file: &Path) -> Option { + let span = |primary| { + diag.spans + .iter() + .find_map(|span| span_line(span, file, primary)) + }; + span(true).or_else(|| span(false)) } -#[derive(serde::Deserialize, Debug)] -struct RustcMessage { - rendered: Option, - spans: Vec, - level: String, - message: String, - children: Vec, - code: Option, -} - -/// Information about macro expansion. -#[derive(serde::Deserialize, Debug)] -struct Expansion { - span: RustcSpan, -} - -#[derive(serde::Deserialize, Debug)] -struct RustcSpan { - #[serde(flatten)] - line_col: Span, - file_name: PathBuf, - is_primary: bool, - expansion: Option>, -} - -#[derive(serde::Deserialize, Debug, Copy, Clone)] -struct Span { - line_start: NonZeroUsize, - column_start: NonZeroUsize, - line_end: NonZeroUsize, - column_end: NonZeroUsize, -} - -impl RustcMessage { - fn line(&self, file: &Path) -> Option { - let span = |primary| self.spans.iter().find_map(|span| span.line(file, primary)); - span(true).or_else(|| span(false)) - } - - /// Put the message and its children into the line-indexed list. - fn insert_recursive( - self, - file: &Path, - messages: &mut Vec>, - messages_from_unknown_file_or_line: &mut Vec, - line: Option, - ) { - let line = self.line(file).or(line); - let msg = Message { - level: self.level.parse().unwrap(), - message: self.message, - line_col: line.clone(), - code: self.code.map(|x| x.code), - }; - if let Some(line) = line.clone() { - if messages.len() <= line.line_start.get() { - messages.resize_with(line.line_start.get() + 1, Vec::new); - } - messages[line.line_start.get()].push(msg); - // All other messages go into the general bin, unless they are specifically of the - // "aborting due to X previous errors" variety, as we never want to match those. They - // only count the number of errors and provide no useful information about the tests. - } else if !(msg.message.starts_with("aborting due to") - && msg.message.contains("previous error")) - { - messages_from_unknown_file_or_line.push(msg); - } - for child in self.children { - child.insert_recursive( - file, - messages, - messages_from_unknown_file_or_line, - line.clone(), - ) +/// Put the message and its children into the line-indexed list. +fn insert_recursive( + diag: Diagnostic, + file: &Path, + messages: &mut Vec>, + messages_from_unknown_file_or_line: &mut Vec, + line: Option, +) { + let line = diag_line(&diag, file).or(line); + let msg = Message { + level: diag.level.into(), + message: diag.message, + line_col: line.clone(), + code: diag.code.map(|x| x.code), + }; + if let Some(line) = line.clone() { + if messages.len() <= line.line_start.get() { + messages.resize_with(line.line_start.get() + 1, Vec::new); } + messages[line.line_start.get()].push(msg); + // All other messages go into the general bin, unless they are specifically of the + // "aborting due to X previous errors" variety, as we never want to match those. They + // only count the number of errors and provide no useful information about the tests. + } else if !(msg.message.starts_with("aborting due to") + && msg.message.contains("previous error")) + { + messages_from_unknown_file_or_line.push(msg); + } + for child in diag.children { + insert_recursive( + child, + file, + messages, + messages_from_unknown_file_or_line, + line.clone(), + ) } } -impl RustcSpan { - /// Returns the most expanded line number *in the given file*, if possible. - fn line(&self, file: &Path, primary: bool) -> Option { - if let Some(exp) = &self.expansion { - if let Some(line) = exp.span.line(file, !primary || self.is_primary) { - return Some(line); - } else if self.file_name != file { - return if !primary && self.is_primary { - exp.span.line(file, false) - } else { - None - }; - } +/// Returns the most expanded line number *in the given file*, if possible. +fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option { + let file_name = PathBuf::from(&span.file_name); + if let Some(exp) = &span.expansion { + if let Some(line) = span_line(&exp.span, file, !primary || span.is_primary) { + return Some(line); + } else if file_name != file { + return if !primary && span.is_primary { + span_line(&exp.span, file, false) + } else { + None + }; } - ((!primary || self.is_primary) && self.file_name == file).then_some(spanned::Span { - file: self.file_name.clone(), - line_start: self.line_col.line_start, - line_end: self.line_col.line_end, - col_start: self.line_col.column_start, - col_end: self.line_col.column_end, - }) } + ((!primary || span.is_primary) && file_name == file).then_some(spanned::Span { + file: file_name, + line_start: span.line_start.try_into().unwrap(), + line_end: span.line_end.try_into().unwrap(), + col_start: span.column_start.try_into().unwrap(), + col_end: span.column_end.try_into().unwrap(), + }) } fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { @@ -125,23 +87,19 @@ pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { let mut messages_from_unknown_file_or_line = vec![]; for line in stderr.lines_with_terminator() { if line.starts_with_str(b"{") { - match serde_json::from_slice::(line) { - Ok(msg) => { - rendered.extend( - filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()).as_bytes(), - ); - msg.insert_recursive( - file, - &mut messages, - &mut messages_from_unknown_file_or_line, - None, - ); - } - Err(_) => { - // FIXME: add a way to swap out the `process` function, so that cargo can use a different one from rustc - // The RustcMessage json just happens to match between the two - } - } + let msg = + serde_json::from_slice::(line).unwrap(); + + rendered.extend( + filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()).as_bytes(), + ); + insert_recursive( + msg, + file, + &mut messages, + &mut messages_from_unknown_file_or_line, + None, + ); } else { // FIXME: do we want to throw interpreter stderr into a separate file? rendered.extend(line); @@ -153,3 +111,36 @@ pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { messages_from_unknown_file_or_line, } } + +pub(crate) fn process_cargo(file: &Path, stderr: &[u8]) -> Diagnostics { + let mut rendered = Vec::new(); + let mut messages = vec![]; + let mut messages_from_unknown_file_or_line = vec![]; + for message in cargo_metadata::Message::parse_stream(stderr) { + match message.unwrap() { + cargo_metadata::Message::CompilerMessage(msg) => { + let msg = msg.message; + rendered.extend( + filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()).as_bytes(), + ); + insert_recursive( + msg, + file, + &mut messages, + &mut messages_from_unknown_file_or_line, + None, + ); + } + cargo_metadata::Message::TextLine(line) => { + rendered.extend(line.bytes()); + rendered.push(b'\n') + } + _ => {} + } + } + Diagnostics { + rendered, + messages, + messages_from_unknown_file_or_line, + } +}