about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-02-23 17:24:33 +0000
committerbors <bors@rust-lang.org>2021-02-23 17:24:33 +0000
commitfe1bf8e05c39bdcc73fc09e246b7209444e389bc (patch)
tree9265dd81347434a5b0b6785222fa0b5901e43a1e /src/tools
parent019610754363d1d92a8d0f364d2c0909d6f53dfd (diff)
parent51511c75b558beddab7fb4b6d8277a872714b87a (diff)
downloadrust-fe1bf8e05c39bdcc73fc09e246b7209444e389bc.tar.gz
rust-fe1bf8e05c39bdcc73fc09e246b7209444e389bc.zip
Auto merge of #82443 - Dylan-DPC:rollup-yni7uio, r=Dylan-DPC
Rollup of 10 pull requests

Successful merges:

 - #81629 (Point out implicit deref coercions in borrow)
 - #82113 (Improve non_fmt_panic lint.)
 - #82258 (Implement -Z hir-stats for nested foreign items)
 - #82296 (Support `pub` on `macro_rules`)
 - #82297 (Consider auto derefs before warning about write only fields)
 - #82305 (Remove many RefCells from DocContext)
 - #82308 (Lower condition of `if` expression before it's "then" block)
 - #82311 (Jsondocck improvements)
 - #82362 (Fix mir-cfg dumps)
 - #82391 (disable atomic_max/min tests in Miri)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/jsondocck/src/cache.rs2
-rw-r--r--src/tools/jsondocck/src/main.rs71
2 files changed, 56 insertions, 17 deletions
diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs
index b742f0eb3ee..8a6a911321c 100644
--- a/src/tools/jsondocck/src/cache.rs
+++ b/src/tools/jsondocck/src/cache.rs
@@ -9,6 +9,7 @@ pub struct Cache {
     root: PathBuf,
     files: HashMap<PathBuf, String>,
     values: HashMap<PathBuf, Value>,
+    pub variables: HashMap<String, Value>,
     last_path: Option<PathBuf>,
 }
 
@@ -19,6 +20,7 @@ impl Cache {
             root: Path::new(doc_dir).to_owned(),
             files: HashMap::new(),
             values: HashMap::new(),
+            variables: HashMap::new(),
             last_path: None,
         }
     }
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 6ec292aba64..5020a4917a0 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -2,6 +2,7 @@ use jsonpath_lib::select;
 use lazy_static::lazy_static;
 use regex::{Regex, RegexBuilder};
 use serde_json::Value;
+use std::borrow::Cow;
 use std::{env, fmt, fs};
 
 mod cache;
@@ -48,13 +49,16 @@ pub struct Command {
 pub enum CommandKind {
     Has,
     Count,
+    Is,
+    Set,
 }
 
 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(),
+            CommandKind::Set => 4 == args.len(),
         };
 
         if !count {
@@ -83,6 +87,8 @@ impl fmt::Display for CommandKind {
         let text = match self {
             CommandKind::Has => "has",
             CommandKind::Count => "count",
+            CommandKind::Is => "is",
+            CommandKind::Set => "set",
         };
         write!(f, "{}", text)
     }
@@ -127,6 +133,8 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
         let cmd = match cmd {
             "has" => CommandKind::Has,
             "count" => CommandKind::Count,
+            "is" => CommandKind::Is,
+            "set" => CommandKind::Set,
             _ => {
                 print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                 errors = true;
@@ -180,6 +188,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, (e.g. syntax error, count not equal)
     let result = match command.kind {
         CommandKind::Has => {
             match command.args.len() {
@@ -188,23 +197,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
                 // @has <path> <jsonpath> = check path exists
                 2 => {
                     let val = cache.get_value(&command.args[0])?;
-
-                    match select(&val, &command.args[1]) {
-                        Ok(results) => !results.is_empty(),
-                        Err(_) => false,
-                    }
+                    let results = select(&val, &command.args[1]).unwrap();
+                    !results.is_empty()
                 }
                 // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                 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.is_empty() && results.into_iter().any(|val| *val == pat)
-                        }
-                        Err(_) => false,
-                    }
+                    let results = select(&val, &command.args[1]).unwrap();
+                    let pat = string_to_value(&command.args[2], cache);
+                    results.contains(&pat.as_ref())
                 }
                 _ => unreachable!(),
             }
@@ -215,9 +216,37 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
             let expected: usize = command.args[2].parse().unwrap();
 
             let val = cache.get_value(&command.args[0])?;
-            match select(&val, &command.args[1]) {
-                Ok(results) => results.len() == expected,
-                Err(_) => false,
+            let results = select(&val, &command.args[1]).unwrap();
+            results.len() == expected
+        }
+        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])?;
+            let results = select(&val, &command.args[1]).unwrap();
+            let pat = string_to_value(&command.args[2], cache);
+            results.len() == 1 && results[0] == pat.as_ref()
+        }
+        CommandKind::Set => {
+            // @set <name> = <path> <jsonpath>
+            assert_eq!(command.args.len(), 4);
+            assert_eq!(command.args[1], "=", "Expected an `=`");
+            let val = cache.get_value(&command.args[2])?;
+            let results = select(&val, &command.args[3]).unwrap();
+            assert_eq!(results.len(), 1);
+            match results.len() {
+                0 => false,
+                1 => {
+                    let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
+                    assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
+                    true
+                }
+                _ => {
+                    panic!(
+                        "Got multiple results in `@set` for `{}`: {:?}",
+                        &command.args[3], results
+                    );
+                }
             }
         }
     };
@@ -247,3 +276,11 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
         Ok(())
     }
 }
+
+fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
+    if s.starts_with("$") {
+        Cow::Borrowed(&cache.variables[&s[1..]])
+    } else {
+        Cow::Owned(serde_json::from_str(s).unwrap())
+    }
+}