Add @is command to jsondocck

This commit is contained in:
Nixon Enraght-Moony 2021-02-20 00:43:02 +00:00
parent 9b471a3f5f
commit a00eb7ee1d
2 changed files with 27 additions and 11 deletions

View File

@ -1,24 +1,24 @@
// edition:2018
// @has nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
// @has - "$.index[*][?(@.name=='nested')].inner.is_crate" true
// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1
// @has nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
// @has - "$.index[*][?(@.name=='l1')].inner.is_crate" false
// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false
// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2
pub mod l1 {
// @has nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
// @has - "$.index[*][?(@.name=='l3')].inner.is_crate" false
// @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
// @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false
// @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1
pub mod l3 {
// @has nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
// @has - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
// @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
// @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
pub struct L4;
}
// @has nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
// @has - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
// @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
// @is - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
pub use l3::L4;
}

View File

@ -48,13 +48,14 @@ pub struct Command {
pub enum CommandKind {
Has,
Count,
Is,
}
impl CommandKind {
fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
let count = match self {
CommandKind::Has => (1..=3).contains(&args.len()),
CommandKind::Count => 3 == args.len(),
CommandKind::Count | CommandKind::Is => 3 == args.len(),
};
if !count {
@ -83,6 +84,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
CommandKind::Has => "has",
CommandKind::Count => "count",
CommandKind::Is => "is",
};
write!(f, "{}", text)
}
@ -127,6 +129,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
let cmd = match cmd {
"has" => CommandKind::Has,
"count" => CommandKind::Count,
"is" => CommandKind::Is,
_ => {
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
errors = true;
@ -180,6 +183,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
// FIXME: Be more granular about why, (eg syntax error, count not equal)
let result = match command.kind {
CommandKind::Has => {
match command.args.len() {
@ -220,6 +224,18 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
Err(_) => false,
}
}
CommandKind::Is => {
// @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
assert_eq!(command.args.len(), 3);
let val = cache.get_value(&command.args[0])?;
match select(&val, &command.args[1]) {
Ok(results) => {
let pat: Value = serde_json::from_str(&command.args[2]).unwrap();
results.len() == 1 && *results[0] == pat
}
Err(_) => false,
}
}
};
if result == command.negated {