Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nineteendo committed Jul 20, 2024
1 parent 60b8499 commit 29a3d08
Showing 1 changed file with 208 additions and 42 deletions.
250 changes: 208 additions & 42 deletions src/jsonyx/test_jsonyx/test_loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

__all__: list[str] = []

from decimal import Decimal
from math import inf, isnan, nan
from typing import TYPE_CHECKING

import pytest
from jsonyx import NAN_AND_INFINITY, TRAILING_COMMA
from jsonyx import (
COMMENTS, DUPLICATE_KEYS, MISSING_COMMAS, NAN_AND_INFINITY, TRAILING_COMMA,
)
# pylint: disable-next=W0611
from jsonyx.test_jsonyx import get_json # type: ignore # noqa: F401
from typing_extensions import Any # type: ignore
Expand All @@ -18,12 +21,12 @@


def _check_syntax_err(
exc_info: pytest.ExceptionInfo[Any], msg: str, lineno: int, colno: int,
exc_info: pytest.ExceptionInfo[Any], msg: str, colno: int,
end_colno: int = -1,
) -> None:
exc: Any = exc_info.value
assert exc.msg == msg
assert exc.lineno == lineno
assert exc.lineno == 1
assert exc.colno == colno
if end_colno == -1:
assert exc.end_colno == colno + 1
Expand All @@ -36,7 +39,7 @@ def test_empty(json: ModuleType) -> None:
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads("")

_check_syntax_err(exc_info, "Expecting value", 1, 1)
_check_syntax_err(exc_info, "Expecting value", 1)


@pytest.mark.parametrize(("string", "expected"), [
Expand All @@ -54,11 +57,12 @@ def test_keywords(json: ModuleType, string: str, expected: Any) -> None:
("Infinity", inf),
("-Infinity", -inf),
])
def test_nan_and_infinity_allowed(
json: ModuleType, string: str, expected: Any,
) -> None:
"""Test NaN and infinity if allowed."""
def test_nan_and_infinity(json: ModuleType, string: str, expected: Any) -> (
None
):
"""Test NaN and infinity."""
obj: Any = json.loads(string, allow=NAN_AND_INFINITY)
assert isinstance(obj, float)
if isnan(expected):
assert isnan(obj)
else:
Expand All @@ -71,9 +75,7 @@ def test_nan_and_infinity_not_allowed(json: ModuleType, string: str) -> None:
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(
exc_info, f"{string} is not allowed", 1, 1, len(string) + 1,
)
_check_syntax_err(exc_info, f"{string} is not allowed", 1, len(string) + 1)


@pytest.mark.parametrize(("string", "expected"), {
Expand Down Expand Up @@ -146,13 +148,26 @@ def test_number(json: ModuleType, string: str, expected: Any) -> None:
assert obj == expected


@pytest.mark.parametrize(("string", "expected"), [
("1e400", Decimal("1E+400")),
("-1e400", Decimal("-1E+400")),
])
def test_big_number_decimal(json: ModuleType, string: str, expected: Any) -> (
None
):
"""Test big JSON number with decimal."""
assert json.loads(string, use_decimal=True) == expected


@pytest.mark.parametrize("string", ["1e400", "-1e400"])
def test_big_number(json: ModuleType, string: str) -> None:
"""Test big JSON number."""
def test_big_number_float(json: ModuleType, string: str) -> None:
"""Test big JSON number with float."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, "Number is too large", 1, 1, len(string) + 1)
_check_syntax_err(
exc_info, "Big numbers require decimal", 1, len(string) + 1,
)


@pytest.mark.parametrize(("string", "expected"), [
Expand All @@ -161,13 +176,13 @@ def test_big_number(json: ModuleType, string: str) -> None:
# UTF-8
('"$"', "$"),
('"\u00a3"', "\u00a3"),
('"\u00a3"', "\xa3"),
('"\u0418"', "\u0418"),
('"\u0939"', "\u0939"),
('"\u20ac"', "\u20ac"),
('"\ud55c"', "\ud55c"),
('"\U00010348"', "\U00010348"),
('"\U001096B3"', "\U001096B3"),
('"\U001096b3"', "\U001096b3"),
# Backslash escapes
(r'"\""', '"'),
Expand All @@ -181,14 +196,14 @@ def test_big_number(json: ModuleType, string: str) -> None:
# Unicode escape sequences
(r'"\u0024"', "$"),
(r'"\u00a3"', "\u00a3"),
(r'"\u00a3"', "\xa3"),
(r'"\u0418"', "\u0418"),
(r'"\u0939"', "\u0939"),
(r'"\u20ac"', "\u20ac"),
(r'"\ud55c"', "\ud55c"),
(r'"\ud800"', "\ud800"),
(r'"\ud800\udf48"', "\U00010348"),
(r'"\udbe5\udeb3"', "\U001096B3"),
(r'"\udbe5\udeb3"', "\U001096b3"),
# Multiple characters
('"foo"', "foo"),
Expand All @@ -207,10 +222,10 @@ def test_string(json: ModuleType, string: str, expected: Any) -> None:
('"\\', "Expecting escaped character", 3, -1),
('"\\\n', "Expecting escaped character", 3, -1),
(r'"\a"', "Invalid backslash escape", 2, 4),
(r'"\u', "Expecting 4 hex digits", 4, 8),
(r'"\uXXXX"', "Expecting 4 hex digits", 4, 8),
(r'"\ud800\u', "Expecting 4 hex digits", 10, 14),
(r'"\ud800\uXXXX"', "Expecting 4 hex digits", 10, 14),
(r'"\u"', "Expecting 4 hex digits", 4, 8),
(r'"\u0xff"', "Expecting 4 hex digits", 4, 8),
(r'"\ud800\u"', "Expecting 4 hex digits", 10, 14),
(r'"\ud800\u0xff"', "Expecting 4 hex digits", 10, 14),
])
def test_invalid_string(
json: ModuleType, string: str, msg: str, colno: int, end_colno: int,
Expand All @@ -219,7 +234,7 @@ def test_invalid_string(
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, msg, 1, colno, end_colno)
_check_syntax_err(exc_info, msg, colno, end_colno)


@pytest.mark.parametrize(("string", "expected"), [
Expand All @@ -229,6 +244,7 @@ def test_invalid_string(
# One value
('[""]', [""]),
("[0]", [0]),
("[0.0]", [0.0]),
("[{}]", [{}]),
("[[]]", [[]]),
("[true]", [True]),
Expand All @@ -243,46 +259,196 @@ def test_array(json: ModuleType, string: str, expected: Any) -> None:
assert json.loads(string) == expected


@pytest.mark.parametrize(("string", "msg", "colno"), [
("[1-2-3]", "Expecting comma", 3),
("[1 2 3]", "Missing comma's are not allowed", 3),
("[0,]", "Trailing comma is not allowed", 3),
])
def test_invalid_array(
json: ModuleType, string: str, msg: str, colno: int,
) -> None:
"""Test invalid JSON array."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, msg, colno)


@pytest.mark.parametrize(("string", "expected"), [
# In empty array
("[/**/]", []),
# Before first element
("[/**/1, 2, 3]", [1, 2, 3]),
# Before comma's
("[1/**/, 2/**/, 3]", [1, 2, 3]),
# After comma's
("[1,/**/2,/**/3]", [1, 2, 3]),
# After last element
("[1, 2, 3/**/]", [1, 2, 3]),
])
def test_array_comments(json: ModuleType, string: str, expected: Any) -> None:
"""Test comments in JSON array."""
assert json.loads(string, allow=COMMENTS) == expected


@pytest.mark.parametrize(("string", "expected"), [
# Empty object
("{}", {}),
# TODO(Nice Zombies): add more tests
])
# One value
('{"k": ""}', {"k": ""}),
('{"k": 0}', {"k": 0}),
('{"k": 0.0}', {"k": 0.0}),
('{"k": {}}', {"k": {}}),
('{"k": []}', {"k": []}),
('{"k": true}', {"k": True}),
('{"k": false}', {"k": False}),
('{"k": null}', {"k": None}),
# Multiple values
('{"k1": 0, "k2": 0, "k3": 0}', {"k1": 0, "k2": 0, "k3": 0}),
]) # type: ignore
def test_object(json: ModuleType, string: str, expected: Any) -> None:
"""Test JSON object."""
assert json.loads(string) == expected


@pytest.mark.parametrize(("string", "msg", "colno", "end_colno"), [
("{0: 0}", "Expecting string", 2, -1),
('{"k": 1, "k": 2, "k": 3}', "Duplicate keys are not allowed", 10, 13),
('{"k"}', "Expecting colon", 5, -1),
('{"k1": 0"k2": 0"k3": 0}', "Expecting comma", 9, -1),
('{"k1": 0 "k2": 0 "k3": 0}', "Missing comma's are not allowed", 9, -1),
('{"k": 1, 2}', "Expecting string", 10, -1),
('{"k": 0,}', "Trailing comma is not allowed", 8, -1),
])
def test_invalid_object(
json: ModuleType, string: str, msg: str, colno: int, end_colno: int,
) -> None:
"""Test invalid JSON object."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, msg, colno, end_colno)


def test_duplicate_keys(json: ModuleType) -> None:
"""Test duplicate keys."""
obj: dict[str, int] = json.loads(
'{"k": 1, "k": 2, "k": 3}', allow=DUPLICATE_KEYS,
)
assert list(map(str, obj.keys())) == ["k", "k", "k"]
assert list(obj.values()) == [1, 2, 3]


@pytest.mark.parametrize(("string", "expected"), [
# In empty object
("{/**/}", {}),
# Before first element
('{"k1": 0, "k2": 0, "k3": 0}', {"k1": 0, "k2": 0, "k3": 0}),
# Before colon
('{"k1"/**/: 0, "k2"/**/: 0, "k3"/**/: 0}', {"k1": 0, "k2": 0, "k3": 0}),
# After colon
('{"k1":/**/0, "k2":/**/0, "k3":/**/0}', {"k1": 0, "k2": 0, "k3": 0}),
# Before comma
('{"k1": 0/**/, "k2": 0/**/, "k3": 0}', {"k1": 0, "k2": 0, "k3": 0}),
# After comma
('{"k1": 0,/**/"k2": 0,/**/"k3": 0}', {"k1": 0, "k2": 0, "k3": 0}),
# After last element
('{"k1": 0, "k2": 0, "k3": 0/**/}', {"k1": 0, "k2": 0, "k3": 0}),
])
def test_object_comments(json: ModuleType, string: str, expected: Any) -> None:
"""Test comments in JSON object."""
assert json.loads(string, allow=COMMENTS) == expected


@pytest.mark.parametrize(("string", "expected"), [
("[1 2 3]", [1, 2, 3]),
('{"k1": 0 "k2": 0 "k3": 0}', {"k1": 0, "k2": 0, "k3": 0}),
])
def test_missing_commas(json: ModuleType, string: str, expected: Any) -> None:
"""Test missing comma's."""
assert json.loads(string, allow=MISSING_COMMAS) == expected


@pytest.mark.parametrize(("string", "expected"), [
("[0,]", [0]),
('{"k": 0,}', {"k": 0}),
])
def test_trailing_comma_allowed(
json: ModuleType, string: str, expected: Any,
) -> None:
"""Test trailing comma if allowed."""
def test_trailing_comma(json: ModuleType, string: str, expected: Any) -> None:
"""Test trailing comma."""
assert json.loads(string, allow=TRAILING_COMMA) == expected


@pytest.mark.parametrize(("string", "colno"), [
("[0,]", 3),
('{"k": 0,}', 8),
])
def test_trailing_comma_not_allowed(
json: ModuleType, string: str, colno: int,
) -> None:
"""Test trailing comma if not allowed."""
@pytest.mark.parametrize("string", ["-", "foo"])
def test_invalid_value(json: ModuleType, string: str) -> None:
"""Test invalid JSON value."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, "Trailing comma is not allowed", 1, colno)
_check_syntax_err(exc_info, "Expecting value", 1)


@pytest.mark.parametrize("string", ["-", "foo"])
def test_invalid_value(json: ModuleType, string: str) -> None:
"""Test invalid JSON value."""
@pytest.mark.parametrize("string", [
# Before value
"/**/0",
# After value
"0/**/",
])
def test_value_comments(json: ModuleType, string: str) -> None:
"""Test comments around JSON value."""
assert json.loads(string, allow=COMMENTS) == 0


@pytest.mark.parametrize("string", [
# Single comments
"0 // line comment",
"0 /* block comment */",
# Multiple comments
"0 // comment 1\n//comment 2\n//comment 3",
"0 /* comment 1 */ /* comment 2 */ /* comment 3 */",
])
def test_comments(json: ModuleType, string: str) -> None:
"""Test comments."""
assert json.loads(string, allow=COMMENTS) == 0


def test_invalid_comment(json: ModuleType) -> None:
"""Test invalid comment."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads("0 /* unterminated comment", allow=COMMENTS)

_check_syntax_err(exc_info, "Unterminated comment", 3, 26)


@pytest.mark.parametrize("string", [
"0 // line comment",
"0 /* block comment */",
"0 /* unterminated comment",
])
def test_comments_not_allowed(json: ModuleType, string: str) -> None:
"""Test comments if not allowed."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads(string)

_check_syntax_err(exc_info, "Expecting value", 1, 1)
_check_syntax_err(exc_info, "Comments are not allowed", 3, len(string) + 1)


def test_end_of_file(json: ModuleType) -> None:
"""Test end of file."""
with pytest.raises(json.JSONSyntaxError) as exc_info:
json.loads("1 2 3")

_check_syntax_err(exc_info, "Expecting end of file", 3)

0 comments on commit 29a3d08

Please sign in to comment.