mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-29 11:22:13 +00:00
code coverage 적용
This commit is contained in:
commit
5f832e8fe7
29
.travis.yml
29
.travis.yml
@ -1,5 +1,9 @@
|
|||||||
language: rust
|
language: rust
|
||||||
sudo: false
|
sudo: required
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libssl-dev
|
||||||
|
|
||||||
cache: cargo
|
cache: cargo
|
||||||
|
|
||||||
@ -13,27 +17,22 @@ matrix:
|
|||||||
- rust: stable
|
- rust: stable
|
||||||
os: linux
|
os: linux
|
||||||
env: RUST_BACKTRACE=1
|
env: RUST_BACKTRACE=1
|
||||||
addons:
|
before_cache: |
|
||||||
chrome: stable
|
if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
|
||||||
before_script:
|
cargo install cargo-tarpaulin -f
|
||||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
fi
|
||||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
|
||||||
- cargo install-update -a
|
|
||||||
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
|
|
||||||
script:
|
script:
|
||||||
|
- cargo clean
|
||||||
- cargo build --verbose --all
|
- cargo build --verbose --all
|
||||||
- cargo test --verbose --all
|
- cargo test --verbose --all
|
||||||
|
after_success: |
|
||||||
|
cargo tarpaulin --exclude-files nodejs wasm parser/mod.rs --out Xml
|
||||||
|
bash <(curl -s https://codecov.io/bash)
|
||||||
- rust: stable
|
- rust: stable
|
||||||
os: osx
|
os: osx
|
||||||
env: RUST_BACKTRACE=1
|
env: RUST_BACKTRACE=1
|
||||||
addons:
|
|
||||||
chrome: stable
|
|
||||||
before_script:
|
|
||||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
|
||||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
|
||||||
- cargo install-update -a
|
|
||||||
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
|
|
||||||
script:
|
script:
|
||||||
|
- cargo clean
|
||||||
- cargo build --verbose --all
|
- cargo build --verbose --all
|
||||||
- cargo test --verbose --all
|
- cargo test --verbose --all
|
||||||
- language: node_js
|
- language: node_js
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly`와 `Javascript`에서도 유사한 API 인터페이스를 제공 한다.
|
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly`와 `Javascript`에서도 유사한 API 인터페이스를 제공 한다.
|
||||||
|
|
||||||
|
9
coverage.sh
Executable file
9
coverage.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# cargo install cargo-tarpaulin
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cargo tarpaulin --exclude-files nodejs wasm parser/mod.rs -v --all
|
@ -41,6 +41,38 @@ mod parser_tests {
|
|||||||
interpreter.start()
|
interpreter.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_error() {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
fn invalid(path: &str) {
|
||||||
|
if let Err(_) = run(path) {
|
||||||
|
assert!(true);
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalid("$[]");
|
||||||
|
invalid("$[a]");
|
||||||
|
invalid("$[?($.a)]");
|
||||||
|
invalid("$[?(@.a > @.b]");
|
||||||
|
invalid("$[?(@.a < @.b&&(@.c < @.d)]");
|
||||||
|
invalid("@.");
|
||||||
|
invalid("$..[?(a <= @.a)]"); // invalid term value
|
||||||
|
invalid("$['a', b]");
|
||||||
|
invalid("$[0, >=]");
|
||||||
|
invalid("$[a:]");
|
||||||
|
invalid("$[:a]");
|
||||||
|
invalid("$[::a]");
|
||||||
|
invalid("$[:>]");
|
||||||
|
invalid("$[1:>]");
|
||||||
|
invalid("$[1,,]");
|
||||||
|
invalid("$[?]");
|
||||||
|
invalid("$[?(1 = 1)]");
|
||||||
|
invalid("$[?(1 = >)]");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_path() {
|
fn parse_path() {
|
||||||
setup();
|
setup();
|
||||||
@ -434,6 +466,18 @@ mod parser_tests {
|
|||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
run(r#"$[?(@ > 1)]"#),
|
||||||
|
Ok(vec![
|
||||||
|
ParseToken::Absolute,
|
||||||
|
ParseToken::Array,
|
||||||
|
ParseToken::Relative,
|
||||||
|
ParseToken::Number(1_f64),
|
||||||
|
ParseToken::Filter(FilterToken::Greater),
|
||||||
|
ParseToken::ArrayEof
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run("$[:]"),
|
run("$[:]"),
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
@ -463,36 +507,6 @@ mod parser_tests {
|
|||||||
ParseToken::ArrayEof
|
ParseToken::ArrayEof
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
match run("$[") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match run("$[]") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match run("$[a]") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match run("$[?($.a)]") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match run("$[?(@.a > @.b]") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match run("$[?(@.a < @.b&&(@.c < @.d)]") {
|
|
||||||
Ok(_) => panic!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -776,6 +790,21 @@ mod tokenizer_tests {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
run(
|
||||||
|
r#"$['single\'1','single\'2']"#,
|
||||||
|
(
|
||||||
|
vec![
|
||||||
|
Token::Absolute(0),
|
||||||
|
Token::OpenArray(1),
|
||||||
|
Token::SingleQuoted(2, "single\'1".to_string()),
|
||||||
|
Token::Comma(13),
|
||||||
|
Token::SingleQuoted(14, "single\'2".to_string()),
|
||||||
|
Token::CloseArray(25),
|
||||||
|
],
|
||||||
|
Some(TokenError::Eof),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
run(
|
run(
|
||||||
r#"$["double\"quote"]"#,
|
r#"$["double\"quote"]"#,
|
||||||
(
|
(
|
||||||
|
@ -111,17 +111,7 @@ impl Parser {
|
|||||||
fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
debug!("#paths_dot");
|
debug!("#paths_dot");
|
||||||
let node = Self::path(prev, tokenizer)?;
|
let node = Self::path(prev, tokenizer)?;
|
||||||
match tokenizer.peek_token() {
|
Self::paths(node, tokenizer)
|
||||||
Ok(Token::Equal(_))
|
|
||||||
| Ok(Token::NotEqual(_))
|
|
||||||
| Ok(Token::Little(_))
|
|
||||||
| Ok(Token::LittleOrEqual(_))
|
|
||||||
| Ok(Token::Greater(_))
|
|
||||||
| Ok(Token::GreaterOrEqual(_))
|
|
||||||
| Ok(Token::And(_))
|
|
||||||
| Ok(Token::Or(_)) => Ok(node),
|
|
||||||
_ => Self::paths(node, tokenizer),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
@ -201,7 +191,12 @@ impl Parser {
|
|||||||
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
debug!("#boolean");
|
debug!("#boolean");
|
||||||
match tokenizer.next_token() {
|
match tokenizer.next_token() {
|
||||||
Ok(Token::Key(_, v)) => {
|
Ok(Token::Key(_, ref v))
|
||||||
|
if {
|
||||||
|
let b = v.as_bytes();
|
||||||
|
b.len() > 0 && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
|
||||||
|
} =>
|
||||||
|
{
|
||||||
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
||||||
}
|
}
|
||||||
_ => Err(tokenizer.err_msg()),
|
_ => Err(tokenizer.err_msg()),
|
||||||
@ -214,15 +209,11 @@ impl Parser {
|
|||||||
Self::eat_token(tokenizer);
|
Self::eat_token(tokenizer);
|
||||||
Self::eat_whitespace(tokenizer);
|
Self::eat_whitespace(tokenizer);
|
||||||
|
|
||||||
if !(tokenizer.peek_is(SINGLE_QUOTE) || tokenizer.peek_is(DOUBLE_QUOTE)) {
|
|
||||||
return Err(tokenizer.err_msg());
|
|
||||||
}
|
|
||||||
|
|
||||||
match tokenizer.next_token() {
|
match tokenizer.next_token() {
|
||||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||||
keys.push(val);
|
keys.push(val);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => return Err(tokenizer.err_msg()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::eat_whitespace(tokenizer);
|
Self::eat_whitespace(tokenizer);
|
||||||
@ -241,7 +232,6 @@ impl Parser {
|
|||||||
Self::array_keys(tokenizer, val)
|
Self::array_keys(tokenizer, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(TokenError::Eof) => Ok(Self::node(ParseToken::Eof)),
|
|
||||||
_ => Err(tokenizer.err_msg()),
|
_ => Err(tokenizer.err_msg()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,11 +331,23 @@ impl Parser {
|
|||||||
fn range_value<S: FromStr>(tokenizer: &mut TokenReader) -> Result<Option<S>, String> {
|
fn range_value<S: FromStr>(tokenizer: &mut TokenReader) -> Result<Option<S>, String> {
|
||||||
Self::eat_whitespace(tokenizer);
|
Self::eat_whitespace(tokenizer);
|
||||||
|
|
||||||
if tokenizer.peek_is(SPLIT) {
|
match tokenizer.peek_token() {
|
||||||
|
Ok(Token::Split(_)) => {
|
||||||
Self::eat_token(tokenizer);
|
Self::eat_token(tokenizer);
|
||||||
Self::eat_whitespace(tokenizer);
|
Self::eat_whitespace(tokenizer);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match tokenizer.peek_token() {
|
||||||
|
Ok(Token::Key(_, _)) => {}
|
||||||
|
_ => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tokenizer.peek_is(KEY) {
|
|
||||||
match tokenizer.next_token() {
|
match tokenizer.next_token() {
|
||||||
Ok(Token::Key(pos, str_step)) => {
|
Ok(Token::Key(pos, str_step)) => {
|
||||||
match utils::string_to_num(&str_step, || tokenizer.err_msg_with_pos(pos)) {
|
match utils::string_to_num(&str_step, || tokenizer.err_msg_with_pos(pos)) {
|
||||||
@ -353,13 +355,9 @@ impl Parser {
|
|||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
_ => {
|
||||||
|
unreachable!();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +421,6 @@ impl Parser {
|
|||||||
Self::eat_whitespace(tokenizer);
|
Self::eat_whitespace(tokenizer);
|
||||||
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)
|
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)
|
||||||
}
|
}
|
||||||
Err(TokenError::Eof) => Ok(Self::node(ParseToken::Eof)),
|
|
||||||
_ => Err(tokenizer.err_msg()),
|
_ => Err(tokenizer.err_msg()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,7 +506,6 @@ impl Parser {
|
|||||||
Ok(Self::node(ParseToken::Number(number)))
|
Ok(Self::node(ParseToken::Number(number)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(TokenError::Eof) => Ok(Self::node(ParseToken::Eof)),
|
|
||||||
_ => Err(tokenizer.err_msg()),
|
_ => Err(tokenizer.err_msg()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,14 +526,6 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_key(tokenizer: &mut TokenReader) -> Option<String> {
|
|
||||||
if let Ok(Token::Key(_, k)) = tokenizer.peek_token() {
|
|
||||||
Some(k.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn term(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
fn term(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||||
debug!("#term");
|
debug!("#term");
|
||||||
|
|
||||||
@ -563,15 +551,15 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tokenizer.peek_is(KEY) {
|
if tokenizer.peek_is(KEY) {
|
||||||
return match Self::peek_key(tokenizer) {
|
let key = if let Ok(Token::Key(_, k)) = tokenizer.peek_token() {
|
||||||
Some(key) => match key.chars().next() {
|
k.clone()
|
||||||
Some(ch) => match ch {
|
} else {
|
||||||
'-' | '0'...'9' => Self::term_num(tokenizer),
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
return match key.as_bytes()[0] {
|
||||||
|
b'-' | b'0'...b'9' => Self::term_num(tokenizer),
|
||||||
_ => Self::boolean(tokenizer),
|
_ => Self::boolean(tokenizer),
|
||||||
},
|
|
||||||
_ => Err(tokenizer.err_msg()),
|
|
||||||
},
|
|
||||||
_ => Err(tokenizer.err_msg()),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +575,6 @@ impl Parser {
|
|||||||
Ok(Token::LittleOrEqual(_)) => ParseToken::Filter(FilterToken::LittleOrEqual),
|
Ok(Token::LittleOrEqual(_)) => ParseToken::Filter(FilterToken::LittleOrEqual),
|
||||||
Ok(Token::Greater(_)) => ParseToken::Filter(FilterToken::Greater),
|
Ok(Token::Greater(_)) => ParseToken::Filter(FilterToken::Greater),
|
||||||
Ok(Token::GreaterOrEqual(_)) => ParseToken::Filter(FilterToken::GreaterOrEqual),
|
Ok(Token::GreaterOrEqual(_)) => ParseToken::Filter(FilterToken::GreaterOrEqual),
|
||||||
Err(TokenError::Eof) => ParseToken::Eof,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(tokenizer.err_msg());
|
return Err(tokenizer.err_msg());
|
||||||
}
|
}
|
||||||
|
@ -995,8 +995,30 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|||||||
.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
.push(Some(ExprTerm::Number(Number::from_f64(*v).unwrap())));
|
||||||
}
|
}
|
||||||
ParseToken::Filter(ref ft) => {
|
ParseToken::Filter(ref ft) => {
|
||||||
if let Some(Some(ref right)) = self.terms.pop() {
|
let ref right = match self.terms.pop() {
|
||||||
if let Some(Some(left)) = self.terms.pop() {
|
Some(Some(right)) => right,
|
||||||
|
Some(None) => ExprTerm::Json(
|
||||||
|
None,
|
||||||
|
match &self.current {
|
||||||
|
Some(current) => current.to_vec(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => panic!("empty term right"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let left = match self.terms.pop() {
|
||||||
|
Some(Some(left)) => left,
|
||||||
|
Some(None) => ExprTerm::Json(
|
||||||
|
None,
|
||||||
|
match &self.current {
|
||||||
|
Some(current) => current.to_vec(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => panic!("empty term left"),
|
||||||
|
};
|
||||||
|
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
match ft {
|
match ft {
|
||||||
FilterToken::Equal => left.eq(right, &mut ret),
|
FilterToken::Equal => left.eq(right, &mut ret),
|
||||||
@ -1012,12 +1034,6 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> {
|
|||||||
if let Some(e) = ret {
|
if let Some(e) = ret {
|
||||||
self.terms.push(Some(e));
|
self.terms.push(Some(e));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ParseToken::Range(from, to, step) => {
|
ParseToken::Range(from, to, step) => {
|
||||||
if !self.terms.is_empty() {
|
if !self.terms.is_empty() {
|
||||||
|
@ -343,6 +343,22 @@ fn op_complex() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn op_compare() {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
for path in [
|
||||||
|
r#"$[?("1" == 1)]"#,
|
||||||
|
r#"$[?(1 == "1")]"#,
|
||||||
|
r#"$[?(true == 1)]"#,
|
||||||
|
r#"$[?(@ == 1)]"#,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
{
|
||||||
|
select_and_then_compare(path, json!({}), json!([Value::Null]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example() {
|
fn example() {
|
||||||
setup();
|
setup();
|
||||||
|
85
tests/lib.rs
85
tests/lib.rs
@ -7,14 +7,14 @@ use serde::Deserialize;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use common::{compare_result, read_contents, read_json, setup};
|
use common::{compare_result, read_contents, read_json, setup};
|
||||||
|
use jsonpath::JsonPathError;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compile() {
|
fn compile() {
|
||||||
setup();
|
let compile_object = |path| {
|
||||||
|
let mut template = jsonpath::compile(path);
|
||||||
let mut template = jsonpath::compile("$..friends[2]");
|
|
||||||
let json_obj = read_json("./benches/data_obj.json");
|
let json_obj = read_json("./benches/data_obj.json");
|
||||||
let json = template(&json_obj).unwrap();
|
let json = template(&json_obj).unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -22,7 +22,10 @@ fn compile() {
|
|||||||
{"id": 2,"name": "Gray Berry"}
|
{"id": 2,"name": "Gray Berry"}
|
||||||
]);
|
]);
|
||||||
compare_result(json, ret);
|
compare_result(json, ret);
|
||||||
|
};
|
||||||
|
|
||||||
|
let compile_array = |path| {
|
||||||
|
let mut template = jsonpath::compile(path);
|
||||||
let json_obj = read_json("./benches/data_array.json");
|
let json_obj = read_json("./benches/data_array.json");
|
||||||
let json = template(&json_obj).unwrap();
|
let json = template(&json_obj).unwrap();
|
||||||
let ret = json!([
|
let ret = json!([
|
||||||
@ -30,27 +33,55 @@ fn compile() {
|
|||||||
{"id": 2,"name": "Rosetta Erickson"}
|
{"id": 2,"name": "Rosetta Erickson"}
|
||||||
]);
|
]);
|
||||||
compare_result(json, ret);
|
compare_result(json, ret);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn compile_error() {
|
||||||
|
let mut template = jsonpath::compile("$[");
|
||||||
|
if let Err(JsonPathError::Path(_)) = template(&Value::Null) {
|
||||||
|
assert!(true);
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setup();
|
||||||
|
|
||||||
|
compile_object("$..friends[2]");
|
||||||
|
compile_array("$..friends[2]");
|
||||||
|
compile_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn selector() {
|
fn selector() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
|
fn select<'a, F>(selector: &mut F, path: &'a str, target: Value)
|
||||||
|
where
|
||||||
|
F: FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError>,
|
||||||
|
{
|
||||||
|
let json = selector(path).unwrap();
|
||||||
|
compare_result(json, target);
|
||||||
|
};
|
||||||
|
|
||||||
let json_obj = read_json("./benches/data_obj.json");
|
let json_obj = read_json("./benches/data_obj.json");
|
||||||
let mut reader = jsonpath::selector(&json_obj);
|
let mut selector = jsonpath::selector(&json_obj);
|
||||||
let json = reader("$..friends[2]").unwrap();
|
|
||||||
let ret = json!([
|
select(
|
||||||
|
&mut selector,
|
||||||
|
"$..friends[2]",
|
||||||
|
json!([
|
||||||
{"id": 2,"name": "Gray Berry"},
|
{"id": 2,"name": "Gray Berry"},
|
||||||
{"id": 2,"name": "Gray Berry"}
|
{"id": 2,"name": "Gray Berry"}
|
||||||
]);
|
]),
|
||||||
compare_result(json, ret);
|
);
|
||||||
|
select(
|
||||||
let json = reader("$..friends[0]").unwrap();
|
&mut selector,
|
||||||
let ret = json!([
|
"$..friends[0]",
|
||||||
|
json!([
|
||||||
{"id": 0},
|
{"id": 0},
|
||||||
{"id": 0,"name": "Millicent Norman"}
|
{"id": 0,"name": "Millicent Norman"}
|
||||||
]);
|
]),
|
||||||
compare_result(json, ret);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -61,11 +92,21 @@ fn selector_as() {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn select<'a, F>(selector: &mut F, path: &'a str, target: Vec<Friend>)
|
||||||
|
where
|
||||||
|
F: FnMut(&'a str) -> Result<Vec<Friend>, JsonPathError>,
|
||||||
|
{
|
||||||
|
let json = selector(path).unwrap();
|
||||||
|
assert_eq!(json, target);
|
||||||
|
};
|
||||||
|
|
||||||
let json_obj = read_json("./benches/data_obj.json");
|
let json_obj = read_json("./benches/data_obj.json");
|
||||||
let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
|
let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
|
||||||
let json = selector("$..friends[2]").unwrap();
|
|
||||||
|
|
||||||
let ret = vec![
|
select(
|
||||||
|
&mut selector,
|
||||||
|
"$..friends[2]",
|
||||||
|
vec![
|
||||||
Friend {
|
Friend {
|
||||||
id: 2,
|
id: 2,
|
||||||
name: Some("Gray Berry".to_string()),
|
name: Some("Gray Berry".to_string()),
|
||||||
@ -74,18 +115,20 @@ fn selector_as() {
|
|||||||
id: 2,
|
id: 2,
|
||||||
name: Some("Gray Berry".to_string()),
|
name: Some("Gray Berry".to_string()),
|
||||||
},
|
},
|
||||||
];
|
],
|
||||||
assert_eq!(json, ret);
|
);
|
||||||
|
|
||||||
let json = selector("$..friends[0]").unwrap();
|
select(
|
||||||
let ret = vec![
|
&mut selector,
|
||||||
|
"$..friends[0]",
|
||||||
|
vec![
|
||||||
Friend { id: 0, name: None },
|
Friend { id: 0, name: None },
|
||||||
Friend {
|
Friend {
|
||||||
id: 0,
|
id: 0,
|
||||||
name: Some("Millicent Norman".to_string()),
|
name: Some("Millicent Norman".to_string()),
|
||||||
},
|
},
|
||||||
];
|
],
|
||||||
assert_eq!(json, ret);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -486,8 +486,6 @@ fn readme_delete2() {
|
|||||||
|
|
||||||
let ret = jsonpath::delete(json_obj, "$.store.book").unwrap();
|
let ret = jsonpath::delete(json_obj, "$.store.book").unwrap();
|
||||||
|
|
||||||
println!("{:?}", ret);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ret,
|
ret,
|
||||||
json!({
|
json!({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user