Skip to content

Commit 44e2fe7

Browse files
authored
Merge pull request #7 from oli-obk/runtest
dogfood ui_test
2 parents 29f64b6 + bfa382f commit 44e2fe7

File tree

22 files changed

+934
-41
lines changed

22 files changed

+934
-41
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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ui_test"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
description = "A test framework for testing rustc diagnostics output"
@@ -22,3 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
2222
serde_json = "1.0"
2323
color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] }
2424
cargo_metadata = "0.15"
25+
26+
[[test]]
27+
name = "integration"
28+
harness = false

src/lib.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use std::collections::VecDeque;
99
use std::ffi::OsString;
1010
use std::fmt::Write;
11+
use std::num::NonZeroUsize;
1112
use std::path::{Path, PathBuf};
1213
use std::process::{Command, ExitStatus};
1314
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -32,6 +33,8 @@ mod tests;
3233
#[derive(Debug)]
3334
pub struct Config {
3435
/// Arguments passed to the binary that is executed.
36+
/// Take care to only append unless you actually meant to overwrite the defaults.
37+
/// Overwriting the defaults may make `//~ ERROR` style comments stop working.
3538
pub args: Vec<OsString>,
3639
/// `None` to run on the host, otherwise a target triple
3740
pub target: Option<String>,
@@ -53,23 +56,28 @@ pub struct Config {
5356
pub dependency_builder: Option<DependencyBuilder>,
5457
/// Print one character per test instead of one line
5558
pub quiet: bool,
59+
/// How many threads to use for running tests. Defaults to number of cores
60+
pub num_test_threads: NonZeroUsize,
5661
}
5762

5863
impl Default for Config {
5964
fn default() -> Self {
6065
Self {
61-
args: vec![],
66+
args: vec!["--error-format=json".into()],
6267
target: None,
6368
stderr_filters: vec![],
6469
stdout_filters: vec![],
6570
root_dir: PathBuf::new(),
66-
mode: Mode::Fail,
71+
mode: Mode::Fail {
72+
require_patterns: true,
73+
},
6774
program: PathBuf::from("rustc"),
6875
output_conflict_handling: OutputConflictHandling::Error,
6976
path_filter: vec![],
7077
dependencies_crate_manifest_path: None,
7178
dependency_builder: None,
7279
quiet: true,
80+
num_test_threads: std::thread::available_parallelism().unwrap(),
7381
}
7482
}
7583
}
@@ -104,9 +112,6 @@ pub type Filter = Vec<(Regex, &'static str)>;
104112
pub fn run_tests(mut config: Config) -> Result<()> {
105113
eprintln!(" Compiler flags: {:?}", config.args);
106114

107-
// Get the triple with which to run the tests
108-
let target = config.target.clone().unwrap_or_else(|| config.get_host());
109-
110115
let dependencies = build_dependencies(&config)?;
111116
for (name, dependency) in dependencies.dependencies {
112117
config.args.push("--extern".into());
@@ -119,7 +124,14 @@ pub fn run_tests(mut config: Config) -> Result<()> {
119124
config.args.push("-L".into());
120125
config.args.push(import_path.into());
121126
}
122-
let config = config;
127+
run_tests_generic(config, |path| {
128+
path.extension().map(|ext| ext == "rs").unwrap_or(false)
129+
})
130+
}
131+
132+
pub fn run_tests_generic(config: Config, file_filter: impl Fn(&Path) -> bool + Sync) -> Result<()> {
133+
// Get the triple with which to run the tests
134+
let target = config.target.clone().unwrap_or_else(|| config.get_host());
123135

124136
// A channel for files to process
125137
let (submit, receive) = crossbeam::channel::unbounded();
@@ -148,7 +160,7 @@ pub fn run_tests(mut config: Config) -> Result<()> {
148160
for entry in entries {
149161
todo.push_back(entry.path());
150162
}
151-
} else if path.extension().map(|ext| ext == "rs").unwrap_or(false) {
163+
} else if file_filter(&path) {
152164
// Forward .rs files to the test workers.
153165
submit.send(path).unwrap();
154166
}
@@ -198,7 +210,7 @@ pub fn run_tests(mut config: Config) -> Result<()> {
198210
let mut threads = vec![];
199211

200212
// Create N worker threads that receive files to test.
201-
for _ in 0..std::thread::available_parallelism().unwrap().get() {
213+
for _ in 0..config.num_test_threads.get() {
202214
let finished_files_sender = finished_files_sender.clone();
203215
threads.push(s.spawn(|_| -> Result<()> {
204216
let finished_files_sender = finished_files_sender;
@@ -412,7 +424,6 @@ fn run_test(
412424
if !revision.is_empty() {
413425
miri.arg(format!("--cfg={revision}"));
414426
}
415-
miri.arg("--error-format=json");
416427
for arg in &comments.compile_flags {
417428
miri.arg(arg);
418429
}
@@ -586,7 +597,12 @@ fn check_annotations(
586597
comments.error_pattern.is_some() || !comments.error_matches.is_empty(),
587598
) {
588599
(Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest),
589-
(Mode::Fail, false) => errors.push(Error::NoPatternsFound),
600+
(
601+
Mode::Fail {
602+
require_patterns: true,
603+
},
604+
false,
605+
) => errors.push(Error::NoPatternsFound),
590606
_ => {}
591607
}
592608
}
@@ -695,18 +711,23 @@ impl Config {
695711

696712
#[derive(Copy, Clone, Debug)]
697713
pub enum Mode {
698-
// The test passes a full execution of the rustc driver
714+
/// The test passes a full execution of the rustc driver
699715
Pass,
700-
// The rustc driver panicked
716+
/// The rustc driver panicked
701717
Panic,
702-
// The rustc driver emitted an error
703-
Fail,
718+
/// The rustc driver emitted an error
719+
Fail {
720+
/// Whether failing tests must have error patterns. Set to false if you just care about .stderr output.
721+
require_patterns: bool,
722+
},
704723
}
705724

706725
impl Mode {
707726
fn ok(self, status: ExitStatus) -> Errors {
708727
match (status.code(), self) {
709-
(Some(1), Mode::Fail) | (Some(101), Mode::Panic) | (Some(0), Mode::Pass) => vec![],
728+
(Some(1), Mode::Fail { .. }) | (Some(101), Mode::Panic) | (Some(0), Mode::Pass) => {
729+
vec![]
730+
}
710731
_ => vec![Error::ExitStatus(self, status)],
711732
}
712733
}

src/tests.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,10 @@ use super::*;
77

88
fn config() -> Config {
99
Config {
10-
args: vec![],
11-
target: None,
12-
stderr_filters: vec![],
13-
stdout_filters: vec![],
1410
root_dir: PathBuf::from("$RUSTROOT"),
15-
mode: Mode::Fail,
16-
path_filter: vec![],
1711
program: PathBuf::from("cake"),
18-
output_conflict_handling: OutputConflictHandling::Error,
19-
dependencies_crate_manifest_path: None,
20-
dependency_builder: None,
2112
quiet: false,
13+
..Config::default()
2214
}
2315
}
2416

tests/integration.rs

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,73 @@
1-
#[test]
2-
fn integrations() {
3-
run("basic");
4-
}
1+
use std::path::Path;
52

6-
fn run(name: &str) {
7-
let path = std::path::Path::new(file!()).parent().unwrap();
3+
use ui_test::color_eyre::Result;
4+
use ui_test::*;
85

9-
let mut cmd = std::process::Command::new(std::env::var_os("CARGO").unwrap());
10-
cmd.arg("test");
6+
fn main() -> Result<()> {
7+
run("integrations", Mode::Pass)?;
8+
run(
9+
"integrations",
10+
Mode::Fail {
11+
require_patterns: false,
12+
},
13+
)
14+
}
1115

12-
cmd.arg("--target-dir");
13-
cmd.arg(path.parent().unwrap().join("target"));
16+
fn run(name: &str, mode: Mode) -> Result<()> {
17+
let path = Path::new(file!()).parent().unwrap();
18+
let root_dir = path.join(name);
19+
let mut config = Config {
20+
root_dir: root_dir.clone(),
21+
args: vec![
22+
"test".into(),
23+
"--color".into(),
24+
"never".into(),
25+
"--target-dir".into(),
26+
path.parent().unwrap().join("target").into(),
27+
"--manifest-path".into(),
28+
],
29+
program: "cargo".into(),
30+
output_conflict_handling: if std::env::var_os("BLESS").is_some() {
31+
OutputConflictHandling::Bless
32+
} else {
33+
OutputConflictHandling::Error
34+
},
35+
mode,
36+
..Config::default()
37+
};
1438

15-
cmd.arg("--manifest-path");
16-
cmd.arg(format!("{}/integrations/{name}/Cargo.toml", path.display()));
39+
config.stderr_filter("in [0-9\\.]+s", "");
40+
config.stderr_filter("( +Running [^(]+).*", "$1");
41+
config.stderr_filter(" *(Compiling|Downloaded|Downloading) .*\n", "");
42+
// The order of the `/deps` directory flag is flaky
43+
config.stderr_filter("/deps", "");
44+
config.stderr_filter(
45+
&std::path::Path::new(path)
46+
.canonicalize()
47+
.unwrap()
48+
.parent()
49+
.unwrap()
50+
.display()
51+
.to_string(),
52+
"$$DIR",
53+
);
54+
config.stderr_filter("[0-9a-f]+\\.rmeta", "$$HASH.rmeta");
1755

18-
assert!(cmd.status().unwrap().success());
56+
run_tests_generic(config, |path| {
57+
let fail = path
58+
.parent()
59+
.unwrap()
60+
.file_name()
61+
.unwrap()
62+
.to_str()
63+
.unwrap()
64+
.ends_with("-fail");
65+
path.ends_with("Cargo.toml")
66+
&& path.parent().unwrap().parent().unwrap() == root_dir
67+
&& match mode {
68+
Mode::Pass => !fail,
69+
Mode::Panic => unreachable!(),
70+
Mode::Fail { .. } => fail,
71+
}
72+
})
1973
}

0 commit comments

Comments
 (0)