Update jsondocck directives to follow ui_test-style

This commit is contained in:
León Orell Valerian Liehr 2024-07-19 16:46:03 +02:00
parent 11e57241f1
commit 25be41cfb8
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
3 changed files with 52 additions and 47 deletions

View File

@ -266,6 +266,7 @@ def get_known_directive_names():
# To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put
# it into a common file which is included in rust code and parsed here.
# FIXME: This setup is temporary until we figure out how to improve this situation.
# See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
KNOWN_DIRECTIVE_NAMES = get_known_directive_names()
LINE_PATTERN = re.compile(r'''

View File

@ -723,12 +723,13 @@ pub fn line_directive<'line>(
}
}
// To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put
// it into a common file which is included in rust code and parsed here.
// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
// we put it into a common file which is included in rust code and parsed here.
// FIXME: This setup is temporary until we figure out how to improve this situation.
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
include!("command-list.rs");
const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[
const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
"count",
"!count",
"files",
@ -747,6 +748,9 @@ const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[
"!snapshot",
];
const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
&["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
/// The broken-down contents of a line containing a test header directive,
/// which [`iter_header`] passes to its callback function.
///
@ -783,7 +787,7 @@ pub(crate) struct CheckDirectiveResult<'ln> {
pub(crate) fn check_directive<'a>(
directive_ln: &'a str,
is_rustdoc: bool,
mode: Mode,
original_line: &str,
) -> CheckDirectiveResult<'a> {
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
@ -791,9 +795,18 @@ pub(crate) fn check_directive<'a>(
let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
let is_known = |s: &str| {
KNOWN_DIRECTIVE_NAMES.contains(&s)
|| (is_rustdoc
&& original_line.starts_with("//@")
&& KNOWN_RUSTDOC_DIRECTIVE_NAMES.contains(&s))
|| match mode {
Mode::Rustdoc | Mode::RustdocJson => {
original_line.starts_with("//@")
&& match mode {
Mode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES,
Mode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
_ => unreachable!(),
}
.contains(&s)
}
_ => false,
}
};
let trailing_directive = {
// 1. is the directive name followed by a space? (to exclude `:`)
@ -875,7 +888,7 @@ fn iter_header(
let directive_ln = non_revisioned_directive_line.trim();
let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
check_directive(directive_ln, mode == Mode::Rustdoc, ln);
check_directive(directive_ln, mode, ln);
if !is_known_directive {
*poisoned = true;
@ -928,7 +941,7 @@ fn iter_header(
let rest = rest.trim_start();
let CheckDirectiveResult { is_known_directive, directive_name, .. } =
check_directive(rest, mode == Mode::Rustdoc, ln);
check_directive(rest, mode, ln);
if is_known_directive {
*poisoned = true;

View File

@ -66,14 +66,17 @@ impl CommandKind {
};
if !count {
print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
print_err(&format!("Incorrect number of arguments to `{}`", self), lineno);
return false;
}
if let CommandKind::Count = self {
if args[1].parse::<usize>().is_err() {
print_err(
&format!("Second argument to @count must be a valid usize (got `{}`)", args[1]),
&format!(
"Second argument to `count` must be a valid usize (got `{}`)",
args[1]
),
lineno,
);
return false;
@ -101,7 +104,8 @@ static LINE_PATTERN: OnceLock<Regex> = OnceLock::new();
fn line_pattern() -> Regex {
RegexBuilder::new(
r#"
\s(?P<invalid>!?)@(?P<negated>!?)
//@\s+
(?P<negated>!?)
(?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
(?P<args>.*)$
"#,
@ -116,6 +120,10 @@ fn print_err(msg: &str, lineno: usize) {
eprintln!("Invalid command: {} on line {}", msg, lineno)
}
// FIXME: This setup is temporary until we figure out how to improve this situation.
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs"));
/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
@ -132,36 +140,22 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
};
let negated = cap.name("negated").unwrap().as_str() == "!";
let cmd = cap.name("cmd").unwrap().as_str();
let cmd = match cmd {
let cmd = match cap.name("cmd").unwrap().as_str() {
"has" => CommandKind::Has,
"count" => CommandKind::Count,
"is" => CommandKind::Is,
"ismany" => CommandKind::IsMany,
"set" => CommandKind::Set,
_ => {
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
// FIXME: See the comment above the `include!(...)`.
cmd if KNOWN_DIRECTIVE_NAMES.contains(&cmd) => continue,
cmd => {
print_err(&format!("Unrecognized command name `{cmd}`"), lineno);
errors = true;
continue;
}
};
if let Some(m) = cap.name("invalid") {
if m.as_str() == "!" {
print_err(
&format!(
"`!@{0}{1}`, (help: try with `@!{1}`)",
if negated { "!" } else { "" },
cmd,
),
lineno,
);
errors = true;
continue;
}
}
let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));
let args = match args {
@ -197,19 +191,19 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
let result = match command.kind {
CommandKind::Has => {
match command.args.len() {
// @has <jsonpath> = check path exists
// `has <jsonpath>`: Check that `jsonpath` exists.
1 => {
let val = cache.value();
let results = select(val, &command.args[0]).unwrap();
!results.is_empty()
}
// @has <jsonpath> <value> = check *any* item matched by path equals value
// `has <jsonpath> <value>`: Check *any* item matched by `jsonpath` equals `value`.
2 => {
let val = cache.value().clone();
let results = select(&val, &command.args[0]).unwrap();
let pat = string_to_value(&command.args[1], cache);
let has = results.contains(&pat.as_ref());
// Give better error for when @has check fails
// Give better error for when `has` check fails.
if !command.negated && !has {
return Err(CkError::FailedCheck(
format!(
@ -227,8 +221,9 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
_ => unreachable!(),
}
}
// `ismany <path> <jsonpath> <value...>`
CommandKind::IsMany => {
// @ismany <path> <jsonpath> <value>...
assert!(!command.negated, "`ismany` may not be negated");
let (query, values) = if let [query, values @ ..] = &command.args[..] {
(query, values)
} else {
@ -236,7 +231,6 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
};
let val = cache.value();
let got_values = select(val, &query).unwrap();
assert!(!command.negated, "`@!ismany` is not supported");
// Serde json doesn't implement Ord or Hash for Value, so we must
// use a Vec here. While in theory that makes setwize equality
@ -265,8 +259,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
}
true
}
// `count <jsonpath> <count>`: Check that `jsonpath` matches exactly `count` times.
CommandKind::Count => {
// @count <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
assert_eq!(command.args.len(), 2);
let expected: usize = command.args[1].parse().unwrap();
let val = cache.value();
@ -287,8 +281,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
eq
}
}
// `has <jsonpath> <value>`: Check` *exactly one* item matched by `jsonpath`, and it equals `value`.
CommandKind::Is => {
// @has <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
assert_eq!(command.args.len(), 2);
let val = cache.value().clone();
let results = select(&val, &command.args[0]).unwrap();
@ -308,8 +302,9 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
is
}
}
// `set <name> = <jsonpath>`
CommandKind::Set => {
// @set <name> = <jsonpath>
assert!(!command.negated, "`set` may not be negated");
assert_eq!(command.args.len(), 3);
assert_eq!(command.args[1], "=", "Expected an `=`");
let val = cache.value().clone();
@ -317,7 +312,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
assert_eq!(
results.len(),
1,
"Expected 1 match for `{}` (because of @set): matched to {:?}",
"Expected 1 match for `{}` (because of `set`): matched to {:?}",
command.args[2],
results
);
@ -330,7 +325,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
}
_ => {
panic!(
"Got multiple results in `@set` for `{}`: {:?}",
"Got multiple results in `set` for `{}`: {:?}",
&command.args[2], results,
);
}
@ -341,18 +336,14 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
if result == command.negated {
if command.negated {
Err(CkError::FailedCheck(
format!(
"`@!{} {}` matched when it shouldn't",
command.kind,
command.args.join(" ")
),
format!("`!{} {}` matched when it shouldn't", command.kind, command.args.join(" ")),
command,
))
} else {
// FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
Err(CkError::FailedCheck(
format!(
"`@{} {}` didn't match when it should",
"`{} {}` didn't match when it should",
command.kind,
command.args.join(" ")
),