Skip to content

Commit

Permalink
Add regex-error-pattern flag in compiletest
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Jul 12, 2022
1 parent b3f4c31 commit f515af7
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 19 deletions.
10 changes: 10 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ impl EarlyProps {
pub struct TestProps {
// Lines that should be expected, in order, on standard out
pub error_patterns: Vec<String>,
// Regexes that should be expected, in order, on standard out
pub regex_error_patterns: Vec<String>,
// Extra flags to pass to the compiler
pub compile_flags: Vec<String>,
// Extra flags to pass when the compiled code is run (such as --bench)
Expand Down Expand Up @@ -163,6 +165,7 @@ pub struct TestProps {

mod directives {
pub const ERROR_PATTERN: &'static str = "error-pattern";
pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern";
pub const COMPILE_FLAGS: &'static str = "compile-flags";
pub const RUN_FLAGS: &'static str = "run-flags";
pub const SHOULD_ICE: &'static str = "should-ice";
Expand Down Expand Up @@ -200,6 +203,7 @@ impl TestProps {
pub fn new() -> Self {
TestProps {
error_patterns: vec![],
regex_error_patterns: vec![],
compile_flags: vec![],
run_flags: None,
pp_exact: None,
Expand Down Expand Up @@ -285,6 +289,12 @@ impl TestProps {
&mut self.error_patterns,
|r| r,
);
config.push_name_value_directive(
ln,
REGEX_ERROR_PATTERN,
&mut self.regex_error_patterns,
|r| r,
);

if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
Expand Down
75 changes: 56 additions & 19 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,13 @@ impl<'test> TestCx<'test> {
let output_to_check = self.get_output(&proc_res);
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
if !expected_errors.is_empty() {
if !self.props.error_patterns.is_empty() {
if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
{
self.fatal("both error pattern and expected errors specified");
}
self.check_expected_errors(expected_errors, &proc_res);
} else {
self.check_error_patterns(&output_to_check, &proc_res, pm);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}
if self.props.should_ice {
match proc_res.status.code() {
Expand Down Expand Up @@ -363,7 +364,7 @@ impl<'test> TestCx<'test> {

let output_to_check = self.get_output(&proc_res);
self.check_correct_failure_status(&proc_res);
self.check_error_patterns(&output_to_check, &proc_res, pm);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}

fn get_output(&self, proc_res: &ProcRes) -> String {
Expand Down Expand Up @@ -1222,14 +1223,13 @@ impl<'test> TestCx<'test> {
}
}

fn check_error_patterns(
fn check_all_error_patterns(
&self,
output_to_check: &str,
proc_res: &ProcRes,
pm: Option<PassMode>,
) {
debug!("check_error_patterns");
if self.props.error_patterns.is_empty() {
if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() {
if pm.is_some() {
// FIXME(#65865)
return;
Expand All @@ -1243,13 +1243,8 @@ impl<'test> TestCx<'test> {

let mut missing_patterns: Vec<String> = Vec::new();

for pattern in &self.props.error_patterns {
if output_to_check.contains(pattern.trim()) {
debug!("found error pattern {}", pattern);
} else {
missing_patterns.push(pattern.to_string());
}
}
self.check_error_patterns(output_to_check, &mut missing_patterns);
self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns);

if missing_patterns.is_empty() {
return;
Expand All @@ -1268,6 +1263,44 @@ impl<'test> TestCx<'test> {
}
}

fn check_error_patterns(&self, output_to_check: &str, missing_patterns: &mut Vec<String>) {
debug!("check_error_patterns");
for pattern in &self.props.error_patterns {
if output_to_check.contains(pattern.trim()) {
debug!("found error pattern {}", pattern);
} else {
missing_patterns.push(pattern.to_string());
}
}
}

fn check_regex_error_patterns(
&self,
output_to_check: &str,
proc_res: &ProcRes,
missing_patterns: &mut Vec<String>,
) {
debug!("check_regex_error_patterns");

for pattern in &self.props.regex_error_patterns {
let pattern = pattern.trim();
let re = match Regex::new(pattern) {
Ok(re) => re,
Err(err) => {
self.fatal_proc_rec(
&format!("invalid regex error pattern '{}': {:?}", pattern, err),
proc_res,
);
}
};
if re.is_match(output_to_check) {
debug!("found regex error pattern {}", pattern);
} else {
missing_patterns.push(pattern.to_string());
}
}
}

fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) {
match proc_res.status.code() {
Some(101) if !should_ice => {
Expand Down Expand Up @@ -1892,7 +1925,9 @@ impl<'test> TestCx<'test> {
// If we are extracting and matching errors in the new
// fashion, then you want JSON mode. Old-skool error
// patterns still match the raw compiler output.
if self.props.error_patterns.is_empty() {
if self.props.error_patterns.is_empty()
&& self.props.regex_error_patterns.is_empty()
{
rustc.args(&["--error-format", "json"]);
rustc.args(&["--json", "future-incompat"]);
}
Expand Down Expand Up @@ -3268,10 +3303,11 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("test run succeeded!", &proc_res);
}

if !self.props.error_patterns.is_empty() {
if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
{
// "// error-pattern" comments
let output_to_check = self.get_output(&proc_res);
self.check_error_patterns(&output_to_check, &proc_res, pm);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}
}

Expand All @@ -3285,15 +3321,16 @@ impl<'test> TestCx<'test> {
self.props.error_patterns
);
if !explicit && self.config.compare_mode.is_none() {
let check_patterns =
should_run == WillExecute::No && !self.props.error_patterns.is_empty();
let check_patterns = should_run == WillExecute::No
&& (!self.props.error_patterns.is_empty()
|| !self.props.regex_error_patterns.is_empty());

let check_annotations = !check_patterns || !expected_errors.is_empty();

if check_patterns {
// "// error-pattern" comments
let output_to_check = self.get_output(&proc_res);
self.check_error_patterns(&output_to_check, &proc_res, pm);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}

if check_annotations {
Expand Down

0 comments on commit f515af7

Please sign in to comment.