summaryrefslogtreecommitdiffstats
path: root/tests/test_jsonpath.py
blob: 4daf3c1ce097a608952bf4fb8fae7da0182f2c1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import json
import os
import unittest

from sqlglot import exp, jsonpath
from sqlglot.errors import ParseError, TokenError
from tests.helpers import FIXTURES_DIR


class TestJsonpath(unittest.TestCase):
    maxDiff = None

    def test_jsonpath(self):
        expected_expressions = [
            exp.JSONPathRoot(),
            exp.JSONPathKey(this=exp.JSONPathWildcard()),
            exp.JSONPathKey(this="a"),
            exp.JSONPathSubscript(this=0),
            exp.JSONPathKey(this="x"),
            exp.JSONPathUnion(expressions=[exp.JSONPathWildcard(), "y", 1]),
            exp.JSONPathKey(this="z"),
            exp.JSONPathSelector(this=exp.JSONPathFilter(this="(@.a == 'b'), 1:")),
            exp.JSONPathSubscript(this=exp.JSONPathSlice(start=1, end=5, step=None)),
            exp.JSONPathUnion(expressions=[1, exp.JSONPathFilter(this="@.a")]),
            exp.JSONPathSelector(this=exp.JSONPathScript(this="@.x)")),
        ]
        self.assertEqual(
            jsonpath.parse("$.*.a[0]['x'][*, 'y', 1].z[?(@.a == 'b'), 1:][1:5][1,?@.a][(@.x)]"),
            exp.JSONPath(expressions=expected_expressions),
        )

    def test_identity(self):
        for selector, expected in (
            ("$.select", "$.select"),
            ("$[(@.length-1)]", "$[(@.length-1)]"),
            ("$[((@.length-1))]", "$[((@.length-1))]"),
        ):
            with self.subTest(f"{selector} -> {expected}"):
                self.assertEqual(jsonpath.parse(selector).sql(), f"'{expected}'")

    def test_cts_file(self):
        with open(os.path.join(FIXTURES_DIR, "jsonpath", "cts.json")) as file:
            tests = json.load(file)["tests"]

        # sqlglot json path generator rewrites to a normal form
        overrides = {
            "$.☺": '$["☺"]',
            """$['a',1]""": """$["a",1]""",
            """$[*,'a']""": """$[*,"a"]""",
            """$..['a','d']""": """$..["a","d"]""",
            """$[1, ?@.a=='b', 1:]""": """$[1,?@.a=='b', 1:]""",
            """$["a"]""": """$.a""",
            """$["c"]""": """$.c""",
            """$['a']""": """$.a""",
            """$['c']""": """$.c""",
            """$[' ']""": """$[" "]""",
            """$['\\'']""": """$["\'"]""",
            """$['\\\\']""": """$["\\\\"]""",
            """$['\\/']""": """$["\\/"]""",
            """$['\\b']""": """$["\\b"]""",
            """$['\\f']""": """$["\\f"]""",
            """$['\\n']""": """$["\\n"]""",
            """$['\\r']""": """$["\\r"]""",
            """$['\\t']""": """$["\\t"]""",
            """$['\\u263A']""": """$["\\u263A"]""",
            """$['\\u263a']""": """$["\\u263a"]""",
            """$['\\uD834\\uDD1E']""": """$["\\uD834\\uDD1E"]""",
            """$['\\uD83D\\uDE00']""": """$["\\uD83D\\uDE00"]""",
            """$['']""": """$[""]""",
            """$[? @.a]""": """$[?@.a]""",
            """$[?\n@.a]""": """$[?@.a]""",
            """$[?\t@.a]""": """$[?@.a]""",
            """$[?\r@.a]""": """$[?@.a]""",
            """$[? (@.a)]""": """$[?(@.a)]""",
            """$[?\n(@.a)]""": """$[?(@.a)]""",
            """$[?\t(@.a)]""": """$[?(@.a)]""",
            """$[?\r(@.a)]""": """$[?(@.a)]""",
            """$[ ?@.a]""": """$[?@.a]""",
            """$[\n?@.a]""": """$[?@.a]""",
            """$[\t?@.a]""": """$[?@.a]""",
            """$[\r?@.a]""": """$[?@.a]""",
            """$ ['a']""": """$.a""",
            """$\n['a']""": """$.a""",
            """$\t['a']""": """$.a""",
            """$\r['a']""": """$.a""",
            """$['a'] ['b']""": """$.a.b""",
            """$['a'] \n['b']""": """$.a.b""",
            """$['a'] \t['b']""": """$.a.b""",
            """$['a'] \r['b']""": """$.a.b""",
            """$ .a""": """$.a""",
            """$\n.a""": """$.a""",
            """$\t.a""": """$.a""",
            """$\r.a""": """$.a""",
            """$[ 'a']""": """$.a""",
            """$[\n'a']""": """$.a""",
            """$[\t'a']""": """$.a""",
            """$[\r'a']""": """$.a""",
            """$['a' ]""": """$.a""",
            """$['a'\n]""": """$.a""",
            """$['a'\t]""": """$.a""",
            """$['a'\r]""": """$.a""",
            """$['a' ,'b']""": """$["a","b"]""",
            """$['a'\n,'b']""": """$["a","b"]""",
            """$['a'\t,'b']""": """$["a","b"]""",
            """$['a'\r,'b']""": """$["a","b"]""",
            """$['a', 'b']""": """$["a","b"]""",
            """$['a',\n'b']""": """$["a","b"]""",
            """$['a',\t'b']""": """$["a","b"]""",
            """$['a',\r'b']""": """$["a","b"]""",
            """$[1 :5:2]""": """$[1:5:2]""",
            """$[1\n:5:2]""": """$[1:5:2]""",
            """$[1\t:5:2]""": """$[1:5:2]""",
            """$[1\r:5:2]""": """$[1:5:2]""",
            """$[1: 5:2]""": """$[1:5:2]""",
            """$[1:\n5:2]""": """$[1:5:2]""",
            """$[1:\t5:2]""": """$[1:5:2]""",
            """$[1:\r5:2]""": """$[1:5:2]""",
            """$[1:5 :2]""": """$[1:5:2]""",
            """$[1:5\n:2]""": """$[1:5:2]""",
            """$[1:5\t:2]""": """$[1:5:2]""",
            """$[1:5\r:2]""": """$[1:5:2]""",
            """$[1:5: 2]""": """$[1:5:2]""",
            """$[1:5:\n2]""": """$[1:5:2]""",
            """$[1:5:\t2]""": """$[1:5:2]""",
            """$[1:5:\r2]""": """$[1:5:2]""",
        }

        for test in tests:
            selector = test["selector"]

            with self.subTest(f"{selector.strip()} /* {test['name']} */"):
                if test.get("invalid_selector"):
                    try:
                        jsonpath.parse(selector)
                    except (ParseError, TokenError):
                        pass
                else:
                    path = jsonpath.parse(selector)
                    self.assertEqual(path.sql(), f"'{overrides.get(selector, selector)}'")