| 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 |  | 
|---|