Skip to content

Commit 7e6cf90

Browse files
authored
Rollup merge of rust-lang#63825 - nathanwhit:check-run-results, r=Mark-Simulacrum
Allow checking of run-pass execution output in compiletest Closes rust-lang#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 85ed538 + 12e0420 commit 7e6cf90

File tree

5 files changed

+102
-105
lines changed

5 files changed

+102
-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"

Diff for: 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:

Diff for: src/tools/compiletest/src/header.rs

+11
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ pub struct TestProps {
326326
pub force_host: bool,
327327
// Check stdout for error-pattern output as well as stderr
328328
pub check_stdout: bool,
329+
// Check stdout & stderr for output of run-pass test
330+
pub check_run_results: bool,
329331
// For UI tests, allows compiler to generate arbitrary output to stdout
330332
pub dont_check_compiler_stdout: bool,
331333
// For UI tests, allows compiler to generate arbitrary output to stderr
@@ -388,6 +390,7 @@ impl TestProps {
388390
build_aux_docs: false,
389391
force_host: false,
390392
check_stdout: false,
393+
check_run_results: false,
391394
dont_check_compiler_stdout: false,
392395
dont_check_compiler_stderr: false,
393396
no_prefer_dynamic: false,
@@ -468,6 +471,10 @@ impl TestProps {
468471
self.check_stdout = config.parse_check_stdout(ln);
469472
}
470473

474+
if !self.check_run_results {
475+
self.check_run_results = config.parse_check_run_results(ln);
476+
}
477+
471478
if !self.dont_check_compiler_stdout {
472479
self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln);
473480
}
@@ -712,6 +719,10 @@ impl Config {
712719
self.parse_name_directive(line, "check-stdout")
713720
}
714721

722+
fn parse_check_run_results(&self, line: &str) -> bool {
723+
self.parse_name_directive(line, "check-run-results")
724+
}
725+
715726
fn parse_dont_check_compiler_stdout(&self, line: &str) -> bool {
716727
self.parse_name_directive(line, "dont-check-compiler-stdout")
717728
}

Diff for: 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).
@@ -2934,44 +2940,64 @@ impl<'test> TestCx<'test> {
29342940
}
29352941
}
29362942

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

2949-
let expected_stderr = self.load_expected_output(UI_STDERR);
2950-
let expected_stdout = self.load_expected_output(UI_STDOUT);
2951-
let expected_fixed = self.load_expected_output(UI_FIXED);
2946+
let (stderr_kind, stdout_kind) = match output_kind {
2947+
TestOutput::Compile => (UI_STDERR, UI_STDOUT),
2948+
TestOutput::Run => (UI_RUN_STDERR, UI_RUN_STDOUT)
2949+
};
2950+
2951+
let expected_stderr = self.load_expected_output(stderr_kind);
2952+
let expected_stdout = self.load_expected_output(stdout_kind);
29522953

29532954
let normalized_stdout =
29542955
self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout);
29552956

2956-
let stderr = if explicit {
2957+
let stderr = if explicit_format {
29572958
proc_res.stderr.clone()
29582959
} else {
29592960
json::extract_rendered(&proc_res.stderr)
29602961
};
29612962

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

29722996
let modes_to_prune = vec![CompareMode::Nll];
29732997
self.prune_duplicate_outputs(&modes_to_prune);
29742998

2999+
let mut errors = self.load_compare_outputs(&proc_res, TestOutput::Compile, explicit);
3000+
29753001
if self.config.compare_mode.is_some() {
29763002
// don't test rustfix with nll right now
29773003
} else if self.config.rustfix_coverage {
@@ -3049,7 +3075,17 @@ impl<'test> TestCx<'test> {
30493075

30503076
if self.should_run_successfully() {
30513077
let proc_res = self.exec_compiled_test();
3052-
3078+
let run_output_errors = if self.props.check_run_results {
3079+
self.load_compare_outputs(&proc_res, TestOutput::Run, explicit)
3080+
} else {
3081+
0
3082+
};
3083+
if run_output_errors > 0 {
3084+
self.fatal_proc_rec(
3085+
&format!("{} errors occured comparing run output.", run_output_errors),
3086+
&proc_res,
3087+
);
3088+
}
30533089
if !proc_res.status.success() {
30543090
self.fatal_proc_rec("test run failed!", &proc_res);
30553091
}

0 commit comments

Comments
 (0)