code coverage 90%

This commit is contained in:
freestrings 2019-06-26 15:07:49 +09:00
parent cab5177811
commit 8f01598e05
5 changed files with 248 additions and 42 deletions

View File

@ -412,13 +412,8 @@ pub fn select_as<T: serde::de::DeserializeOwned>(
/// ```
pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
let mut selector = SelectorMut::default();
let ret = selector
.str_path(path)?
.value(value)
.delete()?
.take()
.unwrap_or(Value::Null);
Ok(ret)
let value = selector.str_path(path)?.value(value).delete()?;
Ok(value.take().unwrap_or(Value::Null))
}
/// Select JSON properties using a jsonpath and transform the result and then replace it. via closure that implements `FnMut` you can transform the selected results.
@ -468,11 +463,6 @@ where
F: FnMut(&Value) -> Value,
{
let mut selector = SelectorMut::default();
let ret = selector
.str_path(path)?
.value(value)
.replace_with(fun)?
.take()
.unwrap_or(Value::Null);
Ok(ret)
let value = selector.str_path(path)?.value(value).replace_with(fun)?;
Ok(value.take().unwrap_or(Value::Null))
}

View File

@ -193,13 +193,14 @@ impl Parser {
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#boolean");
fn validation_bool_value(v: &str) -> bool {
let b = v.as_bytes();
!b.is_empty() && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
}
match tokenizer.next_token() {
Ok(Token::Key(_, ref v))
if {
let b = v.as_bytes();
!b.is_empty() && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
} =>
{
Ok(Token::Key(_, ref v)) if validation_bool_value(v) => {
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
}
_ => Err(tokenizer.err_msg()),
@ -229,10 +230,10 @@ impl Parser {
debug!("#array_quote_value");
match tokenizer.next_token() {
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
if !tokenizer.peek_is(COMMA) {
Ok(Self::node(ParseToken::Key(val)))
} else {
if tokenizer.peek_is(COMMA) {
Self::array_keys(tokenizer, val)
} else {
Ok(Self::node(ParseToken::Key(val)))
}
}
_ => Err(tokenizer.err_msg()),

View File

@ -94,6 +94,7 @@ impl Token {
self.to_simple() == str_token
}
#[cfg_attr(tarpaulin, skip)]
fn to_simple(&self) -> &'static str {
match self {
Token::Absolute(_) => ABSOLUTE,

View File

@ -157,8 +157,8 @@ impl Cmp for CmpAnd {
v1 && v2
}
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
v1 > 0_f64 && v2 > 0_f64
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
true
}
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
@ -177,8 +177,8 @@ impl Cmp for CmpOr {
v1 || v2
}
fn cmp_f64(&self, v1: f64, v2: f64) -> bool {
v1 > 0_f64 || v2 > 0_f64
fn cmp_f64(&self, _v1: f64, _v2: f64) -> bool {
true
}
fn cmp_string(&self, v1: &str, v2: &str) -> bool {
@ -190,7 +190,7 @@ impl Cmp for CmpOr {
}
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
enum ExprTerm<'a> {
String(String),
Number(Number),
@ -434,7 +434,7 @@ fn abs_index(n: isize, len: usize) -> usize {
}
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
enum FilterKey {
String(String),
All,
@ -482,28 +482,25 @@ impl<'a, 'b> Selector<'a, 'b> {
pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> {
debug!("path : {}", path);
if self.node_ref.is_some() {
self.node_ref.take();
}
self.node_ref.take();
self.node = Some(Parser::compile(path).map_err(JsonPathError::Path)?);
Ok(self)
}
pub fn node_ref(&self) -> Option<&Node> {
if let Some(node) = &self.node {
Some(node)
} else {
None
return Some(node);
}
if let Some(node) = &self.node_ref {
return Some(*node);
}
None
}
pub fn compiled_path(&mut self, node: &'b Node) -> &mut Self {
if self.node.is_some() {
self.node.take();
}
self.node.take();
self.node_ref = Some(node);
self
}
@ -1195,3 +1192,212 @@ impl SelectorMut {
Ok(self)
}
}
#[cfg(test)]
mod select_inner_tests {
use serde_json::{Number, Value};
use select::{Cmp, CmpAnd, CmpEq, CmpGe, CmpGt, CmpLe, CmpLt, CmpNe, CmpOr, ExprTerm};
#[test]
fn to_f64_i64() {
let number = 0_i64;
let v: Value = serde_json::from_str(&format!("{}", number)).unwrap();
if let Value::Number(n) = v {
assert_eq!((super::to_f64(&n) - number as f64).abs() == 0_f64, true);
} else {
panic!();
}
}
#[test]
fn to_f64_f64() {
let number = 0.1_f64;
let v: Value = serde_json::from_str(&format!("{}", number)).unwrap();
if let Value::Number(n) = v {
assert_eq!((super::to_f64(&n) - number).abs() == 0_f64, true);
} else {
panic!();
}
}
#[test]
fn to_f64_u64() {
let number = u64::max_value();
let v: Value = serde_json::from_str(&format!("{}", number)).unwrap();
if let Value::Number(n) = v {
assert_eq!((super::to_f64(&n) - number as f64).abs() == 0_f64, true);
} else {
panic!();
}
}
#[test]
fn cmp_eq() {
let cmp_fn = CmpEq;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), false);
assert_eq!(cmp_fn.cmp_bool(true, true), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
}
#[test]
fn cmp_ne() {
let cmp_fn = CmpNe;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), true);
assert_eq!(cmp_fn.cmp_bool(true, true), false);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
assert_eq!(cmp_fn.cmp_string("1", "1"), false);
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
}
#[test]
fn cmp_gt() {
let cmp_fn = CmpGt;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), true);
assert_eq!(cmp_fn.cmp_bool(true, true), false);
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
assert_eq!(cmp_fn.cmp_string("b", "a"), true);
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
}
#[test]
fn cmp_ge() {
let cmp_fn = CmpGe;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), true);
assert_eq!(cmp_fn.cmp_bool(true, true), true);
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), false);
assert_eq!(cmp_fn.cmp_string("1", "1"), true);
assert_eq!(cmp_fn.cmp_string("ab", "a"), true);
assert_eq!(cmp_fn.cmp_string("1", "2"), false);
}
#[test]
fn cmp_lt() {
let cmp_fn = CmpLt;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), false);
assert_eq!(cmp_fn.cmp_bool(false, true), true);
assert_eq!(cmp_fn.cmp_bool(true, true), false);
assert_eq!(cmp_fn.cmp_bool(false, false), false);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), false);
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
assert_eq!(cmp_fn.cmp_string("a", "a"), false);
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
}
#[test]
fn cmp_le() {
let cmp_fn = CmpLe;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), false);
assert_eq!(cmp_fn.cmp_bool(false, true), true);
assert_eq!(cmp_fn.cmp_bool(true, true), true);
assert_eq!(cmp_fn.cmp_bool(false, false), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.2), true);
assert_eq!(cmp_fn.cmp_f64(0.1, 0.1), true);
assert_eq!(cmp_fn.cmp_f64(0.2, 0.1), false);
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
assert_eq!(cmp_fn.cmp_string("ab", "b"), true);
assert_eq!(cmp_fn.cmp_string("abd", "abc"), false);
assert_eq!(cmp_fn.cmp_string("1", "2"), true);
}
#[test]
fn cmp_and() {
let cmp_fn = CmpAnd;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), false);
assert_eq!(cmp_fn.cmp_bool(false, true), false);
assert_eq!(cmp_fn.cmp_bool(true, true), true);
assert_eq!(cmp_fn.cmp_bool(false, false), false);
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
}
#[test]
fn cmp_or() {
let cmp_fn = CmpOr;
assert_eq!(cmp_fn.default(), false);
assert_eq!(cmp_fn.cmp_bool(true, false), true);
assert_eq!(cmp_fn.cmp_bool(false, true), true);
assert_eq!(cmp_fn.cmp_bool(true, true), true);
assert_eq!(cmp_fn.cmp_bool(false, false), false);
assert_eq!(cmp_fn.cmp_f64(0.0, 0.0), true);
assert_eq!(cmp_fn.cmp_string("a", "a"), true);
}
#[test]
fn cmp_json() {
let v1 = Value::Bool(true);
let v2 = Value::String("1".to_string());
let left = [&v1, &v2];
let right = [&v1, &v2];
let empty: Vec<&Value> = Vec::new();
assert_eq!(CmpEq.cmp_json(&left, &right), left.to_vec());
assert_eq!(CmpNe.cmp_json(&left, &right), left.to_vec());
assert_eq!(CmpGt.cmp_json(&left, &right), empty);
assert_eq!(CmpGe.cmp_json(&left, &right), empty);
assert_eq!(CmpLt.cmp_json(&left, &right), empty);
assert_eq!(CmpLe.cmp_json(&left, &right), empty);
assert_eq!(CmpAnd.cmp_json(&left, &right), left.to_vec());
assert_eq!(CmpOr.cmp_json(&left, &right), left.to_vec());
assert_eq!(
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
vec![&Value::Bool(true)]
);
assert_eq!(
CmpEq.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
empty
);
assert_eq!(
CmpNe.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
empty
);
assert_eq!(
CmpNe.cmp_json(&[&Value::Bool(false)], &[&Value::Bool(true)]),
vec![&Value::Bool(false)]
);
assert_eq!(
CmpAnd.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(true)]),
vec![&Value::Bool(true)]
);
assert_eq!(
CmpOr.cmp_json(&[&Value::Bool(true)], &[&Value::Bool(false)]),
vec![&Value::Bool(true), &Value::Bool(false)]
);
}
#[test]
fn value_vec_into() {
let v = Value::Bool(true);
let vec = &vec![&v];
let term: ExprTerm = vec.into();
assert_eq!(term, ExprTerm::Bool(true));
let v = Value::String("a".to_string());
let vec = &vec![&v];
let term: ExprTerm = vec.into();
assert_eq!(term, ExprTerm::String("a".to_string()));
let v = serde_json::from_str("1.0").unwrap();
let vec = &vec![&v];
let term: ExprTerm = vec.into();
assert_eq!(term, ExprTerm::Number(Number::from_f64(1.0).unwrap()));
}
}

View File

@ -3,7 +3,7 @@ extern crate jsonpath_lib as jsonpath;
extern crate serde_json;
use common::{read_json, setup};
use jsonpath::{Selector, SelectorMut};
use jsonpath::{Selector, SelectorMut, Parser};
use serde_json::Value;
mod common;
@ -53,3 +53,11 @@ fn selector_mut() {
result
);
}
#[test]
fn selector_node_ref() {
let node = Parser::compile("$.*").unwrap();
let mut selector = Selector::default();
selector.compiled_path(&node);
assert!(std::ptr::eq(selector.node_ref().unwrap(), &node));
}