1# -*- coding: utf-8 -*-
2
3import sys
4import os
5import redis
6import json
7from RLTest import Env
8from includes import *
9
10from RLTest import Defaults
11
12Defaults.decode_responses = True
13
14# ----------------------------------------------------------------------------------------------
15
16# Path to JSON test case files
17HERE = os.path.abspath(os.path.dirname(__file__))
18ROOT = os.path.abspath(os.path.join(HERE, "../.."))
19TESTS_ROOT = os.path.abspath(os.path.join(HERE, ".."))
20JSON_PATH = os.path.join(TESTS_ROOT, 'files')
21
22# ----------------------------------------------------------------------------------------------
23
24# TODO: these are currently not supported so ignore them
25json_ignore = [
26    'pass-json-parser-0002.json',   # UTF-8 to Unicode
27    'pass-json-parser-0005.json',   # big numbers
28    'pass-json-parser-0006.json',   # UTF-8 to Unicode
29    'pass-json-parser-0007.json',   # UTF-8 to Unicode
30    'pass-json-parser-0012.json',   # UTF-8 to Unicode
31    'pass-jsonsl-1.json',           # big numbers
32    'pass-jsonsl-yelp.json',        # float precision
33]
34
35# Some basic documents to use in the tests
36docs = {
37    'simple': {
38        'foo': 'bar',
39    },
40    'basic': {
41        'string': 'string value',
42        'none': None,
43        'bool': True,
44        'int': 42,
45        'num': 4.2,
46        'arr': [42, None, -1.2, False, ['sub', 'array'], {'subdict': True}],
47        'dict': {
48            'a': 1,
49            'b': '2',
50            'c': None,
51        }
52    },
53    'scalars': {
54        'unicode': 'string value',
55        'NoneType': None,
56        'bool': True,
57        'int': 42,
58        'float': -1.2,
59    },
60    'values': {
61        'str': 'string value',
62        'NoneType': None,
63        'bool': True,
64        'int': 42,
65        'float': -1.2,
66        'dict': {},
67        'list': []
68    },
69    'types': {
70        'null':     None,
71        'boolean':  False,
72        'integer':  42,
73        'number':   1.2,
74        'string':   'str',
75        'object':   {},
76        'array':    [],
77    },
78}
79
80#----------------------------------------------------------------------------------------------
81
82# def getCacheInfo(env):
83#     r = env
84#     res = r.cmd('JSON._CACHEINFO')
85#     ret = {}
86#     for x in range(0, len(res), 2):
87#         ret[res[x]] = res[x+1]
88#     return ret
89
90
91def assertOk(r, x, msg=None):
92    r.assertOk(x, message=msg)
93
94def assertExists(r, key, msg=None):
95    r.assertTrue(r.exists(key), message=msg)
96
97def assertNotExists(r, key, msg=None):
98    r.assertFalse(r.exists(key), message=msg)
99
100#----------------------------------------------------------------------------------------------
101
102def testSetRootWithInvalidJSONValuesShouldFail(env):
103    """Test that setting the root of a ReJSON key with invalid JSON values fails"""
104    r = env
105    invalid = ['{', '}', '[', ']', '{]', '[}', '\\', '\\\\', '',
106               ' ', '\\"', '\'', '\[', '\x00', '\x0a', '\x0c',
107               # '\xff' TODO pending https://github.com/RedisLabsModules/redismodule-rs/pull/15
108               ]
109    for i in invalid:
110        r.expect('JSON.SET', 'test', '.', i).raiseError()
111        assertNotExists(r, 'test%s' % i)
112
113def testSetInvalidPathShouldFail(env):
114    """Test that invalid paths fail"""
115    r = env
116
117    invalid = ['', ' ', '\x00', '\x0a', '\x0c',
118               # '\xff' TODO pending https://github.com/RedisLabsModules/redismodule-rs/pull/15
119               '."', '.\x00', '.\x0a\x0c', '.-foo', '.43',
120               '.foo\n.bar']
121    for i in invalid:
122        r.expect('JSON.SET', 'test', i, 'null').raiseError()
123        assertNotExists(r, 'test%s' % i)
124
125def testSetRootWithJSONValuesShouldSucceed(env):
126    """Test that the root of a JSON key can be set with any valid JSON"""
127    r = env
128    for v in ['string', 1, -2, 3.14, None, True, False, [], {}]:
129        r.cmd('DEL', 'test')
130        j = json.dumps(v)
131        r.assertOk(r.execute_command('JSON.SET', 'test', '.', j))
132        r.assertExists('test')
133        s = json.loads(r.execute_command('JSON.GET', 'test'))
134        r.assertEqual(v, s)
135
136def testSetReplaceRootShouldSucceed(env):
137    """Test replacing the root of an existing key with a valid object succeeds"""
138    r = env
139    r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(docs['basic'])))
140    r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(docs['simple'])))
141    raw = r.execute_command('JSON.GET', 'test', '.')
142    r.assertEqual(json.loads(raw), docs['simple'])
143    for k, v in iter(docs['values'].items()):
144        r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(v)))
145        data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
146        r.assertEqual(str(type(data)), '<class \'{}\'>'.format(k))
147        r.assertEqual(data, v)
148
149def testSetGetWholeBasicDocumentShouldBeEqual(env):
150    """Test basic JSON.GET/JSON.SET"""
151    r = env
152    data = json.dumps(docs['basic'])
153    r.assertOk(r.execute_command('JSON.SET', 'test', '.', data))
154    r.assertExists('test')
155    r.assertEqual(json.dumps(json.loads(r.execute_command('JSON.GET', 'test'))), data)
156
157def testSetBehaviorModifyingSubcommands(env):
158    """Test JSON.SET's NX and XX subcommands"""
159    r = env
160
161    # test against the root
162    r.assertIsNone(r.execute_command('JSON.SET', 'test', '.', '{}', 'XX'))
163    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{}', 'NX'))
164    r.assertIsNone(r.execute_command('JSON.SET', 'test', '.', '{}', 'NX'))
165    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{}', 'XX'))
166
167    # test an object key
168    r.assertIsNone(r.execute_command('JSON.SET', 'test', '.foo', '[]', 'XX'))
169    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '[]', 'NX'))
170    r.assertIsNone(r.execute_command('JSON.SET', 'test', '.foo', '[]', 'NX'))
171    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '[1]', 'XX'))
172
173    # verify failure for arrays
174    r.expect('JSON.SET', 'test', '.foo[1]', 'null', 'NX').raiseError()
175    # r.expect('JSON.SET', 'test', '.foo[1]', 'null', 'XX').raiseError()
176
177    # Wrong arguments
178    r.expect('JSON.SET', 'test', '.foo', '[]', '').raiseError()
179    r.expect('JSON.SET', 'test', '.foo', '[]', 'NN').raiseError()
180    r.expect('JSON.SET', 'test', '.foo', '[]', 'FORMAT', 'TT').raiseError()
181    r.expect('JSON.SET', 'test', '.foo', '[]', 'XX', 'FORMAT', '').raiseError()
182    r.expect('JSON.SET', 'test', '.foo', '[]', 'XX', 'XN').raiseError()
183    r.expect('JSON.SET', 'test', '.foo', '[]', 'XX', '').raiseError()
184
185def testSetWithBracketNotation(env):
186    r = env
187
188    r.assertOk(r.execute_command('JSON.SET', 'x', '.', '{}'))
189    r.assertOk(r.execute_command('JSON.SET', 'x', '.["f1"]', '{}'))  # Simple bracket notation
190    r.assertOk(r.execute_command('JSON.SET', 'x', '.["f1"].f2', '[0,0,0]'))  # Mixed with dot notation
191    r.assertOk(r.execute_command('JSON.SET', 'x', '.["f1"].f2[1]', '{}'))  # Replace in array
192    r.assertOk(r.execute_command('JSON.SET', 'x', '.["f1"].f2[1]["f.]$.f"]', '{}'))  # Dots and invalid chars in the brackets
193    r.assertOk(r.execute_command('JSON.SET', 'x', '.["f1"]["f2"][1]["f.]$.f"]', '1'))  # Replace existing value
194    r.assertIsNone(r.execute_command('JSON.SET', 'x', '.["f3"].f2', '1'))  # Fail trying to set f2 when f3 doesn't exist
195    r.assertEqual(json.loads(r.execute_command('JSON.GET', 'x')), {'f1': {'f2': [0, {'f.]$.f': 1}, 0]}})  # Make sure it worked
196
197def testGetWithBracketNotation(env):
198    r = env
199
200    r.assertOk(r.execute_command('JSON.SET', 'x', '.', '[1,2,3]'))
201    r.assertEqual(json.loads(r.execute_command('JSON.GET', 'x', '.[1]')), 2) # dot notation - single value
202    r.assertEqual(json.loads(r.execute_command('JSON.GET', 'x', '[1]')), 2) # implicit dot notation - single value
203    r.assertEqual(json.loads(r.execute_command('JSON.GET', 'x', '$.[1]')), [2]) # dollar notation - array
204    r.assertEqual(json.loads(r.execute_command('JSON.GET', 'x', '$[1]')), [2]) # dollar notation - array
205
206def testSetWithPathErrors(env):
207    r = env
208
209    r.expect('JSON.SET', 'x', '.', '{}').ok()
210
211    # Add to non static path
212    r.expect('JSON.SET', 'x', '$..f', 1).raiseError()
213    # r.assertEqual(str(e.exception), 'Err: wrong static path')
214
215    # Treat object as array
216    r.expect('JSON.SET', 'x', '$[0]', 1).raiseError()
217    # r.assertEqual(str(e.exception), 'Err: path not an object')
218
219def testGetNonExistantPathsFromBasicDocumentShouldFail(env):
220    """Test failure of getting non-existing values"""
221
222    r = env
223
224    r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(docs['scalars'])))
225
226    # Paths that do not exist
227    paths = ['.foo', 'boo', '.key1[0]', '.key2.bar', '.key5[99]', '.key5["moo"]']
228    for p in paths:
229        r.expect('JSON.GET', 'test', p).raiseError()
230    # TODO uncomment
231    # # Test failure in multi-path get
232    #     r.expect('JSON.GET', 'test', '.bool', paths[0]).raiseError()
233
234def testGetPartsOfValuesDocumentOneByOne(env):
235    """Test type and value returned by JSON.GET"""
236    r = env
237    r.expect('JSON.SET', 'test', '.', json.dumps(docs['values'])).ok()
238    for k, v in iter(docs['values'].items()):
239        data = json.loads(r.execute_command('JSON.GET', 'test', '.{}'.format(k)))
240        r.assertEqual(str(type(data)), '<class \'{}\'>'.format(k), message=k)
241        r.assertEqual(data, v, message=k)
242
243def testGetPartsOfValuesDocumentMultiple(env):
244    """Test correctness of an object returned by JSON.GET"""
245    r = env
246    r.expect('JSON.SET', 'test', '.', json.dumps(docs['values'])).ok()
247    data = json.loads(r.execute_command('JSON.GET', 'test', *docs['values'].keys()))
248    r.assertEqual(data, docs['values'])
249
250def testGetFormatting(env):
251    r = env
252
253    objects_to_test = [
254        {'obj': {'f': 'v'}},
255        {'arr': [0, 1]}
256    ]
257    formatted_objects = [
258        '{{{newline}{indent}"obj":{space}{{{newline}{indent}{indent}"f":{space}"v"{newline}{indent}}}{newline}}}',
259        '{{{newline}{indent}"arr":{space}[{newline}{indent}{indent}0,{newline}{indent}{indent}1{newline}{indent}]{newline}}}'
260    ]
261
262    for o in objects_to_test:
263        r.assertOk(r.execute_command('JSON.SET', list(o.keys()).pop(), '$', json.dumps(o)))
264
265    for space in ['', ' ', '\t', '  ']:
266        for indent in ['', ' ', '\t', '  ']:
267            for newline in ['', '\n', '\r\n']:
268                for o, f in zip(objects_to_test, formatted_objects):
269                    res = r.execute_command('JSON.GET', list(o.keys()).pop(), 'INDENT', indent, 'NEWLINE', newline, 'SPACE', space)
270                    r.assertEqual(res, f.format(newline=newline, space=space, indent=indent))
271
272def testBackwardRDB(env):
273    env.skipOnCluster()
274    dbFileName = env.cmd('config', 'get', 'dbfilename')[1]
275    dbDir = env.cmd('config', 'get', 'dir')[1]
276    rdbFilePath = os.path.join(dbDir, dbFileName)
277    env.stop()
278    try:
279        os.unlink(rdbFilePath)
280    except OSError:
281        pass
282    filePath = os.path.join(JSON_PATH, 'backward.rdb')
283    os.symlink(filePath, rdbFilePath)
284    env.start()
285
286    r = env
287    data = json.loads(r.execute_command('JSON.GET', 'complex'))
288    r.assertEqual(data, {"a":{"b":[{"c":{"d":[1,'2'],"e":None}},True],"a":'a'},"b":1,"c":True,"d":None})
289
290def testSetBSON(env):
291    r = env
292    bson = open(os.path.join(JSON_PATH , 'bson_bytes_1.bson'), 'rb').read()
293    r.assertOk(r.execute_command('JSON.SET', 'test', '.', bson, 'FORMAT', 'BSON'))
294    r.expect('JSON.GET', 'test', *docs['values'].keys()).raiseError()
295
296def testMgetCommand(env):
297    """Test REJSON.MGET command"""
298    r = env
299
300    # Set up a few keys
301    for d in range(0, 5):
302        key = 'doc:{}'.format(d)
303        r.cmd('DEL', key)
304        r.expect('JSON.SET', key, '.', json.dumps(docs['basic'])).ok()
305
306    # Test an MGET that succeeds on all keys
307    raw = r.execute_command('JSON.MGET', *['doc:{}'.format(d) for d in range(0, 5)] + ['.'])
308    r.assertEqual(len(raw), 5)
309    for d in range(0, 5):
310        key = 'doc:{}'.format(d)
311        r.assertEqual(json.loads(raw[d]), docs['basic'], d)
312
313    # Test an MGET that fails for one key
314    r.cmd('DEL', 'test')
315    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"bool":false}'))
316    raw = r.execute_command('JSON.MGET', 'test', 'doc:0', 'foo', '.bool')
317    r.assertEqual(len(raw), 3)
318    r.assertFalse(json.loads(raw[0]))
319    r.assertTrue(json.loads(raw[1]))
320    r.assertEqual(raw[2], None)
321
322    # Test that MGET on missing path
323    raw = r.execute_command('JSON.MGET', 'doc:0', 'doc:1', '42isnotapath')
324    r.assertEqual(len(raw), 2)
325    r.assertEqual(raw[0], None)
326    r.assertEqual(raw[1], None)
327
328    # Test that MGET fails on path errors
329    r.cmd('DEL', 'test')
330    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"bull":4.2}'))
331    raw = r.execute_command('JSON.MGET', 'doc:0', 'test', 'doc:1', '.bool')
332    r.assertEqual(len(raw), 3)
333    r.assertTrue(json.loads(raw[0]))
334    r.assertEqual(raw[1], None)
335    r.assertTrue(json.loads(raw[2]))
336
337def testToggleCommand(env):
338    """Test REJSON.TOGGLE command"""
339    r = env
340    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo":true}'))
341    r.assertEqual(r.execute_command('JSON.TOGGLE','test','.foo'), 'false')
342    r.assertEqual(r.execute_command('JSON.TOGGLE','test','.foo'), 'true')
343
344    # Test Toggeling Empty Path
345    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo":"bar"}'))
346    r.expect('JSON.TOGGLE', 'test', '.bar').raiseError()
347
348    # Test Toggeling Non Boolean
349    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo":"bar"}'))
350    r.expect('JSON.TOGGLE','test','.foo').raiseError()
351
352def testDelCommand(env):
353    """Test REJSON.DEL command"""
354    r = env
355    # Test deleting an empty object
356    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{}'))
357    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.'), 1)
358    assertNotExists(r, 'test')
359
360    # Test deleting an empty object
361    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo": "bar", "baz": "qux"}'))
362    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.baz'), 1)
363    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 1)
364    r.assertIsNone(r.execute_command('JSON.TYPE', 'test', '.baz'))
365    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.foo'), 1)
366    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 0)
367    r.assertIsNone(r.execute_command('JSON.TYPE', 'test', '.foo'))
368    r.assertEqual(r.execute_command('JSON.TYPE', 'test', '.'), 'object')
369
370    # Test deleting some keys from an object
371    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{}'))
372    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '"bar"'))
373    r.assertOk(r.execute_command('JSON.SET', 'test', '.baz', '"qux"'))
374    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.baz'), 1)
375    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 1)
376    r.assertIsNone(r.execute_command('JSON.TYPE', 'test', '.baz'))
377    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.foo'), 1)
378    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 0)
379    r.assertIsNone(r.execute_command('JSON.TYPE', 'test', '.foo'))
380    r.assertEqual(r.execute_command('JSON.TYPE', 'test', '.'), 'object')
381
382    # Test with an array
383    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '"bar"'))
384    r.assertOk(r.execute_command('JSON.SET', 'test', '.baz', '"qux"'))
385    r.assertOk(r.execute_command('JSON.SET', 'test', '.arr', '[1.2,1,2]'))
386    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.arr[1]'), 1)
387    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 3)
388    r.assertEqual(r.execute_command('JSON.ARRLEN', 'test', '.arr'), 2)
389    r.assertEqual(r.execute_command('JSON.TYPE', 'test', '.arr'), 'array')
390    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.arr'), 1)
391    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.'), 2)
392    r.assertEqual(r.execute_command('JSON.DEL', 'test', '.'), 1)
393    r.assertIsNone(r.execute_command('JSON.GET', 'test'))
394
395def testObjectCRUD(env):
396    r = env
397
398    # Create an object
399    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{ }'))
400    r.assertEqual('object', r.execute_command('JSON.TYPE', 'test', '.'))
401    r.assertEqual(0, r.execute_command('JSON.OBJLEN', 'test', '.'))
402    raw = r.execute_command('JSON.GET', 'test')
403    data = json.loads(raw)
404    r.assertEqual(data, {})
405
406    # Test failure to access a non-existing element
407    r.expect('JSON.GET', 'test', '.foo').raiseError()
408
409    # Test setting a key in the oject
410    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '"bar"'))
411    r.assertEqual(1, r.execute_command('JSON.OBJLEN', 'test', '.'))
412    raw = r.execute_command('JSON.GET', 'test', '.')
413    data = json.loads(raw)
414    r.assertEqual(data, {u'foo': u'bar'})
415
416    # Test replacing a key's value in the object
417    r.assertOk(r.execute_command('JSON.SET', 'test', '.foo', '"baz"'))
418    raw = r.execute_command('JSON.GET', 'test', '.')
419    data = json.loads(raw)
420    r.assertEqual(data, {u'foo': u'baz'})
421
422    # Test adding another key to the object
423    r.assertOk(r.execute_command('JSON.SET', 'test', '.boo', '"far"'))
424    r.assertEqual(2, r.execute_command('JSON.OBJLEN', 'test', '.'))
425    raw = r.execute_command('JSON.GET', 'test', '.')
426    data = json.loads(raw)
427    r.assertEqual(data, {u'foo': u'baz', u'boo': u'far'})
428
429    # Test deleting a key from the object
430    r.assertEqual(1, r.execute_command('JSON.DEL', 'test', '.foo'))
431    raw = r.execute_command('JSON.GET', 'test', '.')
432    data = json.loads(raw)
433    r.assertEqual(data, {u'boo': u'far'})
434
435    # Test replacing the object
436    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo": "bar"}'))
437    raw = r.execute_command('JSON.GET', 'test', '.')
438    data = json.loads(raw)
439    r.assertEqual(data, {u'foo': u'bar'})
440
441    # Test deleting the object
442    r.assertEqual(1, r.execute_command('JSON.DEL', 'test', '.'))
443    r.assertIsNone(r.execute_command('JSON.GET', 'test', '.'))
444
445    # Test deleting with default (root) path
446    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo": "bar"}'))
447    r.assertEqual(1, r.execute_command('JSON.DEL', 'test'))
448    r.assertIsNone(r.execute_command('JSON.GET', 'test', '.'))
449
450def testClear(env):
451    """Test JSON.CLEAR command"""
452
453    r = env
454    multi_content = r'{"n":42,"s":"42","arr":[{"n":44},"s",{"n":{"a":1,"b":2}},{"n2":{"x":3.02,"n":["to","be","cleared",4],"y":4.91}}]}'
455    r.expect('JSON.SET', 'test', '.', multi_content).ok()
456
457    # Test get multi results (using .. recursive descent)
458    r.expect('JSON.GET', 'test', '$..n').equal(r'[42,44,{"a":1,"b":2},["to","be","cleared",4]]')
459
460    # Make sure specific obj content exists before clear
461    obj_content = r'[{"a":1,"b":2}]'
462    obj_content_legacy = r'{"a":1,"b":2}'
463    r.expect('JSON.GET', 'test', '$.arr[2].n').equal(obj_content)
464    r.expect('JSON.GET', 'test', '.arr[2].n').equal(obj_content_legacy)
465    # Make sure specific arr content exists before clear
466    arr_content = r'[["to","be","cleared",4]]'
467    arr_content_legacy = r'["to","be","cleared",4]'
468    r.expect('JSON.GET', 'test', '$.arr[3].n2.n').equal(arr_content)
469    r.expect('JSON.GET', 'test', '.arr[3].n2.n').equal(arr_content_legacy)
470
471    # Clear obj and arr with specific paths
472    r.expect('JSON.CLEAR', 'test', '$.arr[2].n').equal(1)
473    r.expect('JSON.CLEAR', 'test', '$.arr[3].n2.n').equal(1)
474
475    # Fail clear on inappropriate path (not obj or arr)
476    r.expect('JSON.CLEAR', 'test', '$.arr[1]').equal(0)
477
478    # Make sure specific obj content was cleared
479    r.expect('JSON.GET', 'test', '$.arr[2].n').equal('[{}]')
480    r.expect('JSON.GET', 'test', '.arr[2].n').equal('{}')
481    # Make sure specific arr content was cleared
482    r.expect('JSON.GET', 'test', '$.arr[3].n2.n').equal('[[]]')
483    r.expect('JSON.GET', 'test', '.arr[3].n2.n').equal('[]')
484
485    # Make sure only appropriate content (obj and arr) was cleared
486    r.expect('JSON.GET', 'test', '$..n').equal('[42,44,{},[]]')
487
488    # Clear dynamic path
489    r.expect('JSON.SET', 'test', '.', r'{"n":42,"s":"42","arr":[{"n":44},"s",{"n":{"a":1,"b":2}},{"n2":{"x":3.02,"n":["to","be","cleared",4],"y":4.91}}]}') \
490        .ok()
491    r.expect('JSON.CLEAR', 'test', '$.arr.*').equal(3)
492    r.expect('JSON.GET', 'test', '$').equal('[{"n":42,"s":"42","arr":[{},"s",{},{}]}]')
493
494    # Clear root
495    r.expect('JSON.SET', 'test', '.', r'{"n":42,"s":"42","arr":[{"n":44},"s",{"n":{"a":1,"b":2}},{"n2":{"x":3.02,"n":["to","be","cleared",4],"y":4.91}}]}') \
496        .ok()
497    # TODO: switch order of the following paths and expect .equals(2) when supporting multi-paths in JSON.CLEAR
498    r.expect('JSON.CLEAR', 'test', '$', '$.arr[2].n').equal(1)
499    r.expect('JSON.GET', 'test', '$').equal('[{}]')
500
501    r.expect('JSON.SET', 'test', '$', obj_content_legacy).ok()
502    r.expect('JSON.CLEAR', 'test').equal(1)
503    r.expect('JSON.GET', 'test', '$').equal('[{}]')
504
505    # Clear none existing path
506    r.expect('JSON.SET', 'test', '.', r'{"a":[1,2], "b":{"c":"d"}}').ok()
507    r.expect('JSON.CLEAR', 'test', '$.c').equal(0)
508    r.expect('JSON.GET', 'test', '$').equal('[{"a":[1,2],"b":{"c":"d"}}]')
509
510    r.expect('JSON.CLEAR', 'test', '$.b..a').equal(0)
511    r.expect('JSON.GET', 'test', '$').equal('[{"a":[1,2],"b":{"c":"d"}}]')
512
513    # Key doesn't exist
514    r.expect('JSON.CLEAR', 'not_test_key', '$').raiseError()
515
516def testArrayCRUD(env):
517    """Test JSON Array CRUDness"""
518
519    r = env
520
521    # Test creation of an empty array
522    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '[]'))
523    r.assertEqual('array', r.execute_command('JSON.TYPE', 'test', '.'))
524    r.assertEqual(0, r.execute_command('JSON.ARRLEN', 'test', '.'))
525
526    # Test failure of setting an element at different positons in an empty array
527    r.expect('JSON.SET', 'test', '[0]', 0).raiseError()
528    r.expect('JSON.SET', 'test', '[19]', 0).raiseError()
529    r.expect('JSON.SET', 'test', '[-1]', 0).raiseError()
530
531    # Test appending and inserting elements to the array
532    r.assertEqual(1, r.execute_command('JSON.ARRAPPEND', 'test', '.', 1))
533    r.assertEqual(1, r.execute_command('JSON.ARRLEN', 'test', '.'))
534    r.assertEqual(2, r.execute_command('JSON.ARRINSERT', 'test', '.', 0, -1))
535    r.assertEqual(2, r.execute_command('JSON.ARRLEN', 'test', '.'))
536    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
537    r.assertListEqual([-1, 1, ], data)
538    r.assertEqual(3, r.execute_command('JSON.ARRINSERT', 'test', '.', -1, 0))
539    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
540    r.assertListEqual([-1, 0, 1, ], data)
541    r.assertEqual(5, r.execute_command('JSON.ARRINSERT', 'test', '.', -3, -3, -2))
542    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
543    r.assertListEqual([-3, -2, -1, 0, 1, ], data)
544    r.assertEqual(7, r.execute_command('JSON.ARRAPPEND', 'test', '.', 2, 3))
545    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
546    r.assertListEqual([-3, -2, -1, 0, 1, 2, 3], data)
547
548    # Test replacing elements in the array
549    r.assertOk(r.execute_command('JSON.SET', 'test', '[0]', '"-inf"'))
550    r.assertOk(r.execute_command('JSON.SET', 'test', '[-1]', '"+inf"'))
551    r.assertOk(r.execute_command('JSON.SET', 'test', '[3]', 'null'))
552    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
553    r.assertListEqual([u'-inf', -2, -1, None, 1, 2, u'+inf'], data)
554
555    # Test deleting from the array
556    r.assertEqual(1, r.execute_command('JSON.DEL', 'test', '[1]'))
557    r.assertEqual(1, r.execute_command('JSON.DEL', 'test', '[-2]'))
558    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
559    r.assertListEqual([u'-inf', -1, None, 1, u'+inf'], data)
560
561    # TODO: Should not be needed once DEL works
562    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '["-inf", -1, null, 1, "+inf"]'))
563
564    # Test trimming the array
565    r.assertEqual(4, r.execute_command('JSON.ARRTRIM', 'test', '.', 1, -1))
566    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
567    r.assertListEqual([-1, None, 1, u'+inf'], data)
568    r.assertEqual(3, r.execute_command('JSON.ARRTRIM', 'test', '.', 0, -2))
569    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
570    r.assertListEqual([-1, None, 1], data)
571    r.assertEqual(1, r.execute_command('JSON.ARRTRIM', 'test', '.', 1, 1))
572    data = json.loads(r.execute_command('JSON.GET', 'test', '.'))
573    r.assertListEqual([None], data)
574
575    # Test replacing the array
576    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '[true]'))
577    r.assertEqual('array', r.execute_command('JSON.TYPE', 'test', '.'))
578    r.assertEqual(1, r.execute_command('JSON.ARRLEN', 'test', '.'))
579    r.assertEqual('true', r.execute_command('JSON.GET', 'test', '[0]'))
580
581def testArrIndexCommand(env):
582    """Test JSON.ARRINDEX command"""
583    r = env
584
585    r.assertOk(r.execute_command('JSON.SET', 'test',
586                                    '.', '{ "arr": [0, 1, 2, 3, 2, 1, 0] }'))
587    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0), 0)
588    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 3), 3)
589    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 4), -1)
590    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 1), 6)
591    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, -1), 6)
592    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 6), 6)
593    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 4, -0), 6)
594    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 5, -1), -1)
595    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 5, 0), 6)
596    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 2, -2, 6), -1)
597    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '"foo"'), -1)
598
599    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', 4, '[4]'), 8)
600    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 3), 3)
601    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 2, 3), 5)
602    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '[4]'), 4)
603
604    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 1), 1)
605
606    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '$.arr', 1), [1])
607    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '$.arr', 2, 1, 4), [2])
608    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '$.arr', 6), [-1])
609    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '$.arr', 3, 0, 2), [-1])
610
611
612def testArrInsertCommand(env):
613    """Test JSON.ARRINSERT command"""
614    r = env
615
616    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{ "arr": [] }'))
617    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', 0, '1'), 1)
618    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', -1, '2'), 2)
619    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', -2, '3'), 3)
620    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', 3, '4'), 4)
621    r.assertEqual(r.execute_command('JSON.GET', 'test', '.arr'), "[3,2,1,4]")
622
623    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', 1, '5'), 5)
624    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', -2, '6'), 6)
625    r.assertEqual(r.execute_command('JSON.GET', 'test', '.arr'), "[3,5,2,6,1,4]")
626
627    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', -3, '7', '{"A":"Z"}', '9'), 9)
628    r.assertEqual(r.execute_command('JSON.GET', 'test', '.arr'), '[3,5,2,7,{"A":"Z"},9,6,1,4]')
629
630    r.expect('JSON.ARRINSERT', 'test', '.arr', -10, '10').raiseError()
631    r.expect('JSON.ARRINSERT', 'test', '.arr', 10, '10').raiseError()
632
633def testArrIndexMixCommand(env):
634    """Test JSON.ARRINDEX command with mixed values"""
635    r = env
636
637    r.assertOk(r.execute_command('JSON.SET', 'test',
638                                    '.', '{ "arr": [0, 1, 2, 3, 2, 1, 0, {"val": 4}, {"val": 9}, [3,4,8], ["a", "b", 8]] }'))
639    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0), 0)
640    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 3), 3)
641    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 4), -1)
642    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 1), 6)
643    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, -5), 6)
644    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 6), 6)
645    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 4, -0), 6)
646    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 0, 5, -1), 6)
647    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 2, -2, 6), -1)
648    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '"foo"'), -1)
649
650    r.assertEqual(r.execute_command('JSON.ARRINSERT', 'test', '.arr', 4, '[4]'), 12)
651    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 3), 3)
652    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', 2, 3), 5)
653    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '[4]'), 4)
654    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '{\"val\":4}'), 8)
655    r.assertEqual(r.execute_command('JSON.ARRINDEX', 'test', '.arr', '["a", "b", 8]'), 11)
656
657def testArrTrimCommand(env):
658    """Test JSON.ARRTRIM command"""
659
660    r = env
661    r.assertOk(r.execute_command('JSON.SET', 'test',
662                                    '.', '{ "arr": [0, 1, 2, 3, 2, 1, 0] }'))
663    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', 1, -2), 5)
664    r.assertListEqual(json.loads(r.execute_command(
665        'JSON.GET', 'test', '.arr')), [1, 2, 3, 2, 1])
666    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', 0, 99), 5)
667    r.assertListEqual(json.loads(r.execute_command(
668        'JSON.GET', 'test', '.arr')), [1, 2, 3, 2, 1])
669    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', 0, 2), 3)
670    r.assertListEqual(json.loads(r.execute_command(
671        'JSON.GET', 'test', '.arr')), [1, 2, 3])
672    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', 99, 2), 0)
673    r.assertListEqual(json.loads(r.execute_command('JSON.GET', 'test', '.arr')), [])
674
675    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', -1, 0), 0)
676
677    r.assertOk(r.execute_command('JSON.SET', 'test',
678                                 '.', '{ "arr": [0, 1, 2, 3, 2, 1, 0] }'))
679    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', -1, 0), 0)
680
681    r.assertOk(r.execute_command('JSON.SET', 'test',
682                                 '.', '{ "arr": [0, 1, 2, 3, 2, 1, 0] }'))
683    r.assertEqual(r.execute_command('JSON.ARRTRIM', 'test', '.arr', -4, 1), 0)
684
685
686def testArrPopCommand(env):
687    """Test JSON.ARRPOP command"""
688
689    r = env
690
691    r.assertOk(r.execute_command('JSON.SET', 'test',
692                                    '.', '[1,2,3,4,5,6,7,8,9]'))
693    r.assertEqual('9', r.execute_command('JSON.ARRPOP', 'test'))
694    r.assertEqual('8', r.execute_command('JSON.ARRPOP', 'test', '.'))
695    r.assertEqual('7', r.execute_command('JSON.ARRPOP', 'test', '.', -1))
696    r.assertEqual('5', r.execute_command('JSON.ARRPOP', 'test', '.', -2))
697    r.assertEqual('1', r.execute_command('JSON.ARRPOP', 'test', '.', 0))
698    r.assertEqual('4', r.execute_command('JSON.ARRPOP', 'test', '.', 2))
699    r.assertEqual('6', r.execute_command('JSON.ARRPOP', 'test', '.', 99))
700    r.assertEqual('2', r.execute_command('JSON.ARRPOP', 'test', '.', -99))
701    r.assertEqual('3', r.execute_command('JSON.ARRPOP', 'test'))
702    r.assertIsNone(r.execute_command('JSON.ARRPOP', 'test'))
703    r.assertIsNone(r.execute_command('JSON.ARRPOP', 'test', '.'))
704    r.assertIsNone(r.execute_command('JSON.ARRPOP', 'test', '.', 2))
705
706def testArrPopErrors(env):
707    r = env
708
709    r.assertOk(r.execute_command('JSON.SET', 'test','.', '1'))
710    r.expect('JSON.ARRPOP', 'test').error().contains("not an array")
711
712def testArrWrongChars(env):
713    r = env
714
715    r.assertOk(r.execute_command('JSON.SET', 'test','.', '{"arr":[1,2]}'))
716    r.expect('JSON.ARRINSERT', 'test', '.arr', 0, b'\x80abc').error().contains("Couldn't parse as UTF-8 string")
717    r.expect('JSON.ARRAPPEND', 'test', '.arr', b'\x80abc').error().contains("Couldn't parse as UTF-8 string")
718
719def testArrTrimErrors(env):
720    r = env
721
722    r.assertOk(r.execute_command('JSON.SET', 'test','.', '1'))
723    r.expect('JSON.ARRTRIM', 'test', '.', '0', '1').error().contains("not an array")
724
725def testTypeCommand(env):
726    """Test JSON.TYPE command"""
727    r = env
728    for k, v in iter(docs['types'].items()):
729        r.cmd('DEL', 'test')
730        r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(v)))
731        reply = r.execute_command('JSON.TYPE', 'test', '.')
732        r.assertEqual(reply, k)
733
734def testLenCommands(env):
735    """Test the JSON.ARRLEN, JSON.OBJLEN and JSON.STRLEN commands"""
736    r = env
737
738    # test that nothing is returned for empty keys
739    r.assertEqual(r.execute_command('JSON.ARRLEN', 'foo', '.bar'), None)
740
741    # test elements with valid lengths
742    r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(docs['basic'])))
743    r.assertEqual(r.execute_command('JSON.STRLEN', 'test', '.string'), 12)
744    r.assertEqual(r.execute_command('JSON.OBJLEN', 'test', '.dict'), 3)
745    r.assertEqual(r.execute_command('JSON.ARRLEN', 'test', '.arr'), 6)
746
747    # test elements with undefined lengths
748    r.expect('JSON.ARRLEN', 'test', '.bool').raiseError().contains("not an array")
749    r.expect('JSON.STRLEN', 'test', '.none').raiseError().contains("expected string but found null")
750    r.expect('JSON.OBJLEN', 'test', '.int').raiseError().contains("expected object but found integer")
751    r.expect('JSON.STRLEN', 'test', '.num').raiseError().contains("expected string but found number")
752
753    # test a non existing key
754    r.expect('JSON.ARRLEN', 'test', '.foo').raiseError().contains("does not exist")
755
756    # test an out of bounds index
757    r.expect('JSON.ARRLEN', 'test', '.arr[999]').raiseError().contains("does not exist")
758
759    # test an infinite index
760    r.expect('JSON.ARRLEN', 'test', '.arr[-inf]').raiseError().contains("path error")
761    r.expect('JSON.ARRLEN', 'test', '.arr[4294967295]').raiseError().contains("does not exist")
762
763def testObjKeysCommand(env):
764    """Test JSON.OBJKEYS command"""
765    r = env
766
767    r.expect('JSON.SET', 'test', '.', json.dumps(docs['types'])).ok()
768    data = r.execute_command('JSON.OBJKEYS', 'test', '.')
769    r.assertEqual(len(data), len(docs['types']))
770    for k in data:
771        r.assertTrue(k in docs['types'], message=k)
772
773    # test a wrong type
774    r.expect('JSON.OBJKEYS', 'test', '.null').raiseError()
775
776def testNumIncrCommand(env):
777    """Test JSON.NUMINCRBY command"""
778    r = env
779
780    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{ "foo": 0, "bar": "baz" }'))
781    r.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 1))
782    r.assertEqual('1', r.execute_command('JSON.GET', 'test', '.foo'))
783    r.assertEqual('3', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 2))
784    r.assertEqual('3.5', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', .5))
785
786    # test a wrong type
787    r.expect('JSON.NUMINCRBY', 'test', '.bar', 1).raiseError()
788
789    # test a missing path
790    r.expect('JSON.NUMINCRBY', 'test', '.fuzz', 1).raiseError()
791
792    # test issue #9
793    r.assertOk(r.execute_command('JSON.SET', 'num', '.', '0'))
794    r.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1))
795    r.assertEqual('2.5', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1.5))
796
797    # test issue 55
798    r.assertOk(r.execute_command('JSON.SET', 'foo', '.', '{"foo":0,"bar":42}'))
799    # Get the document once
800    r.execute_command('JSON.GET', 'foo', '.')
801    r.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'foo', 'foo', 1))
802    r.assertEqual('84', r.execute_command('JSON.NUMMULTBY', 'foo', 'bar', 2))
803    res = json.loads(r.execute_command('JSON.GET', 'foo', '.'))
804    r.assertEqual(1, res['foo'])
805    r.assertEqual(84, res['bar'])
806
807
808def testStrCommands(env):
809    """Test JSON.STRAPPEND and JSON.STRLEN commands"""
810    r = env
811
812    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '"foo"'))
813    r.assertEqual('string', r.execute_command('JSON.TYPE', 'test', '.'))
814    r.assertEqual(3, r.execute_command('JSON.STRLEN', 'test', '.'))
815    r.assertEqual(6, r.execute_command('JSON.STRAPPEND', 'test', '.', '"bar"'))
816    r.assertEqual('"foobar"', r.execute_command('JSON.GET', 'test', '.'))
817
818def testRespCommand(env):
819    """Test JSON.RESP command"""
820    r = env
821
822    r.assertOk(r.execute_command('JSON.SET', 'test', '.', 'null'))
823#   r.assertIsNone(r.execute_command('JSON.RESP', 'test'))
824#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', 'true'))
825#   r.assertEquals('true', r.execute_command('JSON.RESP', 'test'))
826#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', 42))
827#   r.assertEquals(42, r.execute_command('JSON.RESP', 'test'))
828#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', 2.5))
829#   r.assertEquals('2.5', r.execute_command('JSON.RESP', 'test'))
830#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', '"foo"'))
831#   r.assertEquals('foo', r.execute_command('JSON.RESP', 'test'))
832#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{"foo":"bar"}'))
833#   resp = r.execute_command('JSON.RESP', 'test')
834#   r.assertEqual(2, len(resp))
835#   r.assertEqual('{', resp[0])
836#   r.assertEqual(2, len(resp[1]))
837#   r.assertEqual('foo', resp[1][0])
838#   r.assertEqual('bar', resp[1][1])
839#   r.assertOk(r.execute_command('JSON.SET', 'test', '.', '[1,2]'))
840#   resp = r.execute_command('JSON.RESP', 'test')
841#   r.assertEqual(3, len(resp))
842#   r.assertEqual('[', resp[0])
843#   r.assertEqual(1, resp[1])
844#   r.assertEqual(2, resp[2])
845
846# def testAllJSONCaseFiles(env):
847#     """Test using all JSON test case files"""
848#     r.maxDiff = None
849#     with r.redis() as r:
850#         r.client_setname(r._testMethodName)
851#         r.flushdb()
852
853#         for jsonfile in os.listdir(JSON_PATH):
854#             if jsonfile.endswith('.json'):
855#                 path = '{}/{}'.format(JSON_PATH, jsonfile)
856#                 with open(path) as f:
857#                     value = f.read()
858#                     if jsonfile.startswith('pass-'):
859#                         r.assertOk(r.execute_command('JSON.SET', jsonfile, '.', value), path)
860#                     elif jsonfile.startswith('fail-'):
861#                         r.expect('JSON.SET', jsonfile, '.', value).raiseError()
862#                         assertNotExists(r, jsonfile, path)
863
864def testSetGetComparePassJSONCaseFiles(env):
865    """Test setting, getting, saving and loading passable JSON test case files"""
866    r = env
867
868    for jsonfile in os.listdir(JSON_PATH):
869        r.maxDiff = None
870        if jsonfile.startswith('pass-') and jsonfile.endswith('.json') and jsonfile not in json_ignore:
871            path = '{}/{}'.format(JSON_PATH, jsonfile)
872            r.flush()
873            with open(path) as f:
874                value = f.read()
875                r.expect('JSON.SET', jsonfile, '.', value).ok()
876                d1 = json.loads(value)
877                for _ in r.retry_with_rdb_reload():
878                    r.assertExists(jsonfile)
879                    raw = r.execute_command('JSON.GET', jsonfile)
880                    d2 = json.loads(raw)
881                    r.assertEqual(d1, d2, message=path)
882
883def testIssue_13(env):
884    """https://github.com/RedisJSON/RedisJSON/issues/13"""
885    r = env
886
887    r.assertOk(r.execute_command('JSON.SET', 'test', '.', json.dumps(docs['simple'])))
888    # This shouldn't crash Redis
889    r.execute_command('JSON.GET', 'test', 'foo', 'foo')
890
891def testIssue_74(env):
892    """https://github.com/RedisJSON/RedisJSON2/issues/74"""
893    r = env
894
895    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '{}'))
896    # This shouldn't crash Redis
897    r.expect('JSON.SET', 'test', '$a', '12').raiseError()
898
899def testDoubleParse(env):
900    r = env
901    r.cmd('JSON.SET', 'dblNum', '.', '[1512060373.222988]')
902    res = r.cmd('JSON.GET', 'dblNum', '[0]')
903    r.assertEqual(1512060373.222988, float(res))
904    r.assertEqual('1512060373.222988', res)
905
906def testIssue_80(env):
907    """https://github.com/RedisJSON/RedisJSON2/issues/80"""
908    r = env
909    r.assertOk(r.execute_command('JSON.SET', 'test', '.', '[{"code":"1"}, {"code":"2"}]'))
910    r.execute_command('JSON.GET', 'test', '.[?(@.code=="2")]')
911
912    # This shouldn't crash Redis
913    r.execute_command('JSON.GET', 'test', '$.[?(@.code=="2")]')
914
915
916def testMultiPathResults(env):
917    env.expect("JSON.SET", "k", '$', '[1,2,3]').ok()
918    env.expect("JSON.GET", "k", '$[*]').equal('[1,2,3]')
919    env.expect("JSON.SET", "k", '$', '{"a":[1,2,3],"b":["c","d","e"],"c":"k"}').ok()
920    env.expect("JSON.GET", "k", '$.*[0,2]').equal('[1,3,"c","e"]')
921
922    # make sure legacy json path returns single result
923    env.expect("JSON.GET", "k", '.*[0,2]').equal('1')
924
925# class CacheTestCase(BaseReJSONTest):
926#     @property
927#     def module_args(env):
928#         return ['CACHE', 'ON']
929#
930#     def testLruCache(self):
931#         def cacheItems():
932#             return getCacheInfo(r)['items']
933#         def cacheBytes():
934#             return getCacheInfo(r)['bytes']
935#
936#         r.cmd('JSON.SET', 'myDoc', '.', json.dumps({
937#             'foo': 'fooValue',
938#             'bar': 'barValue',
939#             'baz': 'bazValue',
940#             'key\\': 'escapedKey'
941#         }))
942#
943#         res = r.cmd('JSON.GET', 'myDoc', 'foo')
944#         r.assertEqual(1, cacheItems())
945#         r.assertEqual('"fooValue"', res)
946#         r.assertEqual('"fooValue"', r.cmd('JSON.GET', 'myDoc', 'foo'))
947#         r.assertEqual('"fooValue"', r.cmd('JSON.GET', 'myDoc', '.foo'))
948#         # Get it again - item count should be the same
949#         r.cmd('JSON.GET', 'myDoc', 'foo')
950#         r.assertEqual(1, cacheItems())
951#
952#         res = r.cmd('JSON.GET', 'myDoc', '.')
953#         # print repr(json.loads(res))
954#         r.assertEqual({u'bar': u'barValue', u'foo': u'fooValue', u'baz': u'bazValue', u'key\\': u'escapedKey'},
955#                          json.loads(res))
956#
957#         # Try to issue multiple gets
958#         r.cmd('JSON.GET', 'myDoc', '.foo')
959#         r.cmd('JSON.GET', 'myDoc', 'foo')
960#         r.cmd('JSON.GET', 'myDoc', '.bar')
961#         r.cmd('JSON.GET', 'myDoc', 'bar')
962#
963#         res = r.cmd('JSON.GET', 'myDoc', '.foo', 'foo', '.bar', 'bar', '["key\\"]')
964#         # print repr(json.loads(res))
965#         r.assertEqual({u'.foo': u'fooValue', u'foo': u'fooValue', u'bar': u'barValue', u'.bar': u'barValue', u'["key\\"]': u'escapedKey'}, json.loads(res))
966#
967#         r.cmd('JSON.DEL', 'myDoc', '.')
968#         r.assertEqual(0, cacheItems())
969#         r.assertEqual(0, cacheBytes())
970#
971#         # Try with an array document
972#         r.cmd('JSON.SET', 'arr', '.', '[{}, 1,2,3,4]')
973#         r.assertEqual('{}', r.cmd('JSON.GET', 'arr', '[0]'))
974#         r.assertEqual(1, cacheItems())
975#         r.assertEqual('{}', r.cmd('JSON.GET', 'arr', '[0]'))
976#         r.assertEqual(1, cacheItems())
977#         r.assertEqual('{}', r.cmd('JSON.GET', 'arr', '[0]'))
978#
979#         r.assertEqual('[{},1,2,3,4]', r.cmd('JSON.GET', 'arr', '.'))
980#         r.assertEqual(2, cacheItems())
981#
982#         r.cmd('JSON.SET', 'arr', '[0].key', 'null')
983#         r.assertEqual(0, cacheItems())
984#
985#         r.assertEqual('null', r.cmd('JSON.GET', 'arr', '[0].key'))
986#         # NULL is still not cached!
987#         r.assertEqual(0, cacheItems())
988#
989#         # Try with a document that contains top level object with an array child
990#         r.cmd('JSON.DEL', 'arr', '.')
991#         r.cmd('JSON.SET', 'mixed', '.', '{"arr":[{},\"Hello\",2,3,null]}')
992#         r.assertEqual("\"Hello\"", r.cmd('JSON.GET', 'mixed', '.arr[1]'))
993#         r.assertEqual(1, cacheItems())
994#
995#         r.cmd('JSON.ARRAPPEND', 'mixed', 'arr', '42')
996#         r.assertEqual(0, cacheItems())
997#         r.assertEqual("\"Hello\"", r.cmd('JSON.GET', 'mixed', 'arr[1]'))
998#
999#         # Test cache eviction
1000#         r.cmd('json._cacheinit', 4096, 20, 0)
1001#         keys = ['json_{}'.format(x) for x in range(10)]
1002#         paths = ['path_{}'.format(x) for x in xrange(100)]
1003#         doc = json.dumps({ p: "some string" for p in paths})
1004#
1005#         # 100k different path/key combinations
1006#         for k in keys:
1007#             r.cmd('JSON.SET', k, '.', doc)
1008#
1009#         # Now get 'em back all
1010#         for k in keys:
1011#             for p in paths:
1012#                 r.cmd('JSON.GET', k, p)
1013#         r.assertEqual(20, cacheItems())
1014#
1015#         r.cmd('json._cacheinit')
1016
1017# class NoCacheTestCase(BaseReJSONTest):
1018#     def testNoCache(self):
1019#         def cacheItems():
1020#             return getCacheInfo(r)['items']
1021#         def cacheBytes():
1022#             return getCacheInfo(r)['bytes']
1023#
1024#         r.cmd('JSON.SET', 'myDoc', '.', json.dumps({
1025#             'foo': 'fooValue',
1026#             'bar': 'barValue',
1027#             'baz': 'bazValue',
1028#             'key\\': 'escapedKey'
1029#         }))
1030#
1031#         res = r.cmd('JSON.GET', 'myDoc', 'foo')
1032#         r.assertEqual(0, cacheItems())
1033