mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-26 12:32:06 +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]" isCollection
|
||||||
jsonpath "$.errors[0].id" equals "error1"
|
jsonpath "$.errors[0].id" equals "error1"
|
||||||
jsonpath "$.errors[0]['id']" equals "error1"
|
jsonpath "$.errors[0]['id']" equals "error1"
|
||||||
|
jsonpath "$.errors[*].id" includes "error1"
|
||||||
jsonpath "$.duration" equals 1.5
|
jsonpath "$.duration" equals 1.5
|
||||||
jsonpath "$.duration" lessThanOrEquals 2.0
|
jsonpath "$.duration" lessThanOrEquals 2.0
|
||||||
jsonpath "$.duration" lessThan 2
|
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 {
|
pub enum Selector {
|
||||||
NameChild(String),
|
NameChild(String),
|
||||||
ArrayIndex(usize),
|
ArrayIndex(usize),
|
||||||
|
ArrayWildcard,
|
||||||
Filter(Predicate),
|
Filter(Predicate),
|
||||||
RecursiveKey(String),
|
RecursiveKey(String),
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,15 @@ impl Selector {
|
|||||||
None => vec![],
|
None => vec![],
|
||||||
Some(value) => vec![value.clone()],
|
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 {
|
Selector::Filter(predicate) => match root {
|
||||||
serde_json::Value::Array(elements) => elements
|
serde_json::Value::Array(elements) => elements
|
||||||
.iter()
|
.iter()
|
||||||
@ -238,6 +247,46 @@ mod tests {
|
|||||||
json!("J. R. R. Tolkien")
|
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]
|
#[test]
|
||||||
@ -342,7 +391,7 @@ mod tests {
|
|||||||
key: "key".to_string(),
|
key: "key".to_string(),
|
||||||
func: PredicateFunc::LessThan(Number {
|
func: PredicateFunc::LessThan(Number {
|
||||||
int: 10,
|
int: 10,
|
||||||
decimal: 0
|
decimal: 0,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
.eval(json!({"key": 1})),
|
.eval(json!({"key": 1})),
|
||||||
|
@ -48,6 +48,7 @@ fn selector(reader: &mut Reader) -> ParseResult<Selector> {
|
|||||||
vec![
|
vec![
|
||||||
selector_recursive_key,
|
selector_recursive_key,
|
||||||
selector_array_index,
|
selector_array_index,
|
||||||
|
selector_array_wildcard,
|
||||||
selector_object_key_bracket,
|
selector_object_key_bracket,
|
||||||
selector_object_key,
|
selector_object_key,
|
||||||
selector_filter,
|
selector_filter,
|
||||||
@ -72,6 +73,13 @@ fn selector_array_index(reader: &mut Reader) -> Result<Selector, Error> {
|
|||||||
Ok(Selector::ArrayIndex(i))
|
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> {
|
fn selector_filter(reader: &mut Reader) -> Result<Selector, Error> {
|
||||||
try_literal("[?(", reader)?;
|
try_literal("[?(", reader)?;
|
||||||
let pred = predicate(reader)?;
|
let pred = predicate(reader)?;
|
||||||
@ -328,6 +336,19 @@ mod tests {
|
|||||||
assert_eq!(reader.state.cursor, 4);
|
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]
|
#[test]
|
||||||
pub fn test_key_bracket_selector() {
|
pub fn test_key_bracket_selector() {
|
||||||
let mut reader = Reader::init("['key']");
|
let mut reader = Reader::init("['key']");
|
||||||
|
@ -38,6 +38,17 @@ fn test_bookstore_path() {
|
|||||||
let value: serde_json::Value =
|
let value: serde_json::Value =
|
||||||
serde_json::from_str(s.as_str()).expect("could not parse json file");
|
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!(
|
assert_eq!(
|
||||||
test_ok("$.store.book[0].title", value.clone()),
|
test_ok("$.store.book[0].title", value.clone()),
|
||||||
vec![json!("Sayings of the Century")]
|
vec![json!("Sayings of the Century")]
|
||||||
|
Loading…
Reference in New Issue
Block a user