jsonpath_rust/parser/
tests.rs

1use crate::parser::model::slice_from;
2use crate::parser::model::Comparison;
3use crate::parser::model::FilterAtom;
4use crate::parser::model::FnArg;
5use crate::parser::model::JpQuery;
6use crate::parser::model::Literal;
7use crate::parser::model::Segment;
8use crate::parser::model::Selector;
9use crate::parser::model::SingularQuery;
10use crate::parser::model::SingularQuerySegment;
11use crate::parser::model::TestFunction;
12use crate::parser::model::{Comparable, Filter};
13use crate::parser::Test;
14use 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};
19use crate::{
20    arg, atom, cmp, comparable, jq, lit, or, q_segment, q_segments, segment, selector,
21    singular_query, slice, test, test_fn,
22};
23use pest::error::Error;
24use pest::iterators::Pair;
25use pest::Parser;
26use std::fmt::Debug;
27use std::{panic, vec};
28
29struct TestPair<T> {
30    rule: Rule,
31    parse_fn: fn(Pair<Rule>) -> Parsed<T>,
32}
33
34impl<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
64fn 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("no pairs found")),
67        Err(e) => Err(e),
68    }
69}
70
71fn assert<T>(result: Parsed<T>, expected: T)
72where
73    T: PartialEq + Debug,
74{
75    match result {
76        Ok(e) => assert_eq!(e, expected),
77        Err(e) => {
78            panic!("parsing error `{}`", e);
79        }
80    }
81}
82
83#[test]
84fn 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]
93fn 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]
103fn 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]
118fn 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]
134fn 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]
151fn 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]
163fn 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]
187fn 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]
210fn 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]
221fn 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]
228fn parse_i64() {
229    TestPair::new(Rule::literal, literal).assert("1e2", lit!(f 100.0));
230}
231#[test]
232fn parse_selector() {
233    TestPair::new(Rule::selector, selector).assert("1:1", Selector::Slice(Some(1), Some(1), None));
234}
235#[test]
236fn 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}