Skip to content

Commit b9c08ac

Browse files
kurtmckeemichaelmior
authored andcommitted
De-duplicate the parser test cases
1 parent 2787abb commit b9c08ac

File tree

2 files changed

+33
-248
lines changed

2 files changed

+33
-248
lines changed

tests/test_jsonpath.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import pytest
22

3+
from jsonpath_ng.ext.parser import parse as ext_parse
34
from jsonpath_ng.jsonpath import DatumInContext, Fields, Root, This
45
from jsonpath_ng.lexer import JsonPathLexerError
5-
from jsonpath_ng.parser import parse
6+
from jsonpath_ng.parser import parse as base_parse
67

78
from .helpers import assert_full_path_equality, assert_value_equality
89

@@ -48,6 +49,15 @@ def test_datumincontext_in_context_nested():
4849
assert sequential_calls == nested_calls
4950

5051

52+
parsers = pytest.mark.parametrize(
53+
"parse",
54+
(
55+
pytest.param(base_parse, id="parse=jsonpath_ng.parser.parse"),
56+
pytest.param(ext_parse, id="parse=jsonpath_ng.ext.parser.parse"),
57+
),
58+
)
59+
60+
5161
update_test_cases = (
5262
#
5363
# Fields
@@ -121,7 +131,8 @@ def test_datumincontext_in_context_nested():
121131
"expression, data, update_value, expected_value",
122132
update_test_cases,
123133
)
124-
def test_update(expression, data, update_value, expected_value):
134+
@parsers
135+
def test_update(parse, expression, data, update_value, expected_value):
125136
result = parse(expression).update(data, update_value)
126137
assert result == expected_value
127138

@@ -238,7 +249,8 @@ def test_update(expression, data, update_value, expected_value):
238249
@pytest.mark.parametrize(
239250
"path, data, expected_values, expected_full_paths", find_test_cases
240251
)
241-
def test_find(path, data, expected_values, expected_full_paths):
252+
@parsers
253+
def test_find(parse, path, data, expected_values, expected_full_paths):
242254
results = parse(path).find(data)
243255

244256
# Verify result values and full paths match expectations.
@@ -308,12 +320,14 @@ def test_find(path, data, expected_values, expected_full_paths):
308320

309321

310322
@pytest.mark.parametrize("path, data, expected_values", find_test_cases_with_auto_id)
311-
def test_find_values_auto_id(auto_id_field, path, data, expected_values):
323+
@parsers
324+
def test_find_values_auto_id(auto_id_field, parse, path, data, expected_values):
312325
result = parse(path).find(data)
313326
assert_value_equality(result, expected_values)
314327

315328

316-
def test_find_full_paths_auto_id(auto_id_field):
329+
@parsers
330+
def test_find_full_paths_auto_id(auto_id_field, parse):
317331
results = parse("*").find({"foo": 1, "baz": 2})
318332
assert_full_path_equality(results, {"foo", "baz", "id"})
319333

@@ -326,7 +340,8 @@ def test_find_full_paths_auto_id(auto_id_field):
326340
("m.[0].id", ["1.m.[0]"]),
327341
),
328342
)
329-
def test_nested_index_auto_id(auto_id_field, string, target):
343+
@parsers
344+
def test_nested_index_auto_id(auto_id_field, parse, string, target):
330345
data = {
331346
"id": 1,
332347
"b": {"id": "bid", "name": "bob"},
@@ -338,4 +353,4 @@ def test_nested_index_auto_id(auto_id_field, string, target):
338353

339354
def test_invalid_hyphenation_in_key():
340355
with pytest.raises(JsonPathLexerError):
341-
parse("foo.-baz").find({"foo": {"-baz": 8}})
356+
base_parse("foo.-baz")

tests/test_jsonpath_rw_ext.py

Lines changed: 11 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919
Tests for `jsonpath_ng_ext` module.
2020
"""
2121

22-
import unittest
23-
2422
from jsonpath_ng import jsonpath # For setting the global auto_id_field flag
2523

2624
from jsonpath_ng.ext import parser
25+
from jsonpath_ng.exceptions import JsonPathParserError
26+
27+
import pytest
2728

2829

2930
# Example from https://docs.pytest.org/en/7.1.x/example/parametrize.html#a-quick-port-of-testscenarios
3031
def pytest_generate_tests(metafunc):
32+
if metafunc.cls is None:
33+
return
3134
idlist = []
3235
argvalues = []
3336
for scenario in metafunc.cls.scenarios:
@@ -373,243 +376,10 @@ def test_fields_value(self, string, data, target):
373376
else:
374377
assert target == result[0].value
375378

376-
# NOTE(sileht): copy of tests/test_jsonpath.py
377-
# to ensure we didn't break jsonpath_ng
378-
379-
380-
class TestJsonPath(unittest.TestCase):
381-
"""Tests of the actual jsonpath functionality """
382-
383-
#
384-
# Check that the data value returned is good
385-
#
386-
def check_cases(self, test_cases):
387-
# Note that just manually building an AST would avoid this dep and
388-
# isolate the tests, but that would suck a bit
389-
# Also, we coerce iterables, etc, into the desired target type
390-
391-
for string, data, target in test_cases:
392-
print('parse("%s").find(%s) =?= %s' % (string, data, target))
393-
result = parser.parse(string).find(data)
394-
if isinstance(target, list):
395-
assert [r.value for r in result] == target
396-
elif isinstance(target, set):
397-
assert set([r.value for r in result]) == target
398-
else:
399-
assert result.value == target
400-
401-
def test_fields_value(self):
402-
jsonpath.auto_id_field = None
403-
self.check_cases([('foo', {'foo': 'baz'}, ['baz']),
404-
('foo,baz', {'foo': 1, 'baz': 2}, [1, 2]),
405-
('@foo', {'@foo': 1}, [1]),
406-
('*', {'foo': 1, 'baz': 2}, set([1, 2]))])
407-
408-
jsonpath.auto_id_field = 'id'
409-
self.check_cases([('*', {'foo': 1, 'baz': 2}, set([1, 2, '`this`']))])
410379

411-
def test_root_value(self):
412-
jsonpath.auto_id_field = None
413-
self.check_cases([
414-
('$', {'foo': 'baz'}, [{'foo': 'baz'}]),
415-
('foo.$', {'foo': 'baz'}, [{'foo': 'baz'}]),
416-
('foo.$.foo', {'foo': 'baz'}, ['baz']),
417-
])
418-
419-
def test_this_value(self):
420-
jsonpath.auto_id_field = None
421-
self.check_cases([
422-
('`this`', {'foo': 'baz'}, [{'foo': 'baz'}]),
423-
('foo.`this`', {'foo': 'baz'}, ['baz']),
424-
('foo.`this`.baz', {'foo': {'baz': 3}}, [3]),
425-
])
426-
427-
def test_index_value(self):
428-
self.check_cases([
429-
('[0]', [42], [42]),
430-
('[5]', [42], []),
431-
('[2]', [34, 65, 29, 59], [29])
432-
])
433-
434-
def test_slice_value(self):
435-
self.check_cases([('[*]', [1, 2, 3], [1, 2, 3]),
436-
('[*]', range(1, 4), [1, 2, 3]),
437-
('[1:]', [1, 2, 3, 4], [2, 3, 4]),
438-
('[:2]', [1, 2, 3, 4], [1, 2])])
439-
440-
# Funky slice hacks
441-
self.check_cases([
442-
('[*]', 1, [1]), # This is a funky hack
443-
('[0:]', 1, [1]), # This is a funky hack
444-
('[*]', {'foo': 1}, [{'foo': 1}]), # This is a funky hack
445-
('[*].foo', {'foo': 1}, [1]), # This is a funky hack
446-
])
447-
448-
def test_child_value(self):
449-
self.check_cases([('foo.baz', {'foo': {'baz': 3}}, [3]),
450-
('foo.baz', {'foo': {'baz': [3]}}, [[3]]),
451-
('foo.baz.bizzle', {'foo': {'baz': {'bizzle': 5}}},
452-
[5])])
453-
454-
def test_descendants_value(self):
455-
self.check_cases([
456-
('foo..baz', {'foo': {'baz': 1, 'bing': {'baz': 2}}}, [1, 2]),
457-
('foo..baz', {'foo': [{'baz': 1}, {'baz': 2}]}, [1, 2]),
458-
])
459-
460-
def test_parent_value(self):
461-
self.check_cases([('foo.baz.`parent`', {'foo': {'baz': 3}},
462-
[{'baz': 3}]),
463-
('foo.`parent`.foo.baz.`parent`.baz.bizzle',
464-
{'foo': {'baz': {'bizzle': 5}}}, [5])])
465-
466-
def test_hyphen_key(self):
467-
# NOTE(sileht): hyphen is now a operator
468-
# so to use it has key we must escape it with quote
469-
# self.check_cases([('foo.bar-baz', {'foo': {'bar-baz': 3}}, [3]),
470-
# ('foo.[bar-baz,blah-blah]',
471-
# {'foo': {'bar-baz': 3, 'blah-blah': 5}},
472-
# [3, 5])])
473-
self.check_cases([('foo."bar-baz"', {'foo': {'bar-baz': 3}}, [3]),
474-
('foo.["bar-baz","blah-blah"]',
475-
{'foo': {'bar-baz': 3, 'blah-blah': 5}},
476-
[3, 5])])
477-
# self.assertRaises(lexer.JsonPathLexerError, self.check_cases,
478-
# [('foo.-baz', {'foo': {'-baz': 8}}, [8])])
479-
480-
#
481-
# Check that the paths for the data are correct.
482-
# FIXME: merge these tests with the above, since the inputs are the same
483-
# anyhow
484-
#
485-
def check_paths(self, test_cases):
486-
# Note that just manually building an AST would avoid this dep and
487-
# isolate the tests, but that would suck a bit
488-
# Also, we coerce iterables, etc, into the desired target type
489-
490-
for string, data, target in test_cases:
491-
print('parse("%s").find(%s).paths =?= %s' % (string, data, target))
492-
result = parser.parse(string).find(data)
493-
if isinstance(target, list):
494-
assert [str(r.full_path) for r in result] == target
495-
elif isinstance(target, set):
496-
assert set([str(r.full_path) for r in result]) == target
497-
else:
498-
assert str(result.path) == target
499-
500-
def test_filter_with_filtering(self):
501-
data = {"foos": [{"id": 1, "name": "first"}, {"id": 2, "name": "second"}]}
502-
result = parser.parse('$.foos[?(@.name=="second")]').filter(
503-
lambda _: True, data
504-
)
505-
names = [item["name"] for item in result["foos"]]
506-
assert "second" not in names
507-
508-
def test_fields_paths(self):
509-
jsonpath.auto_id_field = None
510-
self.check_paths([('foo', {'foo': 'baz'}, ['foo']),
511-
('foo,baz', {'foo': 1, 'baz': 2}, ['foo', 'baz']),
512-
('*', {'foo': 1, 'baz': 2}, set(['foo', 'baz']))])
513-
514-
jsonpath.auto_id_field = 'id'
515-
self.check_paths([('*', {'foo': 1, 'baz': 2},
516-
set(['foo', 'baz', 'id']))])
517-
518-
def test_root_paths(self):
519-
jsonpath.auto_id_field = None
520-
self.check_paths([
521-
('$', {'foo': 'baz'}, ['$']),
522-
('foo.$', {'foo': 'baz'}, ['$']),
523-
('foo.$.foo', {'foo': 'baz'}, ['foo']),
524-
])
525-
526-
def test_this_paths(self):
527-
jsonpath.auto_id_field = None
528-
self.check_paths([
529-
('`this`', {'foo': 'baz'}, ['`this`']),
530-
('foo.`this`', {'foo': 'baz'}, ['foo']),
531-
('foo.`this`.baz', {'foo': {'baz': 3}}, ['foo.baz']),
532-
])
533-
534-
def test_index_paths(self):
535-
self.check_paths([('[0]', [42], ['[0]']),
536-
('[2]', [34, 65, 29, 59], ['[2]'])])
537-
538-
def test_slice_paths(self):
539-
self.check_paths([('[*]', [1, 2, 3], ['[0]', '[1]', '[2]']),
540-
('[1:]', [1, 2, 3, 4], ['[1]', '[2]', '[3]'])])
541-
542-
def test_child_paths(self):
543-
self.check_paths([('foo.baz', {'foo': {'baz': 3}}, ['foo.baz']),
544-
('foo.baz', {'foo': {'baz': [3]}}, ['foo.baz']),
545-
('foo.baz.bizzle', {'foo': {'baz': {'bizzle': 5}}},
546-
['foo.baz.bizzle'])])
547-
548-
def test_descendants_paths(self):
549-
self.check_paths([('foo..baz', {'foo': {'baz': 1, 'bing': {'baz': 2}}},
550-
['foo.baz', 'foo.bing.baz'])])
551-
552-
#
553-
# Check the "auto_id_field" feature
554-
#
555-
def test_fields_auto_id(self):
556-
jsonpath.auto_id_field = "id"
557-
self.check_cases([('foo.id', {'foo': 'baz'}, ['foo']),
558-
('foo.id', {'foo': {'id': 'baz'}}, ['baz']),
559-
('foo,baz.id', {'foo': 1, 'baz': 2}, ['foo', 'baz']),
560-
('*.id',
561-
{'foo': {'id': 1},
562-
'baz': 2},
563-
set(['1', 'baz']))])
564-
565-
def test_root_auto_id(self):
566-
jsonpath.auto_id_field = 'id'
567-
self.check_cases([
568-
('$.id', {'foo': 'baz'}, ['$']), # This is a wonky case that is
569-
# not that interesting
570-
('foo.$.id', {'foo': 'baz', 'id': 'bizzle'}, ['bizzle']),
571-
('foo.$.baz.id', {'foo': 4, 'baz': 3}, ['baz']),
572-
])
573-
574-
def test_this_auto_id(self):
575-
jsonpath.auto_id_field = 'id'
576-
self.check_cases([
577-
('id', {'foo': 'baz'}, ['`this`']), # This is, again, a wonky case
578-
# that is not that interesting
579-
('foo.`this`.id', {'foo': 'baz'}, ['foo']),
580-
('foo.`this`.baz.id', {'foo': {'baz': 3}}, ['foo.baz']),
581-
])
582-
583-
def test_index_auto_id(self):
584-
jsonpath.auto_id_field = "id"
585-
self.check_cases([('[0].id', [42], ['[0]']),
586-
('[2].id', [34, 65, 29, 59], ['[2]'])])
587-
588-
def test_slice_auto_id(self):
589-
jsonpath.auto_id_field = "id"
590-
self.check_cases([('[*].id', [1, 2, 3], ['[0]', '[1]', '[2]']),
591-
('[1:].id', [1, 2, 3, 4], ['[1]', '[2]', '[3]'])])
592-
593-
def test_child_auto_id(self):
594-
jsonpath.auto_id_field = "id"
595-
self.check_cases([('foo.baz.id', {'foo': {'baz': 3}}, ['foo.baz']),
596-
('foo.baz.id', {'foo': {'baz': [3]}}, ['foo.baz']),
597-
('foo.baz.id', {'foo': {'id': 'bizzle', 'baz': 3}},
598-
['bizzle.baz']),
599-
('foo.baz.id', {'foo': {'baz': {'id': 'hi'}}},
600-
['foo.hi']),
601-
('foo.baz.bizzle.id',
602-
{'foo': {'baz': {'bizzle': 5}}},
603-
['foo.baz.bizzle'])])
604-
605-
def test_descendants_auto_id(self):
606-
jsonpath.auto_id_field = "id"
607-
self.check_cases([('foo..baz.id',
608-
{'foo': {
609-
'baz': 1,
610-
'bing': {
611-
'baz': 2
612-
}
613-
}},
614-
['foo.baz',
615-
'foo.bing.baz'])])
380+
def test_invalid_hyphenation_in_key():
381+
# This test is almost copied-and-pasted directly from `test_jsonpath.py`.
382+
# However, the parsers generate different exceptions for this syntax error.
383+
# This discrepancy needs to be resolved.
384+
with pytest.raises(JsonPathParserError):
385+
parser.parse("foo.-baz")

0 commit comments

Comments
 (0)