def test_linecol(data, line, col, idx): with pytest.raises(sdjson.JSONDecodeError) as err: sdjson.loads(data) if platform.python_implementation() == "PyPy": match = "Unexpected '!'" else: match = 'Expecting value' if pypy: assert err.value.msg.startswith( match) # Fix for varying messages between PyPy versions else: assert err.value.msg == match assert err.value.pos == idx assert err.value.lineno == line assert err.value.colno == col if pypy: assert re.match( rf'{match}.*: line {line} column {col:d} \(char {idx:d}\)', str(err.value)) else: assert re.match( rf'{match}: line {line} column {col:d} \(char {idx:d}\)', str(err.value))
def test_list(): assert sdjson.dumps(list(BigNum)) == str([SMALL, BIG, HUGE, REALLY_HUGE]) assert sdjson.loads(sdjson.dumps(list(BigNum))) == list(BigNum) assert sdjson.dumps(list(FloatNum)) == str([E, PI, TAU]) assert sdjson.loads(sdjson.dumps(list(FloatNum))) == list(FloatNum) assert sdjson.dumps(list(WierdNum)) == '[Infinity, -Infinity, NaN]' assert sdjson.loads(sdjson.dumps(list(WierdNum)))[:2] == list(WierdNum)[:2] assert isnan(sdjson.loads(sdjson.dumps(list(WierdNum)))[2])
def test_weird_floats() -> None: for enum, expected in zip(WierdNum, ("Infinity", "-Infinity", "NaN")): assert sdjson.dumps(enum) == expected if not isnan(enum): assert float(sdjson.dumps(enum)) == enum assert sdjson.loads(sdjson.dumps(enum)) == enum else: assert isnan(float(sdjson.dumps(enum))) assert isnan(sdjson.loads(sdjson.dumps(enum)))
def test_weird_floats(): for enum, expected in zip(WierdNum, ('Infinity', '-Infinity', 'NaN')): assert sdjson.dumps(enum) == expected if not isnan(enum): assert float(sdjson.dumps(enum)) == enum assert sdjson.loads(sdjson.dumps(enum)) == enum else: assert isnan(float(sdjson.dumps(enum))) assert isnan(sdjson.loads(sdjson.dumps(enum)))
def test_object_pairs_hook_with_unicode() -> None: s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] assert sdjson.loads(s, object_pairs_hook=lambda x: x) == p od = sdjson.loads(s, object_pairs_hook=OrderedDict) assert od == OrderedDict(p) assert type(od) == OrderedDict # the object_pairs_hook takes priority over the object_hook assert sdjson.loads(s, object_pairs_hook=OrderedDict, object_hook=lambda x: None) == OrderedDict(p)
def test_encode_long_neg_conversion(): test_input = -9223372036854775808 output = sd_ujson.encode(test_input) sdjson.loads(output) sd_ujson.decode(output) assert test_input == sdjson.loads(output) assert output == sdjson.dumps(test_input) assert test_input == sd_ujson.decode(output)
def test_parse_pass_2() -> None: # from http://json.org/JSON_checker/test/pass2.json JSON = r""" [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] """ # test in/out equivalence and parsing res = sdjson.loads(JSON) out = sdjson.dumps(res) assert res == sdjson.loads(out)
def test_indent(): h = [ ['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', { 'nifty': 87 }, { 'field': 'yes', 'morefield': False }, ] expect = textwrap.dedent("""\ [ \t[ \t\t"blorpie" \t], \t[ \t\t"whoops" \t], \t[], \t"d-shtaeou", \t"d-nthiouh", \t"i-vhbjkhnth", \t{ \t\t"nifty": 87 \t}, \t{ \t\t"field": "yes", \t\t"morefield": false \t} ]""") d1 = sdjson.dumps(h) d2 = sdjson.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) d3 = sdjson.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) d4 = sdjson.dumps(h, indent=2, sort_keys=True) d5 = sdjson.dumps(h, indent='\t', sort_keys=True) h1 = sdjson.loads(d1) h2 = sdjson.loads(d2) h3 = sdjson.loads(d3) assert h1 == h assert h2 == h assert h3 == h assert d2 == expect.expandtabs(2) assert d3 == expect assert d4 == d2 assert d5 == d3
def test_allow_nan(): for val in (float('inf'), float('-inf'), float('nan')): out = sdjson.dumps([val]) if val == val: # inf assert sdjson.loads(out) == [val] else: # nan res = sdjson.loads(out) assert len(res) == 1 assert res[0] != res[0] with pytest.raises(ValueError): sdjson.dumps([val], allow_nan=False)
def test_failures() -> None: for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: sdjson.loads(doc) continue try: sdjson.loads(doc) except sdjson.JSONDecodeError: pass else: pytest.fail(f"Expected failure for fail{idx}.json: {doc!r}")
def test_failures(): for idx, doc in enumerate(JSONDOCS): idx = idx + 1 if idx in SKIPS: sdjson.loads(doc) continue try: sdjson.loads(doc) except sdjson.JSONDecodeError: pass else: pytest.fail("Expected failure for fail{0}.json: {1!r}".format( idx, doc))
def test_allow_nan() -> None: for val in (float("inf"), float("-inf"), float("nan")): out = sdjson.dumps([val]) if val == val: # inf assert sdjson.loads(out) == [val] else: # nan res = sdjson.loads(out) assert len(res) == 1 assert res[0] != res[0] with pytest.raises( ValueError, match="Out of range float values are not JSON compliant"): sdjson.dumps([val], allow_nan=False)
def test_encode_null_character(): test_input = "31337 \x00 1337" output = sd_ujson.encode(test_input) assert test_input == sdjson.loads(output) assert output == sdjson.dumps(test_input) assert test_input == sd_ujson.decode(output) test_input = "\x00" output = sd_ujson.encode(test_input) assert test_input == sdjson.loads(output) assert output == sdjson.dumps(test_input) assert test_input == sd_ujson.decode(output) assert '" \\u0000\\r\\n "' == sd_ujson.dumps(" \u0000\r\n ")
def test_bytes_decode(): for encoding, bom in [ ('utf-8', codecs.BOM_UTF8), ('utf-16be', codecs.BOM_UTF16_BE), ('utf-16le', codecs.BOM_UTF16_LE), ('utf-32be', codecs.BOM_UTF32_BE), ('utf-32le', codecs.BOM_UTF32_LE), ]: data = ["a\xb5\u20ac\U0001d120"] encoded = sdjson.dumps(data).encode(encoding) assert sdjson.loads(bom + encoded) == data assert sdjson.loads(encoded) == data with pytest.raises(UnicodeDecodeError): sdjson.loads(b'["\x80"]') # RFC-7159 and ECMA-404 extend JSON to allow documents that # consist of only a string, which can present a special case # not covered by the encoding detection patterns specified in # RFC-4627 for utf-16-le (XX 00 XX 00). assert sdjson.loads('"\u2600"'.encode('utf-16-le')) == '\u2600' # Encoding detection for small (<4) bytes objects # is implemented as a special case. RFC-7159 and ECMA-404 # allow single codepoint JSON documents which are only two # bytes in utf-16 encodings w/o BOM. assert sdjson.loads(b'5\x00') == 5 assert sdjson.loads(b'\x007') == 7 assert sdjson.loads(b'57') == 57
def test_parse_pass_3() -> None: # from http://json.org/JSON_checker/test/pass3.json JSON = r""" { "JSON Test Pattern pass3": { "The outermost value": "must be an object or array.", "In this test": "It is an object." } } """ # test in/out equivalence and parsing res = sdjson.loads(JSON) out = sdjson.dumps(res) assert res == sdjson.loads(out)
def test_encode_to_utf8(): test_input = b"\xe6\x97\xa5\xd1\x88" test_input = test_input.decode("utf-8") enc = sd_ujson.encode(test_input, ensure_ascii=False) dec = sd_ujson.decode(enc) assert enc == sdjson.dumps(test_input, ensure_ascii=False) assert dec == sdjson.loads(enc)
def test_sdjson(): d = Device( 1000, "Television", DeviceType.RC, MagicMapping( make="Samsung", smart=True, ports=Counter([Port.HDMI, Port.HDMI, Port.HDMI, Port.VGA]), ), ) expected = """{ "device_id": 1000, "display_name": "Television", "device_type": 1, "configuration": { "make": "Samsung", "smart": true, "ports": { "1": 3, "2": 1 } } }""" assert sdjson.dumps(d, indent=2) == expected loaded_device = Device.from_dict(sdjson.loads(sdjson.dumps(d))) # the Counter won't be equal because the enum's have become disassociated assert loaded_device.device_id == d.device_id assert loaded_device.display_name == d.display_name assert loaded_device.configuration["make"] == d.configuration["make"] assert loaded_device.configuration["smart"] == d.configuration["smart"]
def test_dict_keys(): s, b, h, r = BigNum e, p, t = FloatNum i, j, n = WierdNum d = { s: 'tiny', b: 'large', h: 'larger', r: 'largest', e: "Euler's number", p: 'pi', t: 'tau', i: 'Infinity', j: '-Infinity', n: 'NaN', } nd = sdjson.loads(sdjson.dumps(d)) assert nd[str(SMALL)] == 'tiny' assert nd[str(BIG)] == 'large' assert nd[str(HUGE)] == 'larger' assert nd[str(REALLY_HUGE)] == 'largest' assert nd[repr(E)] == "Euler's number" assert nd[repr(PI)] == 'pi' assert nd[repr(TAU)] == 'tau' assert nd['Infinity'] == 'Infinity' assert nd['-Infinity'] == '-Infinity' assert nd['NaN'] == 'NaN'
def test_separators() -> None: h = [ ["blorpie"], ["whoops"], [], "d-shtaeou", "d-nthiouh", "i-vhbjkhnth", { "nifty": 87 }, { "field": "yes", "morefield": False }, ] expect = textwrap.dedent("""\ [ [ "blorpie" ] , [ "whoops" ] , [] , "d-shtaeou" , "d-nthiouh" , "i-vhbjkhnth" , { "nifty" : 87 } , { "field" : "yes" , "morefield" : false } ]""") d1 = sdjson.dumps(h) d2 = sdjson.dumps(h, indent=2, sort_keys=True, separators=(" ,", " : ")) h1 = sdjson.loads(d1) h2 = sdjson.loads(d2) assert h1 == h assert h2 == h assert d2 == expect
def helper(expected_output, **encode_kwargs): if "escape_forward_slashes" not in encode_kwargs: encode_kwargs["escape_forward_slashes"] = True, output = sd_ujson.encode(test_input, **encode_kwargs) assert output == expected_output if encode_kwargs.get("escape_forward_slashes", True): assert test_input == sdjson.loads(output) assert test_input == sd_ujson.decode(output)
def test_double_long_issue(): sut = {"a": -4342969734183514} encoded = sdjson.dumps(sut) decoded = sdjson.loads(encoded) assert sut == decoded encoded = sd_ujson.encode(sut) decoded = sd_ujson.decode(encoded) assert sut == decoded
def test_double_long_decimal_issue(): sut = {"a": -12345678901234.56789012} encoded = sdjson.dumps(sut) decoded = sdjson.loads(encoded) assert sut == decoded encoded = sd_ujson.encode(sut) decoded = sd_ujson.decode(encoded) assert sut == decoded
def __test_invalid_input(data, msg, idx): with pytest.raises(sdjson.JSONDecodeError) as err: sdjson.loads(data) if pypy: assert err.value.msg.startswith( msg) # Fix for varying messages between PyPy versions else: assert err.value.msg == msg assert err.value.pos == idx assert err.value.lineno == 1 assert err.value.colno == idx + 1 if pypy: assert re.match( rf'{msg}.*: line 1 column {idx + 1:d} \(char {idx:d}\)', str(err.value)) else: assert re.match(rf'{msg}: line 1 column {idx + 1:d} \(char {idx:d}\)', str(err.value))
def test_dump_skipkeys() -> None: v = {b"invalid_key": False, "valid_key": True} with pytest.raises(TypeError): sdjson.dumps(v) s = sdjson.dumps(v, skipkeys=True) o = sdjson.loads(s) assert "valid_key" in o assert b"invalid_key" not in o
def test_dump_skipkeys(): v = {b'invalid_key': False, 'valid_key': True} with pytest.raises(TypeError): sdjson.dumps(v) s = sdjson.dumps(v, skipkeys=True) o = sdjson.loads(s) assert 'valid_key' in o assert b'invalid_key' not in o
def test_separators(): h = [ ['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False}, ] expect = textwrap.dedent( """\ [ [ "blorpie" ] , [ "whoops" ] , [] , "d-shtaeou" , "d-nthiouh" , "i-vhbjkhnth" , { "nifty" : 87 } , { "field" : "yes" , "morefield" : false } ]""" ) d1 = sdjson.dumps(h) d2 = sdjson.dumps(h, indent=2, sort_keys=True, separators=(' ,', ' : ')) h1 = sdjson.loads(d1) h2 = sdjson.loads(d2) assert h1 == h assert h2 == h assert d2 == expect
def test_object_pairs_hook() -> None: s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4), ("qrt", 5), ("pad", 6), ("hoy", 7)] assert sdjson.loads(s, object_pairs_hook=lambda x: x) == p assert sdjson.load(StringIO(s), object_pairs_hook=lambda x: x) == p od = sdjson.loads(s, object_pairs_hook=OrderedDict) assert od == OrderedDict(p) assert type(od) == OrderedDict # the object_pairs_hook takes priority over the object_hook assert sdjson.loads(s, object_pairs_hook=OrderedDict, object_hook=lambda x: None) == OrderedDict(p) # check that empty object literals work (see #17368) assert sdjson.loads("{}", object_pairs_hook=OrderedDict) == OrderedDict() assert sdjson.loads('{"empty": {}}', object_pairs_hook=OrderedDict) == OrderedDict([ ("empty", OrderedDict()) ])
def test_string_with_utf8_bom(): import sys # see #18958 bom_json = "[1,2,3]".encode('utf-8-sig').decode('utf-8') with pytest.raises(sdjson.JSONDecodeError) as e: sdjson.loads(bom_json) # TODO: if sys.version_info.major >= 3 and sys.version_info.minor == 7: assert 'BOM' in str(e) with pytest.raises(sdjson.JSONDecodeError) as e: sdjson.load(StringIO(bom_json)) # TODO: if sys.version_info.major >= 3 and sys.version_info.minor == 7: assert 'BOM' in str(e) # make sure that the BOM is not detected in the middle of a string bom_in_str = '"{}"'.format(''.encode('utf-8-sig').decode('utf-8')) assert sdjson.loads(bom_in_str) == '\ufeff' assert sdjson.load(StringIO(bom_in_str)) == '\ufeff'
def test_highly_nested_objects_decoding() -> None: # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 with pytest.raises(RecursionError): sdjson.loads('{"a":' * 100000 + '1' + '}' * 100000) with pytest.raises(RecursionError): sdjson.loads('{"a":' * 100000 + "[1]" + '}' * 100000) with pytest.raises(RecursionError): sdjson.loads('[' * 100000 + '1' + ']' * 100000)
def test_dict(): assert dict(ref_data) == ref_data.__dict__ == ref_data_dict_non_recursive assert sdjson.loads(sdjson.dumps(ref_data)) == ref_data_dict assert ReferenceData.from_dict(dict(ref_data)) == ref_data for obj in [ test_string, test_int, test_float, test_list_ints, test_list_strs, test_dictionary, test_numbers, test_tuple, test_lists, test_sequences, test_lists, ]: with pytest.raises(TypeError): ReferenceData.from_dict(obj) # type: ignore