Skip to content
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pytest
flake8
coverage
pytest-cov
pytest-randomly
15 changes: 15 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pytest


@pytest.fixture(autouse=True)
def disable_auto_id_field(monkeypatch):
monkeypatch.setattr("jsonpath_ng.jsonpath.auto_id_field", None)


@pytest.fixture()
def auto_id_field(monkeypatch, disable_auto_id_field):
"""Enable `jsonpath_ng.jsonpath.auto_id_field`."""

field_name = "id"
monkeypatch.setattr("jsonpath_ng.jsonpath.auto_id_field", field_name)
return field_name
35 changes: 35 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
def assert_value_equality(results, expected_values):
"""Assert equality between two objects.

*results* must be a list of results as returned by `.find()` methods.

If *expected_values* is a list, then value equality and ordering will be checked.
If *expected_values* is a set, value equality and container length will be checked.
Otherwise, the value of the results will be compared to the expected values.
"""

left_values = [result.value for result in results]
if isinstance(expected_values, list):
assert left_values == expected_values
elif isinstance(expected_values, set):
assert len(left_values) == len(expected_values)
assert set(left_values) == expected_values
else:
assert results[0].value == expected_values


def assert_full_path_equality(results, expected_full_paths):
"""Assert equality between two objects.

*results* must be a list or set of results as returned by `.find()` methods.

If *expected_full_paths* is a list, then path equality and ordering will be checked.
If *expected_full_paths* is a set, then path equality and length will be checked.
"""

full_paths = [str(result.full_path) for result in results]
if isinstance(expected_full_paths, list):
assert full_paths == expected_full_paths, full_paths
else: # isinstance(expected_full_paths, set):
assert len(full_paths) == len(expected_full_paths)
assert set(full_paths) == expected_full_paths
125 changes: 64 additions & 61 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,67 @@
import pytest

from jsonpath_ng.ext.filter import Filter, Expression
from jsonpath_ng.ext import parse
from jsonpath_ng.jsonpath import *


@pytest.mark.parametrize('string, parsed', [
# The authors of all books in the store
("$.store.book[*].author",
Child(Child(Child(Child(Root(), Fields('store')), Fields('book')),
Slice()), Fields('author'))),

# All authors
("$..author", Descendants(Root(), Fields('author'))),

# All things in the store
("$.store.*", Child(Child(Root(), Fields('store')), Fields('*'))),

# The price of everything in the store
("$.store..price",
Descendants(Child(Root(), Fields('store')), Fields('price'))),

# The third book
("$..book[2]",
Child(Descendants(Root(), Fields('book')),Index(2))),

# The last book in order
# ("$..book[(@.length-1)]", # Not implemented
# Child(Descendants(Root(), Fields('book')), Slice(start=-1))),
("$..book[-1:]",
Child(Descendants(Root(), Fields('book')), Slice(start=-1))),

# The first two books
# ("$..book[0,1]", # Not implemented
# Child(Descendants(Root(), Fields('book')), Slice(end=2))),
("$..book[:2]",
Child(Descendants(Root(), Fields('book')), Slice(end=2))),

# Filter all books with ISBN number
("$..book[?(@.isbn)]",
Child(Descendants(Root(), Fields('book')),
Filter([Expression(Child(This(), Fields('isbn')), None, None)]))),

# Filter all books cheaper than 10
("$..book[?(@.price<10)]",
Child(Descendants(Root(), Fields('book')),
Filter([Expression(Child(This(), Fields('price')), '<', 10)]))),

# All members of JSON structure
("$..*", Descendants(Root(), Fields('*'))),
])
from jsonpath_ng.ext.filter import Expression, Filter
from jsonpath_ng.jsonpath import Child, Descendants, Fields, Index, Root, Slice, This


@pytest.mark.parametrize(
"string, parsed",
[
# The authors of all books in the store
(
"$.store.book[*].author",
Child(
Child(Child(Child(Root(), Fields("store")), Fields("book")), Slice()),
Fields("author"),
),
),
#
# All authors
("$..author", Descendants(Root(), Fields("author"))),
#
# All things in the store
("$.store.*", Child(Child(Root(), Fields("store")), Fields("*"))),
#
# The price of everything in the store
(
"$.store..price",
Descendants(Child(Root(), Fields("store")), Fields("price")),
),
#
# The third book
("$..book[2]", Child(Descendants(Root(), Fields("book")), Index(2))),
#
# The last book in order
# "$..book[(@.length-1)]" # Not implemented
("$..book[-1:]", Child(Descendants(Root(), Fields("book")), Slice(start=-1))),
#
# The first two books
# "$..book[0,1]" # Not implemented
("$..book[:2]", Child(Descendants(Root(), Fields("book")), Slice(end=2))),
#
# Filter all books with an ISBN
(
"$..book[?(@.isbn)]",
Child(
Descendants(Root(), Fields("book")),
Filter([Expression(Child(This(), Fields("isbn")), None, None)]),
),
),
#
# Filter all books cheaper than 10
(
"$..book[?(@.price<10)]",
Child(
Descendants(Root(), Fields("book")),
Filter([Expression(Child(This(), Fields("price")), "<", 10)]),
),
),
#
# All members of JSON structure
("$..*", Descendants(Root(), Fields("*"))),
],
)
def test_goessner_examples(string, parsed):
"""
Test Stefan Goessner's `examples`_
Expand All @@ -59,16 +71,7 @@ def test_goessner_examples(string, parsed):
assert parse(string, debug=True) == parsed


@pytest.mark.parametrize('string, parsed', [
# Navigate objects
("$.store.book[0].title",
Child(Child(Child(Child(Root(), Fields('store')), Fields('book')),
Index(0)), Fields('title'))),
def test_attribute_and_dict_syntax():
"""Verify that attribute and dict syntax result in identical parse trees."""

# Navigate dictionaries
("$['store']['book'][0]['title']",
Child(Child(Child(Child(Root(), Fields('store')), Fields('book')),
Index(0)), Fields('title'))),
])
def test_obj_v_dict(string, parsed):
assert parse(string, debug=True) == parsed
assert parse("$.store.book[0].title") == parse("$['store']['book'][0]['title']")
31 changes: 12 additions & 19 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,32 @@
import pytest

from jsonpath_ng import parse as rw_parse
from jsonpath_ng.exceptions import JSONPathError, JsonPathParserError
from jsonpath_ng import parse as base_parse
from jsonpath_ng.exceptions import JsonPathParserError
from jsonpath_ng.ext import parse as ext_parse


def test_rw_exception_class():
with pytest.raises(JSONPathError):
rw_parse('foo.bar.`grandparent`.baz')


@pytest.mark.parametrize(
"path",
(
'foo[*.bar.baz',
'foo.bar.`grandparent`.baz',
# error at the end of string
'foo[*',
"foo[*.bar.baz",
"foo.bar.`grandparent`.baz",
"foo[*",
# `len` extension not available in the base parser
'foo.bar.`len`',
)
"foo.bar.`len`",
),
)
def test_rw_exception_subclass(path):
with pytest.raises(JsonPathParserError):
rw_parse(path)
base_parse(path)


@pytest.mark.parametrize(
"path",
(
'foo[*.bar.baz',
'foo.bar.`grandparent`.baz',
# error at the end of string
'foo[*',
)
"foo[*.bar.baz",
"foo.bar.`grandparent`.baz",
"foo[*",
),
)
def test_ext_exception_subclass(path):
with pytest.raises(JsonPathParserError):
Expand Down
Loading