File: test_basic_parse.py

package info (click to toggle)
python-ijson 3.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 668 kB
  • sloc: python: 2,687; ansic: 1,776; sh: 4; makefile: 3
file content (174 lines) | stat: -rw-r--r-- 5,684 bytes parent folder | download
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""Tests for the ijson.basic_parse method"""

import itertools
import threading
from decimal import Decimal

import pytest
from ijson import common

from .test_base import ARRAY_JSON, ARRAY_JSON_EVENTS, INCOMPLETE_JSONS, INCOMPLETE_JSON_TOKENS, INVALID_JSONS, JSON, JSON_EVENTS, SCALAR_JSON, SURROGATE_PAIRS_JSON, STRINGS_JSON


def _raises_json_error(adaptor, json, **kwargs):
    with pytest.raises(common.JSONError):
        adaptor.basic_parse(json, **kwargs)


def _raises_incomplete_json_error(adaptor, json):
    with pytest.raises(common.IncompleteJSONError):
        adaptor.basic_parse(json)


def test_basic_parse(adaptor):
    assert JSON_EVENTS == adaptor.basic_parse(JSON)


def test_basic_parse_threaded(adaptor):
    thread = threading.Thread(target=test_basic_parse, args=(adaptor,))
    thread.start()
    thread.join()


def test_basic_parse_array(adaptor):
    assert ARRAY_JSON_EVENTS == adaptor.basic_parse(ARRAY_JSON)


def test_basic_parse_array_threaded(adaptor):
    thread = threading.Thread(target=test_basic_parse_array, args=(adaptor,))
    thread.start()
    thread.join()


def test_scalar(adaptor):
    assert [('number', 0)] == adaptor.basic_parse(SCALAR_JSON)


def test_strings(adaptor):
    events = adaptor.basic_parse(STRINGS_JSON)
    strings = [value for event, value in events if event == 'string']
    assert ['', '"', '\\', '\\\\', '\b\f\n\r\t'] == strings
    assert ('map_key', 'special\t') in events


def test_surrogate_pairs(adaptor):
    event = adaptor.basic_parse(SURROGATE_PAIRS_JSON)[0]
    parsed_string = event[1]
    assert '💩' == parsed_string


def _get_numbers(adaptor, json, use_float):
    events = adaptor.basic_parse(json, use_float=use_float)
    return [value for event, value in events if event == 'number']


@pytest.mark.parametrize(
    "json, expected_float_type, expected_numbers, use_float",
    (
        (b'[1, 1.0, 1E2]', Decimal, [1, Decimal("1.0"), Decimal("1e2")], False),
        (b'[1, 1.0, 1E2]', float, [1, 1., 100.], True),
        (b'1e400', Decimal, [Decimal('1e400')], False),
        (b'1e-400', Decimal, [Decimal('1e-400')], False),
        (b'1e-400', float, [0], True),
    )
)
def test_numbers(adaptor, json, expected_float_type, expected_numbers, use_float):
    """Check that numbers are correctly parsed"""
    numbers = _get_numbers(adaptor, json, use_float=use_float)
    float_types = set(type(number) for number in numbers)
    float_types -= {int}
    assert 1 == len(float_types)
    assert expected_float_type == next(iter(float_types))
    assert expected_numbers == numbers


def test_32bit_ints(adaptor):
    """Test for 64-bit integers support when using use_float=true"""
    past32bits = 2 ** 32 + 1
    past32bits_as_json = ('%d' % past32bits).encode('utf8')
    if adaptor.backend.capabilities.int64:
        parsed_number = _get_numbers(adaptor, past32bits_as_json, use_float=True)[0]
        assert past32bits == parsed_number
    else:
        _raises_json_error(adaptor, past32bits_as_json, use_float=True)


def test_max_double(adaptor):
    """Check that numbers bigger than MAX_DOUBLE (usually ~1e308) cannot be represented"""
    _raises_json_error(adaptor, b'1e400', use_float=True)


@pytest.mark.parametrize(
    "json", [
        sign + prefix + suffix
        for sign, prefix, suffix in itertools.product(
            (b'', b'-'),
            (b'00', b'01', b'001'),
            (b'', b'.0', b'e0', b'E0')
        )
    ]
)
def test_invalid_leading_zeros(adaptor, json):
    """Check leading zeros are invalid"""
    if not adaptor.backend.capabilities.invalid_leading_zeros_detection:
        return
    _raises_json_error(adaptor, json)


@pytest.mark.parametrize("json", (b'1e', b'0.1e', b'0E'))
def test_incomplete_exponents(adaptor, json):
    """incomplete exponents are invalid JSON"""
    _raises_json_error(adaptor, json)


@pytest.mark.parametrize("json", (b'1.', b'.1'))
def test_incomplete_fractions(adaptor, json):
    """incomplete fractions are invalid JSON"""
    _raises_json_error(adaptor, json)


def test_incomplete(adaptor):
    for json in INCOMPLETE_JSONS:
        _raises_incomplete_json_error(adaptor, json)


def test_incomplete_tokens(adaptor):
    if not adaptor.backend.capabilities.incomplete_json_tokens_detection:
        return
    for json in INCOMPLETE_JSON_TOKENS:
        _raises_incomplete_json_error(adaptor, json)


def test_invalid(adaptor):
    for json in INVALID_JSONS:
        if not adaptor.backend.capabilities.incomplete_json_tokens_detection and json == INVALID_JSON_WITH_DANGLING_JUNK:
            continue
        _raises_json_error(adaptor, json)


def test_comments(adaptor):
    json = b'{"a": 2 /* a comment */}'
    if adaptor.backend.capabilities.c_comments:
        events = adaptor.basic_parse(json, allow_comments=True)
        assert events is not None
    else:
        with pytest.raises(ValueError):
            adaptor.basic_parse(json, allow_comments=True)


def test_multiple_values_raises_if_not_supported(adaptor):
    """Test that setting multiple_values raises if not supported"""
    if not adaptor.backend.capabilities.multiple_values:
        with pytest.raises(ValueError):
            adaptor.basic_parse("", multiple_values=True)


def test_multiple_values(adaptor):
    """Test that multiple_values are supported"""
    multiple_json = JSON + JSON + JSON
    with pytest.raises(common.JSONError):
        adaptor.basic_parse(multiple_json)
    with pytest.raises(common.JSONError):
        adaptor.basic_parse(multiple_json, multiple_values=False)
    result = adaptor.basic_parse(multiple_json, multiple_values=True)
    assert JSON_EVENTS + JSON_EVENTS + JSON_EVENTS == result