Skip to content

Commit ead774c

Browse files
authored
Merge pull request #157 from Alexendoo/args-to-config
Populate `Config` with `Args` instead of passing it to `run_tests_generic`
2 parents 73dcb41 + 38c018f commit ead774c

File tree

23 files changed

+207
-125
lines changed

23 files changed

+207
-125
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ui_test"
3-
version = "0.19.1"
3+
version = "0.20.0"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
description = "A test framework for testing rustc diagnostics output"

src/cmd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl CommandBuilder {
4848
}
4949
}
5050

51-
/// Same as [`rustc`], but with arguments for obtaining the cfgs.
51+
/// Same as [`CommandBuilder::rustc`], but with arguments for obtaining the cfgs.
5252
pub fn cfgs() -> Self {
5353
Self {
5454
args: vec!["--print".into(), "cfg".into()],

src/config.rs

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub use color_eyre;
55
use color_eyre::eyre::Result;
66
use std::{
77
ffi::OsString,
8+
num::NonZeroUsize,
89
path::{Path, PathBuf},
910
};
1011

@@ -34,16 +35,24 @@ pub struct Config {
3435
pub program: CommandBuilder,
3536
/// The command to run to obtain the cfgs that the output is supposed to
3637
pub cfgs: CommandBuilder,
38+
/// What to do in case the stdout/stderr output differs from the expected one.
39+
pub output_conflict_handling: OutputConflictHandling,
3740
/// Path to a `Cargo.toml` that describes which dependencies the tests can access.
3841
pub dependencies_crate_manifest_path: Option<PathBuf>,
3942
/// The command to run can be changed from `cargo` to any custom command to build the
40-
/// dependencies in `dependencies_crate_manifest_path`
43+
/// dependencies in `dependencies_crate_manifest_path`.
4144
pub dependency_builder: CommandBuilder,
4245
/// Where to dump files like the binaries compiled from tests.
4346
/// Defaults to `target/ui` in the current directory.
4447
pub out_dir: PathBuf,
45-
/// The default edition to use on all tests
48+
/// The default edition to use on all tests.
4649
pub edition: Option<String>,
50+
/// Skip test files whose names contain any of these entries.
51+
pub skip_files: Vec<String>,
52+
/// Only test files whose names contain any of these entries.
53+
pub filter_files: Vec<String>,
54+
/// Override the number of threads to use.
55+
pub threads: Option<NonZeroUsize>,
4756
}
4857

4958
impl Config {
@@ -74,13 +83,17 @@ impl Config {
7483
},
7584
program: CommandBuilder::rustc(),
7685
cfgs: CommandBuilder::cfgs(),
86+
output_conflict_handling: OutputConflictHandling::Bless,
7787
dependencies_crate_manifest_path: None,
7888
dependency_builder: CommandBuilder::cargo(),
7989
out_dir: std::env::var_os("CARGO_TARGET_DIR")
8090
.map(PathBuf::from)
8191
.unwrap_or_else(|| std::env::current_dir().unwrap().join("target"))
8292
.join("ui"),
8393
edition: Some("2021".into()),
94+
skip_files: Vec::new(),
95+
filter_files: Vec::new(),
96+
threads: None,
8497
}
8598
}
8699

@@ -98,6 +111,44 @@ impl Config {
98111
}
99112
}
100113

114+
/// Populate the config with the values from parsed command line arguments.
115+
/// If neither `--bless` or `--check` are provided `default_bless` is used.
116+
///
117+
/// The default output conflict handling command suggests adding `--bless`
118+
/// to the end of the current command.
119+
pub fn with_args(&mut self, args: &Args, default_bless: bool) {
120+
let Args {
121+
ref filters,
122+
quiet: _,
123+
check,
124+
bless,
125+
threads,
126+
ref skip,
127+
} = *args;
128+
129+
self.threads = threads.or(self.threads);
130+
131+
self.filter_files.extend_from_slice(filters);
132+
self.skip_files.extend_from_slice(skip);
133+
134+
let bless = match (bless, check) {
135+
(_, true) => false,
136+
(true, _) => true,
137+
_ => default_bless,
138+
};
139+
self.output_conflict_handling = if bless {
140+
OutputConflictHandling::Bless
141+
} else {
142+
OutputConflictHandling::Error(format!(
143+
"{} --bless",
144+
std::env::args()
145+
.map(|s| format!("{s:?}"))
146+
.collect::<Vec<_>>()
147+
.join(" ")
148+
))
149+
};
150+
}
151+
101152
/// Replace all occurrences of a path in stderr/stdout with a byte string.
102153
pub fn path_filter(&mut self, path: &Path, replacement: &'static (impl AsRef<[u8]> + ?Sized)) {
103154
self.path_stderr_filter(path, replacement);
@@ -154,8 +205,8 @@ impl Config {
154205

155206
/// Compile dependencies and return the right flags
156207
/// to find the dependencies.
157-
pub fn build_dependencies(&self, args: &Args) -> Result<Vec<OsString>> {
158-
let dependencies = build_dependencies(args, self)?;
208+
pub fn build_dependencies(&self) -> Result<Vec<OsString>> {
209+
let dependencies = build_dependencies(self)?;
159210
let mut args = vec![];
160211
for (name, artifacts) in dependencies.dependencies {
161212
for dependency in artifacts {
@@ -207,3 +258,15 @@ impl Config {
207258
.any(|arch| self.target.as_ref().unwrap().contains(arch))
208259
}
209260
}
261+
262+
#[derive(Debug, Clone)]
263+
/// The different options for what to do when stdout/stderr files differ from the actual output.
264+
pub enum OutputConflictHandling {
265+
/// The string should be a command that can be executed to bless all tests.
266+
Error(String),
267+
/// Ignore mismatches in the stderr/stdout files.
268+
Ignore,
269+
/// Instead of erroring if the stderr/stdout differs from the expected
270+
/// automatically replace it with the found output (after applying filters).
271+
Bless,
272+
}

src/config/args.rs

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
44
use std::{borrow::Cow, num::NonZeroUsize};
55

6-
use color_eyre::eyre::{bail, ensure, eyre, Result};
6+
use color_eyre::eyre::{bail, ensure, Result};
77

88
/// Plain arguments if `ui_test` is used as a binary.
9-
#[derive(Debug)]
9+
#[derive(Debug, Default)]
1010
pub struct Args {
1111
/// Filters that will be used to match on individual tests
1212
pub filters: Vec<String>,
@@ -23,37 +23,17 @@ pub struct Args {
2323
pub bless: bool,
2424

2525
/// The number of threads to use
26-
pub threads: NonZeroUsize,
26+
pub threads: Option<NonZeroUsize>,
2727

2828
/// Skip tests whose names contain any of these entries.
2929
pub skip: Vec<String>,
3030
}
3131

3232
impl Args {
33-
/// Dummy arguments, but with the number of threads loaded from the environment.
34-
/// The boolearn argument decides whether to bless (`true`) or whether to error (`false`)
35-
pub fn default(bless: bool) -> Result<Self> {
36-
Ok(Args {
37-
filters: vec![],
38-
quiet: false,
39-
bless,
40-
check: !bless,
41-
skip: vec![],
42-
threads: match std::env::var_os("RUST_TEST_THREADS") {
43-
None => std::thread::available_parallelism()?,
44-
Some(n) => n
45-
.to_str()
46-
.ok_or_else(|| eyre!("could not parse RUST_TEST_THREADS env var"))?
47-
.parse()?,
48-
},
49-
})
50-
}
51-
5233
/// Parse the program arguments.
5334
/// This is meant to be used if `ui_test` is used as a `harness=false` test, called from `cargo test`.
54-
/// The boolearn argument decides whether to bless (`true`) or whether to error (`false`)
55-
pub fn test(bless: bool) -> Result<Self> {
56-
Self::default(bless)?.parse_args(std::env::args().skip(1))
35+
pub fn test() -> Result<Self> {
36+
Self::default().parse_args(std::env::args().skip(1))
5737
}
5838

5939
/// Parse arguments into an existing `Args` struct.
@@ -73,7 +53,7 @@ impl Args {
7353
} else if arg == "--help" {
7454
bail!("available flags: --quiet, --check, --bless, --test-threads=n, --skip")
7555
} else if let Some(n) = parse_value("--test-threads", &arg, &mut iter)? {
76-
self.threads = n.parse()?;
56+
self.threads = Some(n.parse()?);
7757
} else if arg.starts_with("--") {
7858
bail!(
7959
"unknown command line flag `{arg}`: {:?}",

src/dependencies.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use std::{
1010
sync::{Arc, OnceLock, RwLock},
1111
};
1212

13-
use crate::{build_aux, status_emitter::StatusEmitter, Args, Config, Errored, Mode};
13+
use crate::{
14+
build_aux, status_emitter::StatusEmitter, Config, Errored, Mode, OutputConflictHandling,
15+
};
1416

1517
#[derive(Default, Debug)]
1618
pub struct Dependencies {
@@ -43,7 +45,7 @@ fn cfgs(config: &Config) -> Result<Vec<Cfg>> {
4345
}
4446

4547
/// Compiles dependencies and returns the crate names and corresponding rmeta files.
46-
pub(crate) fn build_dependencies(args: &Args, config: &Config) -> Result<Dependencies> {
48+
pub(crate) fn build_dependencies(config: &Config) -> Result<Dependencies> {
4749
let manifest_path = match &config.dependencies_crate_manifest_path {
4850
Some(path) => path.to_owned(),
4951
None => return Ok(Default::default()),
@@ -57,10 +59,12 @@ pub(crate) fn build_dependencies(args: &Args, config: &Config) -> Result<Depende
5759
}
5860

5961
// Reusable closure for setting up the environment both for artifact generation and `cargo_metadata`
60-
let set_locking = |cmd: &mut Command| {
61-
if !matches!(config.mode, Mode::Yolo { .. }) && args.check {
62+
let set_locking = |cmd: &mut Command| match (&config.output_conflict_handling, &config.mode) {
63+
(_, Mode::Yolo { .. }) => {}
64+
(OutputConflictHandling::Error(_), _) => {
6265
cmd.arg("--locked");
6366
}
67+
_ => {}
6468
};
6569

6670
set_locking(&mut build);
@@ -233,12 +237,7 @@ impl<'a> BuildManager<'a> {
233237
/// that need to be passed in order to build the dependencies.
234238
/// The error is only reported once, all follow up invocations of the same build will
235239
/// have a generic error about a previous build failing.
236-
pub fn build(
237-
&self,
238-
what: Build,
239-
config: &Config,
240-
args: &Args,
241-
) -> Result<Vec<OsString>, Errored> {
240+
pub fn build(&self, what: Build, config: &Config) -> Result<Vec<OsString>, Errored> {
242241
// Fast path without much contention.
243242
if let Some(res) = self.cache.read().unwrap().get(&what).and_then(|o| o.get()) {
244243
return res.clone().map_err(|()| Errored {
@@ -276,7 +275,7 @@ impl<'a> BuildManager<'a> {
276275
.register_test(what.description().into())
277276
.for_revision("");
278277
let res = match &what {
279-
Build::Dependencies => match config.build_dependencies(args) {
278+
Build::Dependencies => match config.build_dependencies() {
280279
Ok(args) => Ok(args),
281280
Err(e) => {
282281
err = Some(Errored {
@@ -288,7 +287,7 @@ impl<'a> BuildManager<'a> {
288287
Err(())
289288
}
290289
},
291-
Build::Aux { aux_file } => match build_aux(aux_file, config, args, self) {
290+
Build::Aux { aux_file } => match build_aux(aux_file, config, self) {
292291
Ok(args) => Ok(args.iter().map(Into::into).collect()),
293292
Err(e) => {
294293
err = Some(e);

src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub enum Error {
3232
actual: Vec<u8>,
3333
/// The contents of the file.
3434
expected: Vec<u8>,
35+
/// A command, that when run, causes the output to get blessed instead of erroring.
36+
bless_command: String,
3537
},
3638
/// There were errors that don't have a pattern.
3739
ErrorsWithoutPattern {

0 commit comments

Comments
 (0)