Skip to content

Commit 3b00aca

Browse files
authored
Merge pull request #130 from oli-obk/like_libtest
Some performance related changes
2 parents f083a70 + 29cc338 commit 3b00aca

17 files changed

+89
-103
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.13.0"
3+
version = "0.14.0"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
description = "A test framework for testing rustc diagnostics output"

src/config.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ pub use color_eyre;
55
use color_eyre::eyre::Result;
66
use std::{
77
ffi::OsString,
8-
num::NonZeroUsize,
98
path::{Component, Path, PathBuf, Prefix},
109
};
1110

@@ -45,8 +44,6 @@ pub struct Config {
4544
/// The command to run can be changed from `cargo` to any custom command to build the
4645
/// dependencies in `dependencies_crate_manifest_path`
4746
pub dependency_builder: CommandBuilder,
48-
/// How many threads to use for running tests. Defaults to number of cores
49-
pub num_test_threads: NonZeroUsize,
5047
/// Where to dump files like the binaries compiled from tests.
5148
/// Defaults to `target/ui` in the current directory.
5249
pub out_dir: PathBuf,
@@ -88,7 +85,6 @@ impl Config {
8885
)),
8986
dependencies_crate_manifest_path: None,
9087
dependency_builder: CommandBuilder::cargo(),
91-
num_test_threads: std::thread::available_parallelism().unwrap(),
9288
out_dir: std::env::var_os("CARGO_TARGET_DIR")
9389
.map(PathBuf::from)
9490
.unwrap_or_else(|| std::env::current_dir().unwrap().join("target"))

src/lib.rs

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ pub fn run_tests(config: Config) -> Result<()> {
132132
};
133133

134134
run_tests_generic(
135-
config,
135+
vec![config],
136+
std::thread::available_parallelism().unwrap(),
136137
args,
137138
default_file_filter,
138139
default_per_file_config,
@@ -142,7 +143,7 @@ pub fn run_tests(config: Config) -> Result<()> {
142143

143144
/// The filter used by `run_tests` to only run on `.rs` files
144145
/// and those specified in the command line args.
145-
pub fn default_file_filter(path: &Path, args: &Args) -> bool {
146+
pub fn default_file_filter(path: &Path, args: &Args, _config: &Config) -> bool {
146147
path.extension().is_some_and(|ext| ext == "rs") && default_filter_by_arg(path, args)
147148
}
148149

@@ -156,13 +157,11 @@ pub fn default_filter_by_arg(path: &Path, args: &Args) -> bool {
156157
}
157158

158159
/// The default per-file config used by `run_tests`.
159-
pub fn default_per_file_config(config: &Config, path: &Path) -> Option<Config> {
160-
let mut config = config.clone();
160+
pub fn default_per_file_config(config: &mut Config, file_contents: &[u8]) {
161161
// Heuristic:
162162
// * if the file contains `#[test]`, automatically pass `--cfg test`.
163163
// * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`.
164164
// This avoids having to spam `fn main() {}` in almost every test.
165-
let file_contents = std::fs::read(path).unwrap();
166165
if file_contents.find(b"#[proc_macro").is_some() {
167166
config.program.args.push("--crate-type=proc-macro".into())
168167
} else if file_contents.find(b"#[test]").is_some() {
@@ -172,7 +171,6 @@ pub fn default_per_file_config(config: &Config, path: &Path) -> Option<Config> {
172171
{
173172
config.program.args.push("--crate-type=lib".into());
174173
}
175-
Some(config)
176174
}
177175

178176
/// Create a command for running a single file, with the settings from the `config` argument.
@@ -220,24 +218,29 @@ struct TestRun {
220218

221219
/// A version of `run_tests` that allows more fine-grained control over running tests.
222220
pub fn run_tests_generic(
223-
mut config: Config,
221+
mut configs: Vec<Config>,
222+
num_threads: NonZeroUsize,
224223
args: Args,
225-
file_filter: impl Fn(&Path, &Args) -> bool + Sync,
226-
per_file_config: impl Fn(&Config, &Path) -> Option<Config> + Sync,
224+
file_filter: impl Fn(&Path, &Args, &Config) -> bool + Sync,
225+
per_file_config: impl Fn(&mut Config, &[u8]) + Sync,
227226
status_emitter: impl StatusEmitter + Send,
228227
) -> Result<()> {
229-
config.fill_host_and_target()?;
228+
for config in &mut configs {
229+
config.fill_host_and_target()?;
230+
}
230231

231232
let build_manager = BuildManager::new(&status_emitter);
232233

233234
let mut results = vec![];
234235

235236
run_and_collect(
236-
config.num_test_threads.get(),
237+
num_threads,
237238
|submit| {
238239
let mut todo = VecDeque::new();
239-
todo.push_back(config.root_dir.clone());
240-
while let Some(path) = todo.pop_front() {
240+
for config in configs {
241+
todo.push_back((config.root_dir.clone(), config));
242+
}
243+
while let Some((path, config)) = todo.pop_front() {
241244
if path.is_dir() {
242245
if path.file_name().unwrap() == "auxiliary" {
243246
continue;
@@ -250,28 +253,22 @@ pub fn run_tests_generic(
250253
.unwrap();
251254
entries.sort_by_key(|e| e.file_name());
252255
for entry in entries {
253-
todo.push_back(entry.path());
256+
todo.push_back((entry.path(), config.clone()));
254257
}
255-
} else if file_filter(&path, &args) {
258+
} else if file_filter(&path, &args, &config) {
256259
let status = status_emitter.register_test(path);
257260
// Forward .rs files to the test workers.
258-
submit.send(status).unwrap();
261+
submit.send((status, config)).unwrap();
259262
}
260263
}
261264
},
262265
|receive, finished_files_sender| -> Result<()> {
263-
for status in receive {
266+
for (status, mut config) in receive {
264267
let path = status.path();
265-
let maybe_config;
266-
let config = match per_file_config(&config, path) {
267-
None => &config,
268-
Some(config) => {
269-
maybe_config = config;
270-
&maybe_config
271-
}
272-
};
268+
let file_contents = std::fs::read(path).unwrap();
269+
per_file_config(&mut config, &file_contents);
273270
let result = match std::panic::catch_unwind(|| {
274-
parse_and_test_file(&build_manager, &status, config)
271+
parse_and_test_file(&build_manager, &status, &config, file_contents)
275272
}) {
276273
Ok(Ok(res)) => res,
277274
Ok(Err(err)) => {
@@ -351,7 +348,7 @@ pub fn run_tests_generic(
351348
/// A generic multithreaded runner that has a thread for producing work,
352349
/// a thread for collecting work, and `num_threads` threads for doing the work.
353350
pub fn run_and_collect<SUBMISSION: Send, RESULT: Send>(
354-
num_threads: usize,
351+
num_threads: NonZeroUsize,
355352
submitter: impl FnOnce(Sender<SUBMISSION>) + Send,
356353
runner: impl Sync + Fn(&Receiver<SUBMISSION>, Sender<RESULT>) -> Result<()>,
357354
collector: impl FnOnce(Receiver<RESULT>) + Send,
@@ -373,7 +370,7 @@ pub fn run_and_collect<SUBMISSION: Send, RESULT: Send>(
373370
let mut threads = vec![];
374371

375372
// Create N worker threads that receive files to test.
376-
for _ in 0..num_threads {
373+
for _ in 0..num_threads.get() {
377374
let finished_files_sender = finished_files_sender.clone();
378375
threads.push(s.spawn(|| runner(&receive, finished_files_sender)));
379376
}
@@ -389,8 +386,9 @@ fn parse_and_test_file(
389386
build_manager: &BuildManager<'_>,
390387
status: &dyn TestStatus,
391388
config: &Config,
389+
file_contents: Vec<u8>,
392390
) -> Result<Vec<TestRun>, Errored> {
393-
let comments = parse_comments_in_file(status.path())?;
391+
let comments = parse_comments(&file_contents)?;
394392
// Run the test for all revisions
395393
let revisions = comments
396394
.revisions
@@ -413,19 +411,14 @@ fn parse_and_test_file(
413411
.collect())
414412
}
415413

416-
fn parse_comments_in_file(path: &Path) -> Result<Comments, Errored> {
417-
match Comments::parse_file(path) {
418-
Ok(Ok(comments)) => Ok(comments),
419-
Ok(Err(errors)) => Err(Errored {
414+
fn parse_comments(file_contents: &[u8]) -> Result<Comments, Errored> {
415+
match Comments::parse(file_contents) {
416+
Ok(comments) => Ok(comments),
417+
Err(errors) => Err(Errored {
420418
command: Command::new("parse comments"),
421419
errors,
422420
stderr: vec![],
423421
}),
424-
Err(err) => Err(Errored {
425-
command: Command::new("parse comments"),
426-
errors: vec![],
427-
stderr: format!("{err:?}").into(),
428-
}),
429422
}
430423
}
431424

@@ -467,7 +460,8 @@ fn build_aux(
467460
config: &Config,
468461
build_manager: &BuildManager<'_>,
469462
) -> std::result::Result<Vec<OsString>, Errored> {
470-
let comments = parse_comments_in_file(aux_file)?;
463+
let file_contents = std::fs::read(aux_file).unwrap();
464+
let comments = parse_comments(&file_contents)?;
471465
assert_eq!(
472466
comments.revisions, None,
473467
"aux builds cannot specify revisions"
@@ -495,7 +489,7 @@ fn build_aux(
495489
}
496490
});
497491

498-
let mut config = default_per_file_config(&config, aux_file).unwrap();
492+
default_per_file_config(&mut config, &file_contents);
499493

500494
// Put aux builds into a separate directory per path so that multiple aux files
501495
// from different directories (but with the same file name) don't collide.
@@ -615,7 +609,12 @@ impl dyn TestStatus {
615609
.stdout(Stdio::piped())
616610
.stdin(Stdio::null())
617611
.spawn()
618-
.unwrap_or_else(|err| panic!("could not execute {cmd:?}: {err}"));
612+
.unwrap_or_else(|err| {
613+
panic!(
614+
"could not spawn `{:?}` as a process: {err}",
615+
cmd.get_program()
616+
)
617+
});
619618

620619
let stdout = ReadHelper::from(child.stdout.take().unwrap());
621620
let mut stderr = ReadHelper::from(child.stderr.take().unwrap());

tests/integration.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
use std::path::Path;
22

3-
use colored::Colorize;
43
use ui_test::color_eyre::Result;
54
use ui_test::*;
65

76
fn main() -> Result<()> {
8-
run("integrations", Mode::Pass)?;
9-
run("integrations", Mode::Panic)?;
10-
11-
eprintln!("integration tests done");
12-
13-
Ok(())
14-
}
15-
16-
fn run(name: &str, mode: Mode) -> Result<()> {
17-
eprintln!("\n{} `{name}` tests in mode {mode}", "Running".green());
187
let path = Path::new(file!()).parent().unwrap();
19-
let root_dir = path.join(name);
8+
let root_dir = path.join("integrations");
209
let mut config = Config {
21-
mode,
2210
..Config::cargo(root_dir.clone())
2311
};
2412
let args = Args::test();
@@ -85,9 +73,19 @@ fn run(name: &str, mode: Mode) -> Result<()> {
8573
};
8674

8775
run_tests_generic(
88-
config,
76+
vec![
77+
Config {
78+
mode: Mode::Pass,
79+
..config.clone()
80+
},
81+
Config {
82+
mode: Mode::Panic,
83+
..config
84+
},
85+
],
86+
std::thread::available_parallelism().unwrap(),
8987
args,
90-
|path, args| {
88+
|path, args, config| {
9189
let fail = path
9290
.parent()
9391
.unwrap()
@@ -102,7 +100,7 @@ fn run(name: &str, mode: Mode) -> Result<()> {
102100
}
103101
path.ends_with("Cargo.toml")
104102
&& path.parent().unwrap().parent().unwrap() == root_dir
105-
&& match mode {
103+
&& match config.mode {
106104
Mode::Pass => !fail,
107105
// This is weird, but `cargo test` returns 101 instead of 1 when
108106
// multiple [[test]]s exist. If there's only one test, it returns
@@ -112,11 +110,11 @@ fn run(name: &str, mode: Mode) -> Result<()> {
112110
}
113111
&& default_filter_by_arg(path, args)
114112
},
115-
|_, _| None,
113+
|_, _| {},
116114
(
117115
text,
118116
ui_test::status_emitter::Gha::<true> {
119-
name: format!("{mode:?}"),
117+
name: "integration tests".into(),
120118
},
121119
),
122120
)

tests/integrations/basic-bin/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.

tests/integrations/basic-bin/tests/ui_tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ fn main() -> ui_test::color_eyre::Result<()> {
2323
config.path_stderr_filter(tmp_dir, "$$TMP");
2424

2525
run_tests_generic(
26-
config,
26+
vec![config],
27+
std::num::NonZeroUsize::new(1).unwrap(),
2728
Args::test(),
2829
default_file_filter,
2930
default_per_file_config,

tests/integrations/basic-fail-mode/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.

tests/integrations/basic-fail-mode/tests/ui_tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ fn main() -> ui_test::color_eyre::Result<()> {
1919
config.path_stderr_filter(&std::path::Path::new(path), "$DIR");
2020

2121
run_tests_generic(
22-
config,
22+
vec![config],
23+
std::num::NonZeroUsize::new(1).unwrap(),
2324
Args::test(),
2425
default_file_filter,
2526
default_per_file_config,

tests/integrations/basic-fail/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.

0 commit comments

Comments
 (0)