Allow multiple cfgs per comment in "revisions:" tests
The `//[X]~` syntax filters errors for tests that are run across multiple cfgs with `// revisions:`. This commit extends that syntax to accept `//[X,Y]~`, which will match multiple cfgs to the same error annotation. This is functionally the same as writing two comments, `//[X]~` and `//[Y]~`, but can fit on a single line.
This commit is contained in:
parent
53712f8637
commit
54d51bc483
1 changed files with 47 additions and 42 deletions
|
|
@ -7,7 +7,9 @@ use std::io::BufReader;
|
|||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use log::*;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ErrorKind {
|
||||
|
|
@ -85,20 +87,16 @@ pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec<Error> {
|
|||
// updating it in the map callback below.)
|
||||
let mut last_nonfollow_error = None;
|
||||
|
||||
let tag = match cfg {
|
||||
Some(rev) => format!("//[{}]~", rev),
|
||||
None => "//~".to_string(),
|
||||
};
|
||||
|
||||
rdr.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(line_num, line)| {
|
||||
parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), &tag).map(
|
||||
parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), cfg).map(
|
||||
|(which, error)| {
|
||||
match which {
|
||||
FollowPrevious(_) => {}
|
||||
_ => last_nonfollow_error = Some(error.line_num),
|
||||
}
|
||||
|
||||
error
|
||||
},
|
||||
)
|
||||
|
|
@ -110,46 +108,53 @@ fn parse_expected(
|
|||
last_nonfollow_error: Option<usize>,
|
||||
line_num: usize,
|
||||
line: &str,
|
||||
tag: &str,
|
||||
cfg: Option<&str>,
|
||||
) -> Option<(WhichLine, Error)> {
|
||||
let start = line.find(tag)?;
|
||||
let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' {
|
||||
(true, 0)
|
||||
} else {
|
||||
(
|
||||
false,
|
||||
line[start + tag.len()..]
|
||||
.chars()
|
||||
.take_while(|c| *c == '^')
|
||||
.count(),
|
||||
)
|
||||
// Matches comments like:
|
||||
// //~
|
||||
// //~|
|
||||
// //~^
|
||||
// //~^^^^^
|
||||
// //[cfg1]~
|
||||
// //[cfg1,cfg2]~^^
|
||||
lazy_static! {
|
||||
static ref RE: Regex =
|
||||
Regex::new(r"//(?:\[(?P<cfgs>[\w,]+)])?~(?P<adjust>\||\^*)").unwrap();
|
||||
}
|
||||
|
||||
let captures = RE.captures(line)?;
|
||||
|
||||
match (cfg, captures.name("cfgs")) {
|
||||
// Only error messages that contain our `cfg` betweeen the square brackets apply to us.
|
||||
(Some(cfg), Some(filter)) if !filter.as_str().split(',').any(|s| s == cfg)
|
||||
=> return None,
|
||||
(Some(_), Some(_)) => {}
|
||||
|
||||
(None, Some(_)) => panic!("Only tests with revisions should use `//[X]~`"),
|
||||
|
||||
// If an error has no list of revisions, it applies to all revisions.
|
||||
(Some(_), None) | (None, None) => {}
|
||||
}
|
||||
|
||||
let (follow, adjusts) = match &captures["adjust"] {
|
||||
"|" => (true, 0),
|
||||
circumflexes => (false, circumflexes.len()),
|
||||
};
|
||||
let kind_start = start + tag.len() + adjusts + (follow as usize);
|
||||
let (kind, msg);
|
||||
match line[kind_start..]
|
||||
|
||||
// Get the part of the comment after the sigil (e.g. `~^^` or ~|).
|
||||
let (_, mut msg) = line.split_at(captures.get(0).unwrap().end());
|
||||
|
||||
let first_word = msg
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.expect("Encountered unexpected empty comment")
|
||||
.parse::<ErrorKind>()
|
||||
{
|
||||
Ok(k) => {
|
||||
// If we find `//~ ERROR foo` or something like that:
|
||||
kind = Some(k);
|
||||
let letters = line[kind_start..].chars();
|
||||
msg = letters
|
||||
.skip_while(|c| c.is_whitespace())
|
||||
.skip_while(|c| !c.is_whitespace())
|
||||
.collect::<String>();
|
||||
}
|
||||
Err(_) => {
|
||||
// Otherwise we found `//~ foo`:
|
||||
kind = None;
|
||||
let letters = line[kind_start..].chars();
|
||||
msg = letters
|
||||
.skip_while(|c| c.is_whitespace())
|
||||
.collect::<String>();
|
||||
}
|
||||
.expect("Encountered unexpected empty comment");
|
||||
|
||||
// If we find `//~ ERROR foo` or something like that, skip the first word.
|
||||
let kind = first_word.parse::<ErrorKind>().ok();
|
||||
if let Some(_) = kind {
|
||||
msg = &msg.trim_start().split_at(first_word.len()).1;
|
||||
}
|
||||
|
||||
let msg = msg.trim().to_owned();
|
||||
|
||||
let (which, line_num) = if follow {
|
||||
|
|
@ -171,7 +176,7 @@ fn parse_expected(
|
|||
|
||||
debug!(
|
||||
"line={} tag={:?} which={:?} kind={:?} msg={:?}",
|
||||
line_num, tag, which, kind, msg
|
||||
line_num, &captures[0], which, kind, msg
|
||||
);
|
||||
Some((
|
||||
which,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue