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 ;
264}