| 1 | use crate::parser::model::slice_from;
|
| 2 | use crate::parser::model::Comparison;
|
| 3 | use crate::parser::model::FilterAtom;
|
| 4 | use crate::parser::model::FnArg;
|
| 5 | use crate::parser::model::JpQuery;
|
| 6 | use crate::parser::model::Literal;
|
| 7 | use crate::parser::model::Segment;
|
| 8 | use crate::parser::model::Selector;
|
| 9 | use crate::parser::model::SingularQuery;
|
| 10 | use crate::parser::model::SingularQuerySegment;
|
| 11 | use crate::parser::model::TestFunction;
|
| 12 | use crate::parser::model::{Comparable, Filter};
|
| 13 | use crate::parser::Test;
|
| 14 | use crate::parser::{
|
| 15 | comp_expr, comparable, filter_atom, function_expr, jp_query, literal, parse_json_path, segment,
|
| 16 | selector, singular_query, singular_query_segments, slice_selector, test, JSPathParser, Parsed,
|
| 17 | Rule,
|
| 18 | };
|
| 19 | use crate::{
|
| 20 | arg, atom, cmp, comparable, jq, lit, or, q_segment, q_segments, segment, selector,
|
| 21 | singular_query, slice, test, test_fn,
|
| 22 | };
|
| 23 | use pest::error::Error;
|
| 24 | use pest::iterators::Pair;
|
| 25 | use pest::Parser;
|
| 26 | use std::fmt::Debug;
|
| 27 | use std::{panic, vec};
|
| 28 |
|
| 29 | struct TestPair<T> {
|
| 30 | rule: Rule,
|
| 31 | parse_fn: fn(Pair<Rule>) -> Parsed<T>,
|
| 32 | }
|
| 33 |
|
| 34 | impl<T: PartialEq + Debug> TestPair<T> {
|
| 35 | fn new(rule: Rule, parse_fn: fn(Pair<Rule>) -> Parsed<T>) -> Self {
|
| 36 | Self { rule, parse_fn }
|
| 37 | }
|
| 38 | fn assert(self, input: &str, expected: T) -> Self {
|
| 39 | match parse(input, self.rule) {
|
| 40 | Ok(e) => {
|
| 41 | assert((self.parse_fn)(e), expected);
|
| 42 | }
|
| 43 | Err(e) => {
|
| 44 | panic!("parsing error ` {}`" , e);
|
| 45 | }
|
| 46 | }
|
| 47 | self
|
| 48 | }
|
| 49 | fn assert_fail(self, input: &str) -> Self {
|
| 50 | match parse(input, self.rule) {
|
| 51 | Ok(e) => {
|
| 52 | if let Ok(r) = (self.parse_fn)(e) {
|
| 53 | panic!("expected error, got {:?}" , r);
|
| 54 | }
|
| 55 | }
|
| 56 | Err(e) => {
|
| 57 | println!("parsing error ` {}`" , e);
|
| 58 | }
|
| 59 | }
|
| 60 | self
|
| 61 | }
|
| 62 | }
|
| 63 |
|
| 64 | fn parse(input: &str, rule: Rule) -> Result<Pair<Rule>, Error<Rule>> {
|
| 65 | match JSPathParser::parse(rule, input) {
|
| 66 | Ok(e) => Ok(e.into_iter().next().expect(msg:"no pairs found" )),
|
| 67 | Err(e: Error<{unknown}>) => Err(e),
|
| 68 | }
|
| 69 | }
|
| 70 |
|
| 71 | fn assert<T>(result: Parsed<T>, expected: T)
|
| 72 | where
|
| 73 | T: PartialEq + Debug,
|
| 74 | {
|
| 75 | match result {
|
| 76 | Ok(e: T) => assert_eq!(e, expected),
|
| 77 | Err(e: JsonPathError) => {
|
| 78 | panic!("parsing error ` {}`" , e);
|
| 79 | }
|
| 80 | }
|
| 81 | }
|
| 82 |
|
| 83 | #[test ]
|
| 84 | fn singular_query_segment_test() {
|
| 85 | TestPair::new(Rule::singular_query_segments, singular_query_segments)
|
| 86 | .assert("[ \"b \"][ \"b \"]" , q_segments!([b][b]))
|
| 87 | .assert("[2][1]" , q_segments!([2][1]))
|
| 88 | .assert("[2][ \"a \"]" , q_segments!([2][a]))
|
| 89 | .assert(".a.b" , q_segments!(a b))
|
| 90 | .assert(".a.b[ \"c \"][1]" , q_segments!(a b [c][1]));
|
| 91 | }
|
| 92 | #[test ]
|
| 93 | fn singular_query_test() {
|
| 94 | TestPair::new(Rule::singular_query, singular_query)
|
| 95 | .assert("@.a.b" , singular_query!(@ a b))
|
| 96 | .assert("@" , SingularQuery::Current(vec![]))
|
| 97 | .assert("$" , SingularQuery::Root(vec![]))
|
| 98 | .assert("$.a.b.c" , singular_query!(a b c))
|
| 99 | .assert("$[ \"a \"].b[3]" , singular_query!([a] b [3]));
|
| 100 | }
|
| 101 |
|
| 102 | #[test ]
|
| 103 | fn slice_selector_test() {
|
| 104 | TestPair::new(Rule::slice_selector, slice_selector)
|
| 105 | .assert(":" , slice!())
|
| 106 | .assert("::" , slice!())
|
| 107 | .assert("1:" , slice!(1))
|
| 108 | .assert("1:1" , slice!(1, 1))
|
| 109 | .assert("1:1:1" , slice!(1, 1, 1))
|
| 110 | .assert(":1:1" , slice!(,1,1))
|
| 111 | .assert("::1" , slice!(,,1))
|
| 112 | .assert("1::1" , slice!(1,,1))
|
| 113 | .assert_fail("-0:" )
|
| 114 | .assert_fail("9007199254740995" );
|
| 115 | }
|
| 116 |
|
| 117 | #[test ]
|
| 118 | fn function_expr_test() {
|
| 119 | TestPair::new(Rule::function_expr, function_expr)
|
| 120 | .assert("length(1)" , test_fn!(length arg!(lit!(i 1))))
|
| 121 | .assert("length(true)" , test_fn!(length arg!(lit!(b true))))
|
| 122 | .assert(
|
| 123 | "search(@, \"abc \")" ,
|
| 124 | test_fn!(search arg!(t test!(@ ) ), arg!(lit!(s "abc" ))),
|
| 125 | )
|
| 126 | .assert(
|
| 127 | "count(@.a)" ,
|
| 128 | test_fn!(count arg!(t test!(@ segment!(selector!(a))))),
|
| 129 | )
|
| 130 | .assert_fail("count \t(@.*)" );
|
| 131 | }
|
| 132 |
|
| 133 | #[test ]
|
| 134 | fn jq_test() {
|
| 135 | let atom = Filter::Atom(atom!(
|
| 136 | comparable!(> singular_query!(@ a b)),
|
| 137 | ">" ,
|
| 138 | comparable!(lit!(i 1))
|
| 139 | ));
|
| 140 | TestPair::new(Rule::jp_query, jp_query).assert(
|
| 141 | "$.a.b[?@.a.b > 1]" ,
|
| 142 | jq!(
|
| 143 | segment!(selector!(a)),
|
| 144 | segment!(selector!(b)),
|
| 145 | segment!(selector!(?atom))
|
| 146 | ),
|
| 147 | );
|
| 148 | }
|
| 149 |
|
| 150 | #[test ]
|
| 151 | fn comp_expr_test() {
|
| 152 | TestPair::new(Rule::comp_expr, comp_expr).assert(
|
| 153 | "@.a.b.c == 1" ,
|
| 154 | cmp!(
|
| 155 | comparable!(> singular_query!(@ a b c)),
|
| 156 | "==" ,
|
| 157 | comparable!(lit!(i 1))
|
| 158 | ),
|
| 159 | );
|
| 160 | }
|
| 161 |
|
| 162 | #[test ]
|
| 163 | fn literal_test() {
|
| 164 | TestPair::new(Rule::literal, literal)
|
| 165 | .assert("'☺'" , lit!(s "☺" ))
|
| 166 | .assert_fail(" \"\n\"" )
|
| 167 | .assert("' '" , lit!(s " " ))
|
| 168 | .assert("' \"'" , lit!(s " \"" ))
|
| 169 | .assert("null" , lit!())
|
| 170 | .assert("false" , lit!(b false))
|
| 171 | .assert("true" , lit!(b true))
|
| 172 | .assert(" \"hello \"" , lit!(s "hello" ))
|
| 173 | .assert(" \'hello \'" , lit!(s "hello" ))
|
| 174 | .assert(" \'hel \\'lo \'" , lit!(s "hel \\'lo" ))
|
| 175 | .assert(" \'hel \"lo \'" , lit!(s "hel \"lo" ))
|
| 176 | .assert(" \'hel \\nlo \'" , lit!(s "hel \\nlo" ))
|
| 177 | .assert("1" , lit!(i 1))
|
| 178 | .assert("0" , lit!(i 0))
|
| 179 | .assert("-0" , lit!(i 0))
|
| 180 | .assert("1.2" , lit!(f 1.2))
|
| 181 | .assert("9007199254740990" , lit!(i 9007199254740990))
|
| 182 | .assert_fail("hel \\\"lo" )
|
| 183 | .assert_fail("9007199254740995" );
|
| 184 | }
|
| 185 |
|
| 186 | #[test ]
|
| 187 | fn filter_atom_test() {
|
| 188 | TestPair::new(Rule::atom_expr, filter_atom)
|
| 189 | .assert(
|
| 190 | "1 > 2" ,
|
| 191 | atom!(comparable!(lit!(i 1)), ">" , comparable!(lit!(i 2))),
|
| 192 | )
|
| 193 | .assert(
|
| 194 | "!(@.a ==1 || @.b == 2)" ,
|
| 195 | atom!(!or!(
|
| 196 | Filter::Atom(atom!(
|
| 197 | comparable!(> singular_query!(@ a)),
|
| 198 | "==" ,
|
| 199 | comparable!(lit!(i 1))
|
| 200 | )),
|
| 201 | Filter::Atom(atom!(
|
| 202 | comparable!(> singular_query!(@ b)),
|
| 203 | "==" ,
|
| 204 | comparable!(lit!(i 2))
|
| 205 | ))
|
| 206 | )),
|
| 207 | );
|
| 208 | }
|
| 209 | #[test ]
|
| 210 | fn comparable_test() {
|
| 211 | TestPair::new(Rule::comparable, comparable)
|
| 212 | .assert("1" , comparable!(lit!(i 1)))
|
| 213 | .assert(" \"a \"" , comparable!(lit!(s "a" )))
|
| 214 | .assert("@.a.b.c" , comparable!(> singular_query!(@ a b c)))
|
| 215 | .assert("$.a.b.c" , comparable!(> singular_query!(a b c)))
|
| 216 | .assert("$[1]" , comparable!(> singular_query!([1])))
|
| 217 | .assert("length(1)" , comparable!(f test_fn!(length arg!(lit!(i 1)))));
|
| 218 | }
|
| 219 |
|
| 220 | #[test ]
|
| 221 | fn parse_path() {
|
| 222 | let result = parse_json_path("$" );
|
| 223 | assert!(result.is_ok());
|
| 224 | assert_eq!(result.unwrap(), JpQuery::new(vec![]));
|
| 225 | }
|
| 226 |
|
| 227 | #[test ]
|
| 228 | fn parse_i64() {
|
| 229 | TestPair::new(Rule::literal, literal).assert("1e2" , lit!(f 100.0));
|
| 230 | }
|
| 231 | #[test ]
|
| 232 | fn parse_selector() {
|
| 233 | TestPair::new(Rule::selector, selector).assert("1:1" , Selector::Slice(Some(1), Some(1), None));
|
| 234 | }
|
| 235 | #[test ]
|
| 236 | fn parse_global() {
|
| 237 | let sel_a = segment!(selector!(a));
|
| 238 | TestPair::new(Rule::jp_query, jp_query)
|
| 239 | // .assert("$", JpQuery::new(vec![]))
|
| 240 | // .assert("$.a", JpQuery::new(vec![sel_a.clone()]))
|
| 241 | // .assert("$..a", JpQuery::new(vec![segment!(..sel_a)]))
|
| 242 | // .assert(
|
| 243 | // "$..*",
|
| 244 | // JpQuery::new(vec![segment!(..segment!(selector!(*)))]),
|
| 245 | // )
|
| 246 | // .assert(
|
| 247 | // "$[1 :5:2]",
|
| 248 | // JpQuery::new(vec![segment!(selector!(slice slice!(1, 5, 2)))]),
|
| 249 | // )
|
| 250 | // .assert(
|
| 251 | // "$['a']['b']",
|
| 252 | // JpQuery::new(vec![segment!(Selector::Name("'a'".to_string())), segment!(Selector::Name("'b'".to_string()))]),
|
| 253 | // )
|
| 254 | //
|
| 255 | // .assert(
|
| 256 | // "$[1, 1:1]",
|
| 257 | // JpQuery::new(vec![Segment::Selectors(vec![
|
| 258 | // Selector::Index(1),
|
| 259 | // Selector::Slice(Some(1), Some(1), None),
|
| 260 | // ])]),
|
| 261 | // )
|
| 262 | // .assert_fail("$..\ra")
|
| 263 | ;
|
| 264 | }
|
| 265 | |