Skip to content

Commit cb4fc52

Browse files
authored
Merge pull request #163 from oli-obk/stdin
Add convenient way to test stdin
2 parents 6b17c94 + ad972c3 commit cb4fc52

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1120
-48
lines changed

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@
44
"./tests/integrations/basic-bin/Cargo.toml",
55
"./tests/integrations/basic-fail/Cargo.toml",
66
"./tests/integrations/basic-fail-mode/Cargo.toml",
7-
]
7+
"./tests/integrations/cargo-run/Cargo.toml"
8+
],
9+
"nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix"
810
}

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

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ A smaller version of compiletest-rs
66
So if you have any slow tests, prepend them with a small integral number to make them get run first, taking advantage of parallelism as much as possible (instead of waiting for the slow tests at the end).
77
* `cargo test --test your_test_name -- --help` lists the commands you can specify for filtering, blessing and making your tests less verbose.
88
* Since `cargo test` on its own runs all tests, using `cargo test -- --check` will not work on its own, but `cargo test -- --quiet` and `cargo test -- some_test_name` will work just fine, as the CLI matches.
9+
* if there is a `.stdin` file with the same filename as your test, it will be piped as standard input to your program.
910

1011
## Supported magic comment annotations
1112

@@ -53,6 +54,8 @@ their command specifies, or the test will fail without even being run.
5354
* `//@aux-build: filename` looks for a file in the `auxiliary` directory (within the directory of the test), compiles it as a library and links the current crate against it. This allows you import the crate with `extern crate` or just via `use` statements. This will automatically detect aux files that are proc macros and build them as proc macros.
5455
* `//@run` compiles the test and runs the resulting binary. The resulting binary must exit successfully. Stdout and stderr are taken from the resulting binary. Any warnings during compilation are ignored.
5556
* You can also specify a different exit code/status that is expected via e.g. `//@run: 1` or `//@run: 101` (the latter is the standard Rust exit code for panics).
57+
* run tests collect the run output into `.run.stderr` and `.run.stdout` respectively.
58+
* if a `.run.stdin` file exists, it will be piped as standard input to your test's execution.
5659

5760
[rustfix]: https://github.com/rust-lang/rustfix
5861

shell.nix

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
let
2+
pkgs = import <nixpkgs> {};
3+
in
4+
pkgs.mkShell rec {
5+
name = "rustc";
6+
buildInputs = with pkgs; [
7+
rustup
8+
pkg-config
9+
alsaLib
10+
libGL
11+
xorg.libX11
12+
xorg.libXi
13+
python39
14+
];
15+
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
16+
LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath buildInputs}";
17+
}
18+

src/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,14 @@ impl Config {
166166
}
167167

168168
/// Replace all occurrences of a path in stderr/stdout with a byte string.
169+
#[track_caller]
169170
pub fn path_filter(&mut self, path: &Path, replacement: &'static (impl AsRef<[u8]> + ?Sized)) {
170171
self.path_stderr_filter(path, replacement);
171172
self.path_stdout_filter(path, replacement);
172173
}
173174

174175
/// Replace all occurrences of a path in stderr with a byte string.
176+
#[track_caller]
175177
pub fn path_stderr_filter(
176178
&mut self,
177179
path: &Path,
@@ -183,6 +185,7 @@ impl Config {
183185
}
184186

185187
/// Replace all occurrences of a path in stdout with a byte string.
188+
#[track_caller]
186189
pub fn path_stdout_filter(
187190
&mut self,
188191
path: &Path,
@@ -194,12 +197,14 @@ impl Config {
194197
}
195198

196199
/// Replace all occurrences of a regex pattern in stderr/stdout with a byte string.
200+
#[track_caller]
197201
pub fn filter(&mut self, pattern: &str, replacement: &'static (impl AsRef<[u8]> + ?Sized)) {
198202
self.stderr_filter(pattern, replacement);
199203
self.stdout_filter(pattern, replacement);
200204
}
201205

202206
/// Replace all occurrences of a regex pattern in stderr with a byte string.
207+
#[track_caller]
203208
pub fn stderr_filter(
204209
&mut self,
205210
pattern: &str,
@@ -210,6 +215,7 @@ impl Config {
210215
}
211216

212217
/// Replace all occurrences of a regex pattern in stdout with a byte string.
218+
#[track_caller]
213219
pub fn stdout_filter(
214220
&mut self,
215221
pattern: &str,

src/lib.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -627,23 +627,45 @@ impl dyn TestStatus {
627627
build_manager,
628628
)?;
629629

630-
let mut cmd = build_command(path, config, revision, comments)?;
630+
let mut config = config.clone();
631+
632+
// Put aux builds into a separate directory per path so that multiple aux files
633+
// from different directories (but with the same file name) don't collide.
634+
let relative = strip_path_prefix(path.parent().unwrap(), &config.out_dir);
635+
636+
config.out_dir.extend(relative);
637+
638+
let mut cmd = build_command(path, &config, revision, comments)?;
631639
cmd.args(&extra_args);
640+
let stdin = path.with_extension("stdin");
641+
if stdin.exists() {
642+
cmd.stdin(std::fs::File::open(stdin).unwrap());
643+
}
632644

633645
let (cmd, status, stderr, stdout) = self.run_command(cmd)?;
634646

635647
let mode = config.mode.maybe_override(comments, revision)?;
648+
let cmd = check_test_result(
649+
cmd,
650+
match *mode {
651+
Mode::Run { .. } => Mode::Pass,
652+
_ => *mode,
653+
},
654+
path,
655+
&config,
656+
revision,
657+
comments,
658+
status,
659+
&stdout,
660+
&stderr,
661+
)?;
636662

637663
if let Mode::Run { .. } = *mode {
638-
if Mode::Pass.ok(status).is_ok() {
639-
return run_test_binary(mode, path, revision, comments, cmd, config);
640-
}
664+
return run_test_binary(mode, path, revision, comments, cmd, &config);
641665
}
642-
check_test_result(
643-
cmd, *mode, path, config, revision, comments, status, &stdout, &stderr,
644-
)?;
666+
645667
run_rustfix(
646-
&stderr, &stdout, path, comments, revision, config, *mode, extra_args,
668+
&stderr, &stdout, path, comments, revision, &config, *mode, extra_args,
647669
)?;
648670
Ok(TestOk::Ok)
649671
}
@@ -739,6 +761,11 @@ fn run_test_binary(
739761
mut cmd: Command,
740762
config: &Config,
741763
) -> TestResult {
764+
let revision = if revision.is_empty() {
765+
"run".to_string()
766+
} else {
767+
format!("run.{revision}")
768+
};
742769
cmd.arg("--print").arg("file-names");
743770
let output = cmd.output().unwrap();
744771
assert!(output.status.success());
@@ -747,16 +774,22 @@ fn run_test_binary(
747774
let file = files.next().unwrap();
748775
assert_eq!(files.next(), None);
749776
let file = std::str::from_utf8(file).unwrap();
750-
let exe = config.out_dir.join(file);
751-
let mut exe = Command::new(exe);
752-
let output = exe.output().unwrap();
777+
let exe_file = config.out_dir.join(file);
778+
let mut exe = Command::new(&exe_file);
779+
let stdin = path.with_extension(format!("{revision}.stdin"));
780+
if stdin.exists() {
781+
exe.stdin(std::fs::File::open(stdin).unwrap());
782+
}
783+
let output = exe
784+
.output()
785+
.unwrap_or_else(|err| panic!("exe file: {}: {err}", exe_file.display()));
753786

754787
let mut errors = vec![];
755788

756789
check_test_output(
757790
path,
758791
&mut errors,
759-
revision,
792+
&revision,
760793
config,
761794
comments,
762795
&output.stdout,
@@ -948,7 +981,7 @@ fn check_test_result(
948981
status: ExitStatus,
949982
stdout: &[u8],
950983
stderr: &[u8],
951-
) -> Result<(), Errored> {
984+
) -> Result<Command, Errored> {
952985
let mut errors = vec![];
953986
errors.extend(mode.ok(status).err());
954987
// Always remove annotation comments from stderr.
@@ -973,7 +1006,7 @@ fn check_test_result(
9731006
comments,
9741007
)?;
9751008
if errors.is_empty() {
976-
Ok(())
1009+
Ok(command)
9771010
} else {
9781011
Err(Errored {
9791012
command,

tests/integration.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ fn main() -> Result<()> {
3333

3434
config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", "");
3535
config.stdout_filter(r#""--out-dir"(,)? "[^"]+""#, r#""--out-dir"$1 "$$TMP"#);
36+
config.filter("\\.exe", b"");
3637
config.filter(
37-
"( *process didn't exit successfully: `[^-]+)-[0-9a-f]+",
38-
"$1-HASH",
38+
"( *process didn't exit successfully: `.*)-[0-9a-f]+`",
39+
"$1-HASH`",
3940
);
4041
// Windows io::Error uses "exit code".
4142
config.filter("exit code", "exit status");
@@ -54,7 +55,6 @@ fn main() -> Result<()> {
5455
config
5556
.stdout_filters
5657
.insert(0, (Match::Exact(b"\\\\".to_vec()), b"\\"));
57-
config.filter("\\.exe", b"");
5858
config.stdout_filter(r#"(panic.*)\.rs:[0-9]+:[0-9]+"#, "$1.rs");
5959
config.filter("(\\+)? +[0-9]+: .*\n", "");
6060
config.filter("(\\+)? +at /.*\n", "");
@@ -69,6 +69,7 @@ fn main() -> Result<()> {
6969
config.filter("(src/.*?\\.rs):[0-9]+:[0-9]+", "$1:LL:CC");
7070
config.filter("program not found", "No such file or directory");
7171
config.filter(" \\(os error [0-9]+\\)", "");
72+
config.filter("note: rustc 1\\..*", "");
7273

7374
let text = ui_test::status_emitter::Text::from(args.format);
7475

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-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.

0 commit comments

Comments
 (0)