about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNixon Enraght-Moony <nixon.emoony@gmail.com>2022-07-19 16:54:53 +0100
committerNixon Enraght-Moony <nixon.emoony@gmail.com>2022-08-12 18:11:55 +0100
commit64f790f030494f586a0754536dc85a50aedb77f6 (patch)
treea927bdb713916c65c4add37683396d4454bc1080
parentdacffd22a0a6803fb38e2c50cbbd726d52c94ad3 (diff)
downloadrust-64f790f030494f586a0754536dc85a50aedb77f6.tar.gz
rust-64f790f030494f586a0754536dc85a50aedb77f6.zip
Jsondocck: New `@ismany` command
-rw-r--r--src/tools/jsondocck/src/main.rs42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index c4462466646..022f7eb8e02 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -50,6 +50,7 @@ pub enum CommandKind {
     Has,
     Count,
     Is,
+    IsMany,
     Set,
 }
 
@@ -57,6 +58,7 @@ 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::IsMany => args.len() >= 3,
             CommandKind::Count | CommandKind::Is => 3 == args.len(),
             CommandKind::Set => 4 == args.len(),
         };
@@ -89,6 +91,7 @@ impl fmt::Display for CommandKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let text = match self {
             CommandKind::Has => "has",
+            CommandKind::IsMany => "ismany",
             CommandKind::Count => "count",
             CommandKind::Is => "is",
             CommandKind::Set => "set",
@@ -137,6 +140,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
             "has" => CommandKind::Has,
             "count" => CommandKind::Count,
             "is" => CommandKind::Is,
+            "ismany" => CommandKind::IsMany,
             "set" => CommandKind::Set,
             _ => {
                 print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
@@ -227,6 +231,44 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
                 _ => unreachable!(),
             }
         }
+        CommandKind::IsMany => {
+            // @ismany <path> <jsonpath> <value>...
+            let (path, query, values) = if let [path, query, values @ ..] = &command.args[..] {
+                (path, query, values)
+            } else {
+                unreachable!("Checked in CommandKind::validate")
+            };
+            let val = cache.get_value(path)?;
+            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
+            // O(n^2), in practice n will never be large enought to matter.
+            let expected_values =
+                values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
+            if expected_values.len() != got_values.len() {
+                return Err(CkError::FailedCheck(
+                    format!(
+                        "Expected {} values, but `{}` matched to {} values ({:?})",
+                        expected_values.len(),
+                        query,
+                        got_values.len(),
+                        got_values
+                    ),
+                    command,
+                ));
+            };
+            for got_value in got_values {
+                if !expected_values.iter().any(|exp| &**exp == got_value) {
+                    return Err(CkError::FailedCheck(
+                        format!("`{}` has match {:?}, which was not expected", query, got_value),
+                        command,
+                    ));
+                }
+            }
+            true
+        }
         CommandKind::Count => {
             // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
             assert_eq!(command.args.len(), 3);