mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-25 12:05:32 +03:00
Merge pull request #170 from Orange-OpenSource/fix/support-wildcard-in-jsonpath
Support wildcard in jsonpath
This commit is contained in:
commit
a7bf5bb144
File diff suppressed because one or more lines are too long
@ -19,6 +19,7 @@ jsonpath "$.errors[0]" exists
|
||||
jsonpath "$.errors[0]" isCollection
|
||||
jsonpath "$.errors[0].id" equals "error1"
|
||||
jsonpath "$.errors[0]['id']" equals "error1"
|
||||
jsonpath "$.errors[*].id" includes "error1"
|
||||
jsonpath "$.duration" equals 1.5
|
||||
jsonpath "$.duration" lessThanOrEquals 2.0
|
||||
jsonpath "$.duration" lessThan 2
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-json"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"equal","value":5}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"equal","value":5.0}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":1}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":1.0}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"equal","value":false}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"not":true,"type":"equal","value":null}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"isBoolean"}},{"query":{"type":"jsonpath","expr":"$.errors"},"predicate":{"type":"count","value":2}},{"query":{"type":"jsonpath","expr":"$.errors"},"predicate":{"type":"isCollection"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"count","value":0}},{"query":{"type":"jsonpath","expr":"$.toto"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.errors[0]"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.errors[0]"},"predicate":{"type":"isCollection"}},{"query":{"type":"jsonpath","expr":"$.errors[0].id"},"predicate":{"type":"equal","value":"error1"}},{"query":{"type":"jsonpath","expr":"$.errors[0]['id']"},"predicate":{"type":"equal","value":"error1"}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"equal","value":1.5}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"less-or-equal","value":2.0}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"greater","value":2}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"isFloat"}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"not":true,"type":"isInteger"}},{"query":{"type":"jsonpath","expr":"$.nullable"},"predicate":{"type":"equal","value":null}}],"body":{"type":"json","value":{"count":5,"success":false,"errors":[{"id":"error1"},{"id":"error2"}],"warnings":[],"duration":1.5,"tags":["test"],"nullable":null}}}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json/index"},"response":{"version":"HTTP/1.0","status":200,"captures":[{"name":"index","query":{"type":"body"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.errors[{{index}}].id"},"predicate":{"type":"equal","value":"error2"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"type":"include","value":"test"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"not":true,"type":"include","value":"prod"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"not":true,"type":"include","value":null}}]}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json/list"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$"},"predicate":{"type":"count","value":2}},{"query":{"type":"jsonpath","expr":"$.[0].name"},"predicate":{"type":"equal","value":"Bob"}},{"query":{"type":"jsonpath","expr":"$[0].name"},"predicate":{"type":"equal","value":"Bob"}}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-json"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"equal","value":5}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"equal","value":5.0}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":1}},{"query":{"type":"jsonpath","expr":"$.count"},"predicate":{"type":"greater","value":1.0}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"equal","value":false}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"not":true,"type":"equal","value":null}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.success"},"predicate":{"type":"isBoolean"}},{"query":{"type":"jsonpath","expr":"$.errors"},"predicate":{"type":"count","value":2}},{"query":{"type":"jsonpath","expr":"$.errors"},"predicate":{"type":"isCollection"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"count","value":0}},{"query":{"type":"jsonpath","expr":"$.toto"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.warnings"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.errors[0]"},"predicate":{"type":"exist"}},{"query":{"type":"jsonpath","expr":"$.errors[0]"},"predicate":{"type":"isCollection"}},{"query":{"type":"jsonpath","expr":"$.errors[0].id"},"predicate":{"type":"equal","value":"error1"}},{"query":{"type":"jsonpath","expr":"$.errors[0]['id']"},"predicate":{"type":"equal","value":"error1"}},{"query":{"type":"jsonpath","expr":"$.errors[*].id"},"predicate":{"type":"include","value":"error1"}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"equal","value":1.5}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"less-or-equal","value":2.0}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"greater","value":2}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"type":"isFloat"}},{"query":{"type":"jsonpath","expr":"$.duration"},"predicate":{"not":true,"type":"isInteger"}},{"query":{"type":"jsonpath","expr":"$.nullable"},"predicate":{"type":"equal","value":null}}],"body":{"type":"json","value":{"count":5,"success":false,"errors":[{"id":"error1"},{"id":"error2"}],"warnings":[],"duration":1.5,"tags":["test"],"nullable":null}}}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json/index"},"response":{"version":"HTTP/1.0","status":200,"captures":[{"name":"index","query":{"type":"body"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$.errors[{{index}}].id"},"predicate":{"type":"equal","value":"error2"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"type":"include","value":"test"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"not":true,"type":"include","value":"prod"}},{"query":{"type":"jsonpath","expr":"$.tags"},"predicate":{"not":true,"type":"include","value":null}}]}},{"request":{"method":"GET","url":"http://localhost:8000/assert-json/list"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"jsonpath","expr":"$"},"predicate":{"type":"count","value":2}},{"query":{"type":"jsonpath","expr":"$.[0].name"},"predicate":{"type":"equal","value":"Bob"}},{"query":{"type":"jsonpath","expr":"$[0].name"},"predicate":{"type":"equal","value":"Bob"}}]}}]}
|
@ -28,6 +28,7 @@ pub struct Query {
|
||||
pub enum Selector {
|
||||
NameChild(String),
|
||||
ArrayIndex(usize),
|
||||
ArrayWildcard,
|
||||
Filter(Predicate),
|
||||
RecursiveKey(String),
|
||||
}
|
||||
|
@ -45,6 +45,15 @@ impl Selector {
|
||||
None => vec![],
|
||||
Some(value) => vec![value.clone()],
|
||||
},
|
||||
Selector::ArrayWildcard {} => {
|
||||
let mut elements = vec![];
|
||||
if let serde_json::Value::Array(values) = root {
|
||||
for value in values {
|
||||
elements.push(value);
|
||||
}
|
||||
}
|
||||
elements
|
||||
}
|
||||
Selector::Filter(predicate) => match root {
|
||||
serde_json::Value::Array(elements) => elements
|
||||
.iter()
|
||||
@ -238,6 +247,46 @@ mod tests {
|
||||
json!("J. R. R. Tolkien")
|
||||
]
|
||||
);
|
||||
|
||||
// $.store.book[*].author
|
||||
let query = Query {
|
||||
selectors: vec![
|
||||
Selector::NameChild("store".to_string()),
|
||||
Selector::NameChild("book".to_string()),
|
||||
Selector::ArrayWildcard {},
|
||||
Selector::NameChild("author".to_string()),
|
||||
],
|
||||
};
|
||||
assert_eq!(
|
||||
query.eval(json_root()),
|
||||
vec![
|
||||
json!("Nigel Rees"),
|
||||
json!("Evelyn Waugh"),
|
||||
json!("Herman Melville"),
|
||||
json!("J. R. R. Tolkien")
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_selector_array_index() {
|
||||
assert_eq!(
|
||||
Selector::ArrayIndex(0).eval(json_books()),
|
||||
vec![json_first_book()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_selector_array_wildcard() {
|
||||
assert_eq!(
|
||||
Selector::ArrayWildcard {}.eval(json_books()),
|
||||
vec![
|
||||
json_first_book(),
|
||||
json_second_book(),
|
||||
json_third_book(),
|
||||
json_fourth_book()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -342,7 +391,7 @@ mod tests {
|
||||
key: "key".to_string(),
|
||||
func: PredicateFunc::LessThan(Number {
|
||||
int: 10,
|
||||
decimal: 0
|
||||
decimal: 0,
|
||||
}),
|
||||
}
|
||||
.eval(json!({"key": 1})),
|
||||
|
@ -48,6 +48,7 @@ fn selector(reader: &mut Reader) -> ParseResult<Selector> {
|
||||
vec![
|
||||
selector_recursive_key,
|
||||
selector_array_index,
|
||||
selector_array_wildcard,
|
||||
selector_object_key_bracket,
|
||||
selector_object_key,
|
||||
selector_filter,
|
||||
@ -72,6 +73,13 @@ fn selector_array_index(reader: &mut Reader) -> Result<Selector, Error> {
|
||||
Ok(Selector::ArrayIndex(i))
|
||||
}
|
||||
|
||||
fn selector_array_wildcard(reader: &mut Reader) -> Result<Selector, Error> {
|
||||
try_left_bracket(reader)?;
|
||||
try_literal("*", reader)?;
|
||||
literal("]", reader)?;
|
||||
Ok(Selector::ArrayWildcard {})
|
||||
}
|
||||
|
||||
fn selector_filter(reader: &mut Reader) -> Result<Selector, Error> {
|
||||
try_literal("[?(", reader)?;
|
||||
let pred = predicate(reader)?;
|
||||
@ -328,6 +336,19 @@ mod tests {
|
||||
assert_eq!(reader.state.cursor, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_selector_wildcard() {
|
||||
let mut reader = Reader::init("[*]");
|
||||
assert_eq!(selector(&mut reader).unwrap(), Selector::ArrayWildcard {});
|
||||
assert_eq!(reader.state.cursor, 3);
|
||||
|
||||
// you don't need to keep the exact string
|
||||
// this is not part of the AST
|
||||
let mut reader = Reader::init(".[*]");
|
||||
assert_eq!(selector(&mut reader).unwrap(), Selector::ArrayWildcard {});
|
||||
assert_eq!(reader.state.cursor, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_key_bracket_selector() {
|
||||
let mut reader = Reader::init("['key']");
|
||||
|
@ -38,6 +38,17 @@ fn test_bookstore_path() {
|
||||
let value: serde_json::Value =
|
||||
serde_json::from_str(s.as_str()).expect("could not parse json file");
|
||||
|
||||
// $.store.book[*].author
|
||||
assert_eq!(
|
||||
test_ok("$.store.book[*].author", value.clone()),
|
||||
vec![
|
||||
json!("Nigel Rees"),
|
||||
json!("Evelyn Waugh"),
|
||||
json!("Herman Melville"),
|
||||
json!("J. R. R. Tolkien")
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
test_ok("$.store.book[0].title", value.clone()),
|
||||
vec![json!("Sayings of the Century")]
|
||||
|
Loading…
Reference in New Issue
Block a user