|
1 | | -from __future__ import unicode_literals, print_function, absolute_import, division, generators, nested_scopes |
2 | | -import unittest |
| 1 | +from __future__ import ( |
| 2 | + absolute_import, |
| 3 | + division, |
| 4 | + generators, |
| 5 | + nested_scopes, |
| 6 | + print_function, |
| 7 | + unicode_literals, |
| 8 | +) |
3 | 9 |
|
| 10 | +import pytest |
| 11 | + |
| 12 | +from jsonpath_ng.jsonpath import * |
4 | 13 | from jsonpath_ng.lexer import JsonPathLexer |
5 | 14 | from jsonpath_ng.parser import JsonPathParser |
6 | | -from jsonpath_ng.jsonpath import * |
7 | 15 |
|
8 | | -class TestParser(unittest.TestCase): |
9 | | - # TODO: This will be much more effective with a few regression tests and `arbitrary` parse . pretty testing |
10 | | - |
11 | | - @classmethod |
12 | | - def setup_class(cls): |
13 | | - logging.basicConfig() |
14 | | - |
15 | | - def check_parse_cases(self, test_cases): |
16 | | - parser = JsonPathParser(debug=True, lexer_class=lambda:JsonPathLexer(debug=False)) # Note that just manually passing token streams avoids this dep, but that sucks |
17 | | - |
18 | | - for string, parsed in test_cases: |
19 | | - print(string, '=?=', parsed) # pytest captures this and we see it only on a failure, for debugging |
20 | | - assert parser.parse(string) == parsed |
21 | | - |
22 | | - def test_atomic(self): |
23 | | - self.check_parse_cases([('foo', Fields('foo')), |
24 | | - ('*', Fields('*')), |
25 | | - ('baz,bizzle', Fields('baz','bizzle')), |
26 | | - ('[1]', Index(1)), |
27 | | - ('[1:]', Slice(start=1)), |
28 | | - ('[:]', Slice()), |
29 | | - ('[*]', Slice()), |
30 | | - ('[:2]', Slice(end=2)), |
31 | | - ('[1:2]', Slice(start=1, end=2)), |
32 | | - ('[5:-2]', Slice(start=5, end=-2)) |
33 | | - ]) |
34 | | - |
35 | | - def test_nested(self): |
36 | | - self.check_parse_cases([('foo.baz', Child(Fields('foo'), Fields('baz'))), |
37 | | - ('foo.baz,bizzle', Child(Fields('foo'), Fields('baz', 'bizzle'))), |
38 | | - ('foo where baz', Where(Fields('foo'), Fields('baz'))), |
39 | | - ('foo..baz', Descendants(Fields('foo'), Fields('baz'))), |
40 | | - ('foo..baz.bing', Descendants(Fields('foo'), Child(Fields('baz'), Fields('bing'))))]) |
41 | | - |
42 | | - def test_goessner_examples(self): |
43 | | - """ |
44 | | - Test Stefan Goessner's `examples`_ |
45 | | -
|
46 | | - .. _examples: https://goessner.net/articles/JsonPath/index.html#e3 |
47 | | - """ |
48 | | - self.check_parse_cases([ |
49 | | - # The authors of all books in the store |
50 | | - ("$.store.book[*].author", |
51 | | - Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
52 | | - Slice()), Fields('author'))), |
53 | | - |
54 | | - # All authors |
55 | | - ("$..author", Descendants(Root(), Fields('author'))), |
56 | | - |
57 | | - # All things in the store |
58 | | - ("$.store.*", Child(Child(Root(), Fields('store')), Fields('*'))), |
59 | | - |
60 | | - # The price of everything in the store |
61 | | - ("$.store..price", |
62 | | - Descendants(Child(Root(), Fields('store')), Fields('price'))), |
63 | | - |
64 | | - # The third book |
65 | | - ("$..book[2]", |
66 | | - Child(Descendants(Root(), Fields('book')),Index(2))), |
67 | | - |
68 | | - # The last book in order |
69 | | - # ("$..book[(@.length-1)]", # Not implemented |
70 | | - # Child(Descendants(Root(), Fields('book')), Slice(start=-1))), |
71 | | - ("$..book[-1:]", |
72 | | - Child(Descendants(Root(), Fields('book')), Slice(start=-1))), |
73 | | - |
74 | | - # The first two books |
75 | | - # ("$..book[0,1]", # Not implemented |
76 | | - # Child(Descendants(Root(), Fields('book')), Slice(end=2))), |
77 | | - ("$..book[:2]", |
78 | | - Child(Descendants(Root(), Fields('book')), Slice(end=2))), |
79 | | - |
80 | | - # Filter all books with ISBN number |
81 | | - # ("$..book[?(@.isbn)]", None), # Not implemented |
82 | | - |
83 | | - # Filter all books cheaper than 10 |
84 | | - # ("$..book[?(@.price<10)]", None), # Not implemented |
85 | | - |
86 | | - # All members of JSON structure |
87 | | - ("$..*", Descendants(Root(), Fields('*'))), |
88 | | - ]) |
89 | | - |
90 | | - def test_a_few_more_examples(self): |
91 | | - self.check_parse_cases([ |
92 | | - # Navigate objects |
93 | | - ("$.store.book[0].title", |
94 | | - Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
95 | | - Index(0)), Fields('title'))), |
96 | | - |
97 | | - # Navigate dictionaries |
98 | | - ("$['store']['book'][0]['title']", |
99 | | - Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
100 | | - Index(0)), Fields('title'))), |
101 | | - ]) |
| 16 | + |
| 17 | +# TODO: This will be much more effective with a few regression tests and `arbitrary` parse . pretty testing |
| 18 | + |
| 19 | + |
| 20 | +def setup_module(): |
| 21 | + logging.basicConfig() |
| 22 | + |
| 23 | + |
| 24 | +def check_parse_case(string, parsed): |
| 25 | + parser = JsonPathParser( |
| 26 | + debug=True, |
| 27 | + # Note that just manually passing token streams avoids this |
| 28 | + # dep, but that sucks |
| 29 | + lexer_class=lambda: JsonPathLexer(debug=False), |
| 30 | + ) |
| 31 | + assert parser.parse(string) == parsed |
| 32 | + |
| 33 | + |
| 34 | +@pytest.mark.parametrize('string, parsed', [ |
| 35 | + ('foo', Fields('foo')), |
| 36 | + ('*', Fields('*')), |
| 37 | + ('baz,bizzle', Fields('baz','bizzle')), |
| 38 | + ('[1]', Index(1)), |
| 39 | + ('[1:]', Slice(start=1)), |
| 40 | + ('[:]', Slice()), |
| 41 | + ('[*]', Slice()), |
| 42 | + ('[:2]', Slice(end=2)), |
| 43 | + ('[1:2]', Slice(start=1, end=2)), |
| 44 | + ('[5:-2]', Slice(start=5, end=-2)), |
| 45 | +]) |
| 46 | +def test_atomic(string, parsed): |
| 47 | + check_parse_case(string, parsed) |
| 48 | + |
| 49 | + |
| 50 | +@pytest.mark.parametrize('string, parsed', [ |
| 51 | + ('foo.baz', Child(Fields('foo'), Fields('baz'))), |
| 52 | + ('foo.baz,bizzle', Child(Fields('foo'), Fields('baz', 'bizzle'))), |
| 53 | + ('foo where baz', Where(Fields('foo'), Fields('baz'))), |
| 54 | + ('foo..baz', Descendants(Fields('foo'), Fields('baz'))), |
| 55 | + ('foo..baz.bing', Descendants(Fields('foo'), Child(Fields('baz'), Fields('bing')))) |
| 56 | +]) |
| 57 | +def test_nested(string, parsed): |
| 58 | + check_parse_case(string, parsed) |
| 59 | + |
| 60 | + |
| 61 | +@pytest.mark.parametrize('string, parsed', [ |
| 62 | + # The authors of all books in the store |
| 63 | + ("$.store.book[*].author", |
| 64 | + Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
| 65 | + Slice()), Fields('author'))), |
| 66 | +
|
| 67 | + # All authors |
| 68 | + ("$..author", Descendants(Root(), Fields('author'))), |
| 69 | +
|
| 70 | + # All things in the store |
| 71 | + ("$.store.*", Child(Child(Root(), Fields('store')), Fields('*'))), |
| 72 | +
|
| 73 | + # The price of everything in the store |
| 74 | + ("$.store..price", |
| 75 | + Descendants(Child(Root(), Fields('store')), Fields('price'))), |
| 76 | +
|
| 77 | + # The third book |
| 78 | + ("$..book[2]", |
| 79 | + Child(Descendants(Root(), Fields('book')),Index(2))), |
| 80 | +
|
| 81 | + # The last book in order |
| 82 | + # ("$..book[(@.length-1)]", # Not implemented |
| 83 | + # Child(Descendants(Root(), Fields('book')), Slice(start=-1))), |
| 84 | + ("$..book[-1:]", |
| 85 | + Child(Descendants(Root(), Fields('book')), Slice(start=-1))), |
| 86 | +
|
| 87 | + # The first two books |
| 88 | + # ("$..book[0,1]", # Not implemented |
| 89 | + # Child(Descendants(Root(), Fields('book')), Slice(end=2))), |
| 90 | + ("$..book[:2]", |
| 91 | + Child(Descendants(Root(), Fields('book')), Slice(end=2))), |
| 92 | +
|
| 93 | + # Filter all books with ISBN number |
| 94 | + # ("$..book[?(@.isbn)]", None), # Not implemented |
| 95 | +
|
| 96 | + # Filter all books cheaper than 10 |
| 97 | + # ("$..book[?(@.price<10)]", None), # Not implemented |
| 98 | +
|
| 99 | + # All members of JSON structure |
| 100 | + ("$..*", Descendants(Root(), Fields('*'))), |
| 101 | +]) |
| 102 | +def test_goessner_examples(string, parsed): |
| 103 | + """ |
| 104 | + Test Stefan Goessner's `examples`_ |
| 105 | +
|
| 106 | + .. _examples: https://goessner.net/articles/JsonPath/index.html#e3 |
| 107 | + """ |
| 108 | + check_parse_case(string, parsed) |
| 109 | + |
| 110 | + |
| 111 | +@pytest.mark.parametrize('string, parsed', [ |
| 112 | + # Navigate objects |
| 113 | + ("$.store.book[0].title", |
| 114 | + Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
| 115 | + Index(0)), Fields('title'))), |
| 116 | +
|
| 117 | + # Navigate dictionaries |
| 118 | + ("$['store']['book'][0]['title']", |
| 119 | + Child(Child(Child(Child(Root(), Fields('store')), Fields('book')), |
| 120 | + Index(0)), Fields('title'))), |
| 121 | +]) |
| 122 | +def test_obj_v_dict(string, parsed): |
| 123 | + check_parse_case(string, parsed) |
0 commit comments