Skip to content

Commit 65b9947

Browse files
authored
Merge pull request #297 from oli-obk/push-uuyxytltvwqn
Make `Errored` debug rendering readable
2 parents 57ef8f5 + a97d3f4 commit 65b9947

File tree

12 files changed

+101
-126
lines changed

12 files changed

+101
-126
lines changed

examples/rustc_basic.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
#[cfg(feature = "rustc")]
2-
use std::sync::atomic::Ordering;
3-
#[cfg(feature = "rustc")]
42
use ui_test::{run_tests, Config};
53

64
#[cfg(feature = "rustc")]
75
#[cfg_attr(test, test)]
86
fn main() -> ui_test::color_eyre::Result<()> {
97
let config = Config::rustc("examples_tests/rustc_basic");
108
let abort_check = config.abort_check.clone();
11-
ctrlc::set_handler(move || abort_check.store(true, Ordering::Relaxed))?;
9+
ctrlc::set_handler(move || abort_check.abort())?;
1210

1311
// Compile all `.rs` files in the given directory (relative to your
1412
// Cargo.toml) and compare their output against the corresponding

examples/rustc_twice_with_different_flags.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
#[cfg(feature = "rustc")]
2-
use std::sync::atomic::Ordering;
3-
#[cfg(feature = "rustc")]
42
use ui_test::{
53
default_file_filter, default_per_file_config, run_tests_generic, status_emitter, Config,
64
};
@@ -10,7 +8,7 @@ use ui_test::{
108
fn main() -> ui_test::color_eyre::Result<()> {
119
let config = Config::rustc("examples_tests/rustc_basic");
1210
let abort_check = config.abort_check.clone();
13-
ctrlc::set_handler(move || abort_check.store(true, Ordering::Relaxed))?;
11+
ctrlc::set_handler(move || abort_check.abort())?;
1412

1513
// Compile all `.rs` files in the given directory (relative to your
1614
// Cargo.toml) and compare their output against the corresponding

src/aux_builds.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl Build for AuxBuilder {
122122

123123
aux_cmd.arg("--emit=link");
124124
let filename = self.aux_file.file_stem().unwrap().to_str().unwrap();
125-
let output = aux_cmd.output().unwrap();
125+
let output = config.config.run_command(&mut aux_cmd)?;
126126
if !output.status.success() {
127127
let error = Error::Command {
128128
kind: "compilation of aux build failed".to_string(),
@@ -138,11 +138,7 @@ impl Build for AuxBuilder {
138138

139139
// Now run the command again to fetch the output filenames
140140
aux_cmd.arg("--print").arg("file-names");
141-
let output = aux_cmd.output().unwrap();
142-
143-
if build_manager.aborted() {
144-
return Err(Errored::aborted());
145-
}
141+
let output = config.config.run_command(&mut aux_cmd)?;
146142

147143
assert!(output.status.success());
148144

src/build_manager.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! Auxiliary and dependency builder. Extendable to custom builds.
22
33
use crate::{
4+
per_test_config::TestConfig,
45
status_emitter::{RevisionStyle, TestStatus},
5-
test_result::TestRun,
6+
test_result::{TestResult, TestRun},
67
Config, Errored,
78
};
89
use color_eyre::eyre::Result;
@@ -27,7 +28,7 @@ pub trait Build {
2728
pub struct BuildManager {
2829
#[allow(clippy::type_complexity)]
2930
cache: RwLock<HashMap<String, Arc<OnceLock<Result<Vec<OsString>, ()>>>>>,
30-
config: Config,
31+
pub(crate) config: Config,
3132
new_job_submitter: Sender<NewJob>,
3233
}
3334

@@ -52,12 +53,24 @@ impl BuildManager {
5253

5354
/// Lazily add more jobs after a test has finished. These are added to the queue
5455
/// as normally, but nested below the test.
55-
pub fn add_new_job(&self, job: impl Send + 'static + FnOnce() -> TestRun) {
56+
pub fn add_new_job(
57+
&self,
58+
mut config: TestConfig,
59+
job: impl Send + 'static + FnOnce(&mut TestConfig) -> TestResult,
60+
) {
5661
if self.aborted() {
5762
return;
5863
}
5964
self.new_job_submitter
60-
.send(Box::new(move |sender| Ok(sender.send(job())?)))
65+
.send(Box::new(move |sender| {
66+
let result = job(&mut config);
67+
let result = TestRun {
68+
result,
69+
status: config.status,
70+
abort_check: config.config.abort_check,
71+
};
72+
Ok(sender.send(result)?)
73+
}))
6174
.unwrap()
6275
}
6376

@@ -143,6 +156,6 @@ impl BuildManager {
143156

144157
/// Whether the build was cancelled
145158
pub fn aborted(&self) -> bool {
146-
self.config.aborted()
159+
self.config.abort_check.aborted()
147160
}
148161
}

src/config.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
diagnostics::{self, Diagnostics},
99
parser::CommandParserFunc,
1010
per_test_config::{Comments, Condition},
11-
CommandBuilder, Error, Errors,
11+
CommandBuilder, Error, Errored, Errors,
1212
};
1313
use color_eyre::eyre::Result;
1414
use regex::bytes::Regex;
@@ -17,6 +17,7 @@ use std::{
1717
collections::BTreeMap,
1818
num::NonZeroUsize,
1919
path::{Path, PathBuf},
20+
process::{Command, Output},
2021
sync::{atomic::AtomicBool, Arc},
2122
};
2223

@@ -61,10 +62,26 @@ pub struct Config {
6162
pub custom_comments: BTreeMap<&'static str, CommandParserFunc>,
6263
/// Custom diagnostic extractor (invoked on the output of tests)
6364
pub diagnostic_extractor: fn(&Path, &[u8]) -> Diagnostics,
64-
/// An atomic bool that can be set to `true` to abort all tests.
65-
/// Will not cancel child processes, but if set from a Ctrl+C handler,
66-
/// the pressing of Ctrl+C will already have cancelled child processes.
67-
pub abort_check: Arc<AtomicBool>,
65+
/// Handle to the global abort check.
66+
pub abort_check: AbortCheck,
67+
}
68+
69+
/// An atomic bool that can be set to `true` to abort all tests.
70+
/// Will not cancel child processes, but if set from a Ctrl+C handler,
71+
/// the pressing of Ctrl+C will already have cancelled child processes.
72+
#[derive(Clone, Debug, Default)]
73+
pub struct AbortCheck(Arc<AtomicBool>);
74+
75+
impl AbortCheck {
76+
/// Whether any test has been aborted.
77+
pub fn aborted(&self) -> bool {
78+
self.0.load(std::sync::atomic::Ordering::Relaxed)
79+
}
80+
81+
/// Inform everyone that an abort has been requested
82+
pub fn abort(&self) {
83+
self.0.store(true, std::sync::atomic::Ordering::Relaxed)
84+
}
6885
}
6986

7087
/// Function that performs the actual output conflict handling.
@@ -438,8 +455,27 @@ impl Config {
438455
^ self.run_only_ignored
439456
}
440457

441-
pub(crate) fn aborted(&self) -> bool {
442-
self.abort_check.load(std::sync::atomic::Ordering::Relaxed)
458+
pub(crate) fn aborted(&self) -> Result<(), Errored> {
459+
if self.abort_check.aborted() {
460+
Err(Errored::aborted())
461+
} else {
462+
Ok(())
463+
}
464+
}
465+
466+
pub(crate) fn run_command(&self, cmd: &mut Command) -> Result<Output, Errored> {
467+
self.aborted()?;
468+
469+
let output = cmd.output().map_err(|err| Errored {
470+
errors: vec![],
471+
stderr: err.to_string().into_bytes(),
472+
stdout: format!("could not spawn `{:?}` as a process", cmd.get_program()).into_bytes(),
473+
command: format!("{cmd:?}"),
474+
})?;
475+
476+
self.aborted()?;
477+
478+
Ok(output)
443479
}
444480
}
445481

src/core.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Basic operations useful for building a testsuite
22
3-
use crate::test_result::Errored;
43
use color_eyre::eyre::Result;
54
use crossbeam_channel::unbounded;
65
use crossbeam_channel::Receiver;
@@ -10,23 +9,9 @@ use std::num::NonZeroUsize;
109
use std::path::Component;
1110
use std::path::Path;
1211
use std::path::Prefix;
13-
use std::process::Command;
14-
use std::process::Output;
1512
use std::sync::OnceLock;
1613
use std::thread;
1714

18-
pub(crate) fn run_command(cmd: &mut Command) -> Result<Output, Errored> {
19-
match cmd.output() {
20-
Err(err) => Err(Errored {
21-
errors: vec![],
22-
stderr: err.to_string().into_bytes(),
23-
stdout: format!("could not spawn `{:?}` as a process", cmd.get_program()).into_bytes(),
24-
command: format!("{cmd:?}"),
25-
}),
26-
Ok(output) => Ok(output),
27-
}
28-
}
29-
3015
/// Remove the common prefix of this path and the `root_dir`.
3116
pub(crate) fn strip_path_prefix<'a>(
3217
path: &'a Path,

src/custom_flags/run.rs

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use super::Flag;
44
use crate::{
55
build_manager::BuildManager, display, per_test_config::TestConfig,
66
status_emitter::RevisionStyle, CommandBuilder, Error, Errored, OutputConflictHandling, TestOk,
7-
TestRun,
87
};
98
use bstr::ByteSlice;
109
use spanned::Spanned;
@@ -45,16 +44,10 @@ impl Flag for Run {
4544
if let Some(och) = self.output_conflict_handling {
4645
config.config.output_conflict_handling = och;
4746
}
48-
build_manager.add_new_job(move || {
47+
build_manager.add_new_job(config, move |config| {
4948
cmd.arg("--print").arg("file-names");
5049
let output = cmd.output().unwrap();
51-
if config.aborted() {
52-
return TestRun {
53-
result: Err(Errored::aborted()),
54-
status: config.status,
55-
abort_check: config.config.abort_check.clone(),
56-
};
57-
}
50+
config.aborted()?;
5851
assert!(output.status.success(), "{cmd:#?}: {output:#?}");
5952

6053
let mut files = output.stdout.lines();
@@ -81,13 +74,7 @@ impl Flag for Run {
8174
)
8275
});
8376

84-
if config.aborted() {
85-
return TestRun {
86-
result: Err(Errored::aborted()),
87-
status: config.status,
88-
abort_check: config.config.abort_check.clone(),
89-
};
90-
}
77+
config.aborted()?;
9178

9279
let mut errors = vec![];
9380

@@ -108,20 +95,15 @@ impl Flag for Run {
10895
},
10996
})
11097
}
111-
112-
TestRun {
113-
result: if errors.is_empty() {
114-
Ok(TestOk::Ok)
115-
} else {
116-
Err(Errored {
117-
command: format!("{exe:?}"),
118-
errors,
119-
stderr: output.stderr,
120-
stdout: output.stdout,
121-
})
122-
},
123-
status: config.status,
124-
abort_check: config.config.abort_check,
98+
if errors.is_empty() {
99+
Ok(TestOk::Ok)
100+
} else {
101+
Err(Errored {
102+
command: format!("{exe:?}"),
103+
errors,
104+
stderr: output.stderr,
105+
stdout: output.stdout,
106+
})
125107
}
126108
});
127109
Ok(())

src/custom_flags/rustfix.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
display,
77
parser::OptWithLine,
88
per_test_config::{Comments, Revisioned, TestConfig},
9-
Error, Errored, TestOk, TestRun,
9+
Error, Errored, TestOk,
1010
};
1111
use rustfix::{CodeFix, Filter, Suggestion};
1212
use spanned::{Span, Spanned};
@@ -214,11 +214,10 @@ fn compile_fixed(
214214
let mut cmd = fixed_config.build_command(build_manager)?;
215215
cmd.arg("--crate-name")
216216
.arg(format!("__{crate_name}_{}", i + 1));
217-
build_manager.add_new_job(move || {
217+
build_manager.add_new_job(fixed_config, move |fixed_config| {
218218
let output = cmd.output().unwrap();
219-
let result = if fixed_config.aborted() {
220-
Err(Errored::aborted())
221-
} else if output.status.success() {
219+
fixed_config.aborted()?;
220+
if output.status.success() {
222221
Ok(TestOk::Ok)
223222
} else {
224223
let diagnostics = fixed_config.process(&output.stderr);
@@ -242,11 +241,6 @@ fn compile_fixed(
242241
stderr: diagnostics.rendered,
243242
stdout: output.stdout,
244243
})
245-
};
246-
TestRun {
247-
result,
248-
status: fixed_config.status,
249-
abort_check: fixed_config.config.abort_check,
250244
}
251245
});
252246
}

src/dependencies.rs

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,7 @@ fn cfgs(config: &Config) -> Result<Vec<Cfg>, Errored> {
3737
let mut cmd = config.program.build(&config.out_dir);
3838
cmd.arg(cfg);
3939
cmd.arg("--target").arg(config.target.as_ref().unwrap());
40-
let output = match cmd.output() {
41-
Ok(o) => o,
42-
Err(e) => {
43-
return Err(Errored {
44-
command: format!("{cmd:?}"),
45-
stderr: e.to_string().into_bytes(),
46-
stdout: vec![],
47-
errors: vec![],
48-
})
49-
}
50-
};
40+
let output = config.run_command(&mut cmd)?;
5141

5242
if !output.status.success() {
5343
return Err(Errored {
@@ -106,17 +96,7 @@ fn build_dependencies_inner(
10696

10797
build.arg("--message-format=json");
10898

109-
let output = match build.output() {
110-
Err(e) => {
111-
return Err(Errored {
112-
command: format!("{build:?}"),
113-
stderr: e.to_string().into_bytes(),
114-
stdout: vec![],
115-
errors: vec![],
116-
})
117-
}
118-
Ok(o) => o,
119-
};
99+
let output = config.run_command(&mut build)?;
120100

121101
if !output.status.success() {
122102
let stdout = output
@@ -212,17 +192,7 @@ fn build_dependencies_inner(
212192
.arg(&info.crate_manifest_path);
213193
info.program.apply_env(&mut metadata);
214194
set_locking(&mut metadata);
215-
let output = match metadata.output() {
216-
Err(e) => {
217-
return Err(Errored {
218-
command: format!("{metadata:?}"),
219-
errors: vec![],
220-
stderr: e.to_string().into_bytes(),
221-
stdout: vec![],
222-
})
223-
}
224-
Ok(output) => output,
225-
};
195+
let output = config.run_command(&mut metadata)?;
226196

227197
if !output.status.success() {
228198
return Err(Errored {

0 commit comments

Comments
 (0)