Skip to content

Commit 64f790f

Browse files
committed
Jsondocck: New @ismany command
1 parent dacffd2 commit 64f790f

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

src/tools/jsondocck/src/main.rs

+42
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,15 @@ pub enum CommandKind {
5050
Has,
5151
Count,
5252
Is,
53+
IsMany,
5354
Set,
5455
}
5556

5657
impl CommandKind {
5758
fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
5859
let count = match self {
5960
CommandKind::Has => (1..=3).contains(&args.len()),
61+
CommandKind::IsMany => args.len() >= 3,
6062
CommandKind::Count | CommandKind::Is => 3 == args.len(),
6163
CommandKind::Set => 4 == args.len(),
6264
};
@@ -89,6 +91,7 @@ impl fmt::Display for CommandKind {
8991
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9092
let text = match self {
9193
CommandKind::Has => "has",
94+
CommandKind::IsMany => "ismany",
9295
CommandKind::Count => "count",
9396
CommandKind::Is => "is",
9497
CommandKind::Set => "set",
@@ -137,6 +140,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
137140
"has" => CommandKind::Has,
138141
"count" => CommandKind::Count,
139142
"is" => CommandKind::Is,
143+
"ismany" => CommandKind::IsMany,
140144
"set" => CommandKind::Set,
141145
_ => {
142146
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
@@ -227,6 +231,44 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
227231
_ => unreachable!(),
228232
}
229233
}
234+
CommandKind::IsMany => {
235+
// @ismany <path> <jsonpath> <value>...
236+
let (path, query, values) = if let [path, query, values @ ..] = &command.args[..] {
237+
(path, query, values)
238+
} else {
239+
unreachable!("Checked in CommandKind::validate")
240+
};
241+
let val = cache.get_value(path)?;
242+
let got_values = select(&val, &query).unwrap();
243+
assert!(!command.negated, "`@!ismany` is not supported");
244+
245+
// Serde json doesn't implement Ord or Hash for Value, so we must
246+
// use a Vec here. While in theory that makes setwize equality
247+
// O(n^2), in practice n will never be large enought to matter.
248+
let expected_values =
249+
values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
250+
if expected_values.len() != got_values.len() {
251+
return Err(CkError::FailedCheck(
252+
format!(
253+
"Expected {} values, but `{}` matched to {} values ({:?})",
254+
expected_values.len(),
255+
query,
256+
got_values.len(),
257+
got_values
258+
),
259+
command,
260+
));
261+
};
262+
for got_value in got_values {
263+
if !expected_values.iter().any(|exp| &**exp == got_value) {
264+
return Err(CkError::FailedCheck(
265+
format!("`{}` has match {:?}, which was not expected", query, got_value),
266+
command,
267+
));
268+
}
269+
}
270+
true
271+
}
230272
CommandKind::Count => {
231273
// @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
232274
assert_eq!(command.args.len(), 3);

0 commit comments

Comments
 (0)