Skip to content

Commit c11b9bb

Browse files
committed
Auto merge of #63825 - nathanwhit:check-run-results, r=Mark-Simulacrum
Allow checking of run-pass execution output in compiletest Closes #63751 Adds a `check-run-results` flag to compiletest headers, which if enabled checks the output of the execution of a run-pass test's binary against expected output.
2 parents b505208 + bf44f12 commit c11b9bb

File tree

5 files changed

+107
-105
lines changed

5 files changed

+107
-105
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// run-pass
2-
// ignore-cloudabi no processes
3-
// ignore-emscripten no processes
4-
// ignore-sgx no processes
2+
// check-run-results
53

64
// Tests ensuring that `dbg!(expr)` has the expected run-time behavior.
75
// as well as some compile time properties we expect.
@@ -18,7 +16,7 @@ struct Point<T> {
1816
#[derive(Debug, PartialEq)]
1917
struct NoCopy(usize);
2018

21-
fn test() {
19+
fn main() {
2220
let a: Unit = dbg!(Unit);
2321
let _: Unit = dbg!(a);
2422
// We can move `a` because it's Copy.
@@ -67,81 +65,3 @@ fn test() {
6765
assert_eq!((1u8, 2u32, "Yeah"), dbg!(1u8, 2u32,
6866
"Yeah",));
6967
}
70-
71-
fn validate_stderr(stderr: Vec<String>) {
72-
assert_eq!(stderr, &[
73-
":22] Unit = Unit",
74-
75-
":23] a = Unit",
76-
77-
":29] Point{x: 42, y: 24,} = Point {",
78-
" x: 42,",
79-
" y: 24,",
80-
"}",
81-
82-
":30] b = Point {",
83-
" x: 42,",
84-
" y: 24,",
85-
"}",
86-
87-
":38]",
88-
89-
":42] &a = NoCopy(",
90-
" 1337,",
91-
")",
92-
93-
":42] dbg!(& a) = NoCopy(",
94-
" 1337,",
95-
")",
96-
":47] f(&42) = 42",
97-
98-
"before",
99-
":52] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
100-
101-
":60] (\"Yeah\",) = (",
102-
" \"Yeah\",",
103-
")",
104-
105-
":63] 1 = 1",
106-
":63] 2 = 2",
107-
108-
":67] 1u8 = 1",
109-
":67] 2u32 = 2",
110-
":67] \"Yeah\" = \"Yeah\"",
111-
]);
112-
}
113-
114-
fn main() {
115-
// The following is a hack to deal with compiletest's inability
116-
// to check the output (to stdout) of run-pass tests.
117-
use std::env;
118-
use std::process::Command;
119-
120-
let mut args = env::args();
121-
let prog = args.next().unwrap();
122-
let child = args.next();
123-
if let Some("child") = child.as_ref().map(|s| &**s) {
124-
// Only run the test if we've been spawned as 'child'
125-
test()
126-
} else {
127-
// This essentially spawns as 'child' to run the tests
128-
// and then it collects output of stderr and checks the output
129-
// against what we expect.
130-
let out = Command::new(&prog).arg("child").output().unwrap();
131-
assert!(out.status.success());
132-
assert!(out.stdout.is_empty());
133-
134-
let stderr = String::from_utf8(out.stderr).unwrap();
135-
let stderr = stderr.lines().map(|mut s| {
136-
if s.starts_with("[") {
137-
// Strip `[` and file path:
138-
s = s.trim_start_matches("[");
139-
assert!(s.starts_with(file!()));
140-
s = s.trim_start_matches(file!());
141-
}
142-
s.to_owned()
143-
}).collect();
144-
145-
validate_stderr(stderr);
146-
}
147-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[$DIR/dbg-macro-expected-behavior.rs:20] Unit = Unit
2+
[$DIR/dbg-macro-expected-behavior.rs:21] a = Unit
3+
[$DIR/dbg-macro-expected-behavior.rs:27] Point{x: 42, y: 24,} = Point {
4+
x: 42,
5+
y: 24,
6+
}
7+
[$DIR/dbg-macro-expected-behavior.rs:28] b = Point {
8+
x: 42,
9+
y: 24,
10+
}
11+
[$DIR/dbg-macro-expected-behavior.rs:36]
12+
[$DIR/dbg-macro-expected-behavior.rs:40] &a = NoCopy(
13+
1337,
14+
)
15+
[$DIR/dbg-macro-expected-behavior.rs:40] dbg!(& a) = NoCopy(
16+
1337,
17+
)
18+
[$DIR/dbg-macro-expected-behavior.rs:45] f(&42) = 42
19+
before
20+
[$DIR/dbg-macro-expected-behavior.rs:50] { foo += 1; eprintln!("before"); 7331 } = 7331
21+
[$DIR/dbg-macro-expected-behavior.rs:58] ("Yeah",) = (
22+
"Yeah",
23+
)
24+
[$DIR/dbg-macro-expected-behavior.rs:61] 1 = 1
25+
[$DIR/dbg-macro-expected-behavior.rs:61] 2 = 2
26+
[$DIR/dbg-macro-expected-behavior.rs:65] 1u8 = 1
27+
[$DIR/dbg-macro-expected-behavior.rs:65] 2u32 = 2
28+
[$DIR/dbg-macro-expected-behavior.rs:65] "Yeah" = "Yeah"

src/tools/compiletest/src/common.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,12 @@ pub fn expected_output_path(
333333
testpaths.file.with_extension(extension)
334334
}
335335

336-
pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED];
336+
pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT];
337337
pub const UI_STDERR: &str = "stderr";
338338
pub const UI_STDOUT: &str = "stdout";
339339
pub const UI_FIXED: &str = "fixed";
340+
pub const UI_RUN_STDERR: &str = "run.stderr";
341+
pub const UI_RUN_STDOUT: &str = "run.stdout";
340342

341343
/// Absolute path to the directory where all output for all tests in the given
342344
/// `relative_dir` group should reside. Example:

src/tools/compiletest/src/header.rs

+16
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ impl EarlyProps {
137137
config.parse_needs_sanitizer_support(ln) {
138138
props.ignore = Ignore::Ignore;
139139
}
140+
141+
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
142+
props.ignore = Ignore::Ignore;
143+
}
144+
140145
}
141146

142147
if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
@@ -326,6 +331,8 @@ pub struct TestProps {
326331
pub force_host: bool,
327332
// Check stdout for error-pattern output as well as stderr
328333
pub check_stdout: bool,
334+
// Check stdout & stderr for output of run-pass test
335+
pub check_run_results: bool,
329336
// For UI tests, allows compiler to generate arbitrary output to stdout
330337
pub dont_check_compiler_stdout: bool,
331338
// For UI tests, allows compiler to generate arbitrary output to stderr
@@ -388,6 +395,7 @@ impl TestProps {
388395
build_aux_docs: false,
389396
force_host: false,
390397
check_stdout: false,
398+
check_run_results: false,
391399
dont_check_compiler_stdout: false,
392400
dont_check_compiler_stderr: false,
393401
no_prefer_dynamic: false,
@@ -468,6 +476,10 @@ impl TestProps {
468476
self.check_stdout = config.parse_check_stdout(ln);
469477
}
470478

479+
if !self.check_run_results {
480+
self.check_run_results = config.parse_check_run_results(ln);
481+
}
482+
471483
if !self.dont_check_compiler_stdout {
472484
self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln);
473485
}
@@ -712,6 +724,10 @@ impl Config {
712724
self.parse_name_directive(line, "check-stdout")
713725
}
714726

727+
fn parse_check_run_results(&self, line: &str) -> bool {
728+
self.parse_name_directive(line, "check-run-results")
729+
}
730+
715731
fn parse_dont_check_compiler_stdout(&self, line: &str) -> bool {
716732
self.parse_name_directive(line, "dont-check-compiler-stdout")
717733
}

src/tools/compiletest/src/runtest.rs

+58-22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use crate::common::{CompareMode, PassMode};
44
use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
5+
use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
56
use crate::common::{output_base_dir, output_base_name, output_testname_unique};
67
use crate::common::{Codegen, CodegenUnits, Rustdoc};
78
use crate::common::{DebugInfoCdb, DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb};
@@ -288,6 +289,11 @@ enum ReadFrom {
288289
Stdin(String),
289290
}
290291

292+
enum TestOutput {
293+
Compile,
294+
Run,
295+
}
296+
291297
impl<'test> TestCx<'test> {
292298
/// Code executed for each revision in turn (or, if there are no
293299
/// revisions, exactly once, with revision == None).
@@ -2930,44 +2936,64 @@ impl<'test> TestCx<'test> {
29302936
}
29312937
}
29322938

2933-
fn run_ui_test(&self) {
2934-
// if the user specified a format in the ui test
2935-
// print the output to the stderr file, otherwise extract
2936-
// the rendered error messages from json and print them
2937-
let explicit = self
2938-
.props
2939-
.compile_flags
2940-
.iter()
2941-
.any(|s| s.contains("--error-format"));
2942-
let proc_res = self.compile_test();
2943-
self.check_if_test_should_compile(&proc_res);
2939+
fn load_compare_outputs(&self, proc_res: &ProcRes,
2940+
output_kind: TestOutput, explicit_format: bool) -> usize {
29442941

2945-
let expected_stderr = self.load_expected_output(UI_STDERR);
2946-
let expected_stdout = self.load_expected_output(UI_STDOUT);
2947-
let expected_fixed = self.load_expected_output(UI_FIXED);
2942+
let (stderr_kind, stdout_kind) = match output_kind {
2943+
TestOutput::Compile => (UI_STDERR, UI_STDOUT),
2944+
TestOutput::Run => (UI_RUN_STDERR, UI_RUN_STDOUT)
2945+
};
2946+
2947+
let expected_stderr = self.load_expected_output(stderr_kind);
2948+
let expected_stdout = self.load_expected_output(stdout_kind);
29482949

29492950
let normalized_stdout =
29502951
self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
29512952

2952-
let stderr = if explicit {
2953+
let stderr = if explicit_format {
29532954
proc_res.stderr.clone()
29542955
} else {
29552956
json::extract_rendered(&proc_res.stderr)
29562957
};
29572958

29582959
let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
2959-
29602960
let mut errors = 0;
2961-
if !self.props.dont_check_compiler_stdout {
2962-
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2963-
}
2964-
if !self.props.dont_check_compiler_stderr {
2965-
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
2961+
match output_kind {
2962+
TestOutput::Compile => {
2963+
if !self.props.dont_check_compiler_stdout {
2964+
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2965+
}
2966+
if !self.props.dont_check_compiler_stderr {
2967+
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
2968+
}
2969+
}
2970+
TestOutput::Run => {
2971+
errors += self.compare_output(stdout_kind, &normalized_stdout, &expected_stdout);
2972+
errors += self.compare_output(stderr_kind, &normalized_stderr, &expected_stderr);
2973+
}
29662974
}
2975+
errors
2976+
}
2977+
2978+
fn run_ui_test(&self) {
2979+
// if the user specified a format in the ui test
2980+
// print the output to the stderr file, otherwise extract
2981+
// the rendered error messages from json and print them
2982+
let explicit = self
2983+
.props
2984+
.compile_flags
2985+
.iter()
2986+
.any(|s| s.contains("--error-format"));
2987+
let proc_res = self.compile_test();
2988+
self.check_if_test_should_compile(&proc_res);
2989+
2990+
let expected_fixed = self.load_expected_output(UI_FIXED);
29672991

29682992
let modes_to_prune = vec![CompareMode::Nll];
29692993
self.prune_duplicate_outputs(&modes_to_prune);
29702994

2995+
let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit);
2996+
29712997
if self.config.compare_mode.is_some() {
29722998
// don't test rustfix with nll right now
29732999
} else if self.config.rustfix_coverage {
@@ -3045,7 +3071,17 @@ impl<'test> TestCx<'test> {
30453071

30463072
if self.should_run_successfully() {
30473073
let proc_res = self.exec_compiled_test();
3048-
3074+
let run_output_errors = if self.props.check_run_results {
3075+
self.load_compare_outputs(&proc_res, TestOutput::Run, explicit)
3076+
} else {
3077+
0
3078+
};
3079+
if run_output_errors > 0 {
3080+
self.fatal_proc_rec(
3081+
&format!("{} errors occured comparing run output.", run_output_errors),
3082+
&proc_res,
3083+
);
3084+
}
30493085
if !proc_res.status.success() {
30503086
self.fatal_proc_rec("test run failed!", &proc_res);
30513087
}

0 commit comments

Comments
 (0)