You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

992 lines
33 KiB

import decimal
import json
import math
import sys
import unittest
import pytest
from io import StringIO
from pathlib import Path
from srsly import ujson
json_unicode = json.dumps
class UltraJSONTests(unittest.TestCase):
def test_encodeDecimal(self):
sut = decimal.Decimal("1337.1337")
encoded = ujson.encode(sut)
decoded = ujson.decode(encoded)
self.assertEqual(decoded, 1337.1337)
def test_encodeStringConversion(self):
input = "A string \\ / \b \f \n \r \t </script> &"
not_html_encoded = '"A string \\\\ \\/ \\b \\f \\n \\r \\t <\\/script> &"'
html_encoded = (
'"A string \\\\ \\/ \\b \\f \\n \\r \\t \\u003c\\/script\\u003e \\u0026"'
)
not_slashes_escaped = '"A string \\\\ / \\b \\f \\n \\r \\t </script> &"'
def helper(expected_output, **encode_kwargs):
output = ujson.encode(input, **encode_kwargs)
self.assertEqual(output, expected_output)
if encode_kwargs.get("escape_forward_slashes", True):
self.assertEqual(input, json.loads(output))
self.assertEqual(input, ujson.decode(output))
# Default behavior assumes encode_html_chars=False.
helper(not_html_encoded, ensure_ascii=True)
helper(not_html_encoded, ensure_ascii=False)
# Make sure explicit encode_html_chars=False works.
helper(not_html_encoded, ensure_ascii=True, encode_html_chars=False)
helper(not_html_encoded, ensure_ascii=False, encode_html_chars=False)
# Make sure explicit encode_html_chars=True does the encoding.
helper(html_encoded, ensure_ascii=True, encode_html_chars=True)
helper(html_encoded, ensure_ascii=False, encode_html_chars=True)
# Do escape forward slashes if disabled.
helper(not_slashes_escaped, escape_forward_slashes=False)
def testWriteEscapedString(self):
self.assertEqual(
"\"\\u003cimg src='\\u0026amp;'\\/\\u003e\"",
ujson.dumps("<img src='&amp;'/>", encode_html_chars=True),
)
def test_doubleLongIssue(self):
sut = {"a": -4342969734183514}
encoded = json.dumps(sut)
decoded = json.loads(encoded)
self.assertEqual(sut, decoded)
encoded = ujson.encode(sut)
decoded = ujson.decode(encoded)
self.assertEqual(sut, decoded)
def test_doubleLongDecimalIssue(self):
sut = {"a": -12345678901234.56789012}
encoded = json.dumps(sut)
decoded = json.loads(encoded)
self.assertEqual(sut, decoded)
encoded = ujson.encode(sut)
decoded = ujson.decode(encoded)
self.assertEqual(sut, decoded)
def test_encodeDecodeLongDecimal(self):
sut = {"a": -528656961.4399388}
encoded = ujson.dumps(sut)
ujson.decode(encoded)
def test_decimalDecodeTest(self):
sut = {"a": 4.56}
encoded = ujson.encode(sut)
decoded = ujson.decode(encoded)
self.assertAlmostEqual(sut[u"a"], decoded[u"a"])
def test_encodeDictWithUnicodeKeys(self):
input = {
"key1": "value1",
"key1": "value1",
"key1": "value1",
"key1": "value1",
"key1": "value1",
"key1": "value1",
}
ujson.encode(input)
input = {
"بن": "value1",
"بن": "value1",
"بن": "value1",
"بن": "value1",
"بن": "value1",
"بن": "value1",
"بن": "value1",
}
ujson.encode(input)
def test_encodeDoubleConversion(self):
input = math.pi
output = ujson.encode(input)
self.assertEqual(round(input, 5), round(json.loads(output), 5))
self.assertEqual(round(input, 5), round(ujson.decode(output), 5))
def test_encodeWithDecimal(self):
input = 1.0
output = ujson.encode(input)
self.assertEqual(output, "1.0")
def test_encodeDoubleNegConversion(self):
input = -math.pi
output = ujson.encode(input)
self.assertEqual(round(input, 5), round(json.loads(output), 5))
self.assertEqual(round(input, 5), round(ujson.decode(output), 5))
def test_encodeArrayOfNestedArrays(self):
input = [[[[]]]] * 20
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
# self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeArrayOfDoubles(self):
input = [31337.31337, 31337.31337, 31337.31337, 31337.31337] * 10
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
# self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeStringConversion2(self):
input = "A string \\ / \b \f \n \r \t"
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, '"A string \\\\ \\/ \\b \\f \\n \\r \\t"')
self.assertEqual(input, ujson.decode(output))
def test_decodeUnicodeConversion(self):
pass
def test_encodeUnicodeConversion1(self):
input = "Räksmörgås اسامة بن محمد بن عوض بن لادن"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(enc, json_unicode(input))
self.assertEqual(dec, json.loads(enc))
def test_encodeControlEscaping(self):
input = "\x19"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(input, dec)
self.assertEqual(enc, json_unicode(input))
def test_encodeUnicodeConversion2(self):
input = "\xe6\x97\xa5\xd1\x88"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(enc, json_unicode(input))
self.assertEqual(dec, json.loads(enc))
def test_encodeUnicodeSurrogatePair(self):
input = "\xf0\x90\x8d\x86"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(enc, json_unicode(input))
self.assertEqual(dec, json.loads(enc))
def test_encodeUnicode4BytesUTF8(self):
input = "\xf0\x91\x80\xb0TRAILINGNORMAL"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(enc, json_unicode(input))
self.assertEqual(dec, json.loads(enc))
def test_encodeUnicode4BytesUTF8Highest(self):
input = "\xf3\xbf\xbf\xbfTRAILINGNORMAL"
enc = ujson.encode(input)
dec = ujson.decode(enc)
self.assertEqual(enc, json_unicode(input))
self.assertEqual(dec, json.loads(enc))
# Characters outside of Basic Multilingual Plane(larger than
# 16 bits) are represented as \UXXXXXXXX in python but should be encoded
# as \uXXXX\uXXXX in json.
def testEncodeUnicodeBMP(self):
s = "\U0001f42e\U0001f42e\U0001F42D\U0001F42D" # 🐮🐮🐭🐭
encoded = ujson.dumps(s)
encoded_json = json.dumps(s)
if len(s) == 4:
self.assertEqual(len(encoded), len(s) * 12 + 2)
else:
self.assertEqual(len(encoded), len(s) * 6 + 2)
self.assertEqual(encoded, encoded_json)
decoded = ujson.loads(encoded)
self.assertEqual(s, decoded)
# ujson outputs an UTF-8 encoded str object
encoded = ujson.dumps(s, ensure_ascii=False)
# json outputs an unicode object
encoded_json = json.dumps(s, ensure_ascii=False)
self.assertEqual(len(encoded), len(s) + 2) # original length + quotes
self.assertEqual(encoded, encoded_json)
decoded = ujson.loads(encoded)
self.assertEqual(s, decoded)
def testEncodeSymbols(self):
s = "\u273f\u2661\u273f" # ✿♡✿
encoded = ujson.dumps(s)
encoded_json = json.dumps(s)
self.assertEqual(len(encoded), len(s) * 6 + 2) # 6 characters + quotes
self.assertEqual(encoded, encoded_json)
decoded = ujson.loads(encoded)
self.assertEqual(s, decoded)
# ujson outputs an UTF-8 encoded str object
encoded = ujson.dumps(s, ensure_ascii=False)
# json outputs an unicode object
encoded_json = json.dumps(s, ensure_ascii=False)
self.assertEqual(len(encoded), len(s) + 2) # original length + quotes
self.assertEqual(encoded, encoded_json)
decoded = ujson.loads(encoded)
self.assertEqual(s, decoded)
def test_encodeArrayInArray(self):
input = [[[[]]]]
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeIntConversion(self):
input = 31337
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeIntNegConversion(self):
input = -31337
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeLongNegConversion(self):
input = -9223372036854775808
output = ujson.encode(input)
json.loads(output)
ujson.decode(output)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeListConversion(self):
input = [1, 2, 3, 4]
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(input, ujson.decode(output))
def test_encodeDictConversion(self):
input = {"k1": 1, "k2": 2, "k3": 3, "k4": 4}
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(input, ujson.decode(output))
self.assertEqual(input, ujson.decode(output))
def test_encodeNoneConversion(self):
input = None
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeTrueConversion(self):
input = True
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeFalseConversion(self):
input = False
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeToUTF8(self):
input = b"\xe6\x97\xa5\xd1\x88"
input = input.decode("utf-8")
enc = ujson.encode(input, ensure_ascii=False)
dec = ujson.decode(enc)
self.assertEqual(enc, json.dumps(input, ensure_ascii=False))
self.assertEqual(dec, json.loads(enc))
def test_decodeFromUnicode(self):
input = '{"obj": 31337}'
dec1 = ujson.decode(input)
dec2 = ujson.decode(str(input))
self.assertEqual(dec1, dec2)
def test_encodeRecursionMax(self):
# 8 is the max recursion depth
class O2:
member = 0
def toDict(self):
return {"member": self.member}
class O1:
member = 0
def toDict(self):
return {"member": self.member}
input = O1()
input.member = O2()
input.member.member = input
self.assertRaises(OverflowError, ujson.encode, input)
def test_encodeDoubleNan(self):
input = float("nan")
self.assertRaises(OverflowError, ujson.encode, input)
def test_encodeDoubleInf(self):
input = float("inf")
self.assertRaises(OverflowError, ujson.encode, input)
def test_encodeDoubleNegInf(self):
input = -float("inf")
self.assertRaises(OverflowError, ujson.encode, input)
def test_encodeOrderedDict(self):
from collections import OrderedDict
input = OrderedDict([(1, 1), (0, 0), (8, 8), (2, 2)])
self.assertEqual('{"1":1,"0":0,"8":8,"2":2}', ujson.encode(input))
def test_decodeJibberish(self):
input = "fdsa sda v9sa fdsa"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenArrayStart(self):
input = "["
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenObjectStart(self):
input = "{"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenArrayEnd(self):
input = "]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayDepthTooBig(self):
input = "[" * (1024 * 1024)
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenObjectEnd(self):
input = "}"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeObjectTrailingCommaFail(self):
input = '{"one":1,}'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeObjectDepthTooBig(self):
input = "{" * (1024 * 1024)
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeStringUnterminated(self):
input = '"TESTING'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeStringUntermEscapeSequence(self):
input = '"TESTING\\"'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeStringBadEscape(self):
input = '"TESTING\\"'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeTrueBroken(self):
input = "tru"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeFalseBroken(self):
input = "fa"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeNullBroken(self):
input = "n"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenDictKeyTypeLeakTest(self):
input = '{{1337:""}}'
for x in range(1000):
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenDictLeakTest(self):
input = '{{"key":"}'
for x in range(1000):
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeBrokenListLeakTest(self):
input = "[[[true"
for x in range(1000):
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeDictWithNoKey(self):
input = "{{{{31337}}}}"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeDictWithNoColonOrValue(self):
input = '{{{{"key"}}}}'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeDictWithNoValue(self):
input = '{{{{"key":}}}}'
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeNumericIntPos(self):
input = "31337"
self.assertEqual(31337, ujson.decode(input))
def test_decodeNumericIntNeg(self):
input = "-31337"
self.assertEqual(-31337, ujson.decode(input))
def test_encodeUnicode4BytesUTF8Fail(self):
input = b"\xfd\xbf\xbf\xbf\xbf\xbf"
self.assertRaises(OverflowError, ujson.encode, input)
def test_encodeNullCharacter(self):
input = "31337 \x00 1337"
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
input = "\x00"
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
self.assertEqual('" \\u0000\\r\\n "', ujson.dumps(" \u0000\r\n "))
def test_decodeNullCharacter(self):
input = '"31337 \\u0000 31337"'
self.assertEqual(ujson.decode(input), json.loads(input))
def test_encodeListLongConversion(self):
input = [
9223372036854775807,
9223372036854775807,
9223372036854775807,
9223372036854775807,
9223372036854775807,
9223372036854775807,
]
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(input, ujson.decode(output))
def test_encodeListLongUnsignedConversion(self):
input = [18446744073709551615, 18446744073709551615, 18446744073709551615]
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(input, ujson.decode(output))
def test_encodeLongConversion(self):
input = 9223372036854775807
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_encodeLongUnsignedConversion(self):
input = 18446744073709551615
output = ujson.encode(input)
self.assertEqual(input, json.loads(output))
self.assertEqual(output, json.dumps(input))
self.assertEqual(input, ujson.decode(output))
def test_numericIntExp(self):
input = "1337E40"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_numericIntFrcExp(self):
input = "1.337E40"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpEPLUS(self):
input = "1337E+9"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpePLUS(self):
input = "1.337e+40"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpE(self):
input = "1337E40"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpe(self):
input = "1337e40"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpEMinus(self):
input = "1.337E-4"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_decodeNumericIntExpeMinus(self):
input = "1.337e-4"
output = ujson.decode(input)
self.assertEqual(output, json.loads(input))
def test_dumpToFile(self):
f = StringIO()
ujson.dump([1, 2, 3], f)
self.assertEqual("[1,2,3]", f.getvalue())
def test_dumpToFileLikeObject(self):
class filelike:
def __init__(self):
self.bytes = ""
def write(self, bytes):
self.bytes += bytes
f = filelike()
ujson.dump([1, 2, 3], f)
self.assertEqual("[1,2,3]", f.bytes)
def test_dumpFileArgsError(self):
self.assertRaises(TypeError, ujson.dump, [], "")
def test_loadFile(self):
f = StringIO("[1,2,3,4]")
self.assertEqual([1, 2, 3, 4], ujson.load(f))
def test_loadFileLikeObject(self):
class filelike:
def read(self):
try:
self.end
except AttributeError:
self.end = True
return "[1,2,3,4]"
f = filelike()
self.assertEqual([1, 2, 3, 4], ujson.load(f))
def test_loadFileArgsError(self):
self.assertRaises(TypeError, ujson.load, "[]")
def test_encodeNumericOverflow(self):
self.assertRaises(OverflowError, ujson.encode, 12839128391289382193812939)
def test_decodeNumberWith32bitSignBit(self):
# Test that numbers that fit within 32 bits but would have the
# sign bit set (2**31 <= x < 2**32) are decoded properly.
docs = (
'{"id": 3590016419}',
'{"id": %s}' % 2 ** 31,
'{"id": %s}' % 2 ** 32,
'{"id": %s}' % ((2 ** 32) - 1),
)
results = (3590016419, 2 ** 31, 2 ** 32, 2 ** 32 - 1)
for doc, result in zip(docs, results):
self.assertEqual(ujson.decode(doc)["id"], result)
def test_encodeBigEscape(self):
for x in range(10):
base = "\u00e5".encode("utf-8")
input = base * 1024 * 1024 * 2
ujson.encode(input)
def test_decodeBigEscape(self):
for x in range(10):
base = "\u00e5".encode("utf-8")
quote = '"'.encode()
input = quote + (base * 1024 * 1024 * 2) + quote
ujson.decode(input)
def test_toDict(self):
d = {"key": 31337}
class DictTest:
def toDict(self):
return d
def __json__(self):
return '"json defined"' # Fallback and shouldn't be called.
o = DictTest()
output = ujson.encode(o)
dec = ujson.decode(output)
self.assertEqual(dec, d)
def test_object_with_json(self):
# If __json__ returns a string, then that string
# will be used as a raw JSON snippet in the object.
output_text = "this is the correct output"
class JSONTest:
def __json__(self):
return '"' + output_text + '"'
d = {u"key": JSONTest()}
output = ujson.encode(d)
dec = ujson.decode(output)
self.assertEqual(dec, {u"key": output_text})
def test_object_with_json_unicode(self):
# If __json__ returns a string, then that string
# will be used as a raw JSON snippet in the object.
output_text = u"this is the correct output"
class JSONTest:
def __json__(self):
return u'"' + output_text + u'"'
d = {u"key": JSONTest()}
output = ujson.encode(d)
dec = ujson.decode(output)
self.assertEqual(dec, {u"key": output_text})
def test_object_with_complex_json(self):
# If __json__ returns a string, then that string
# will be used as a raw JSON snippet in the object.
obj = {u"foo": [u"bar", u"baz"]}
class JSONTest:
def __json__(self):
return ujson.encode(obj)
d = {u"key": JSONTest()}
output = ujson.encode(d)
dec = ujson.decode(output)
self.assertEqual(dec, {u"key": obj})
def test_object_with_json_type_error(self):
# __json__ must return a string, otherwise it should raise an error.
for return_value in (None, 1234, 12.34, True, {}):
class JSONTest:
def __json__(self):
return return_value
d = {u"key": JSONTest()}
self.assertRaises(TypeError, ujson.encode, d)
def test_object_with_json_attribute_error(self):
# If __json__ raises an error, make sure python actually raises it.
class JSONTest:
def __json__(self):
raise AttributeError
d = {u"key": JSONTest()}
self.assertRaises(AttributeError, ujson.encode, d)
def test_decodeArrayTrailingCommaFail(self):
input = "[31337,]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayLeadingCommaFail(self):
input = "[,31337]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayOnlyCommaFail(self):
input = "[,]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayUnmatchedBracketFail(self):
input = "[]]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayEmpty(self):
input = "[]"
obj = ujson.decode(input)
self.assertEqual([], obj)
def test_decodeArrayOneItem(self):
input = "[31337]"
ujson.decode(input)
def test_decodeLongUnsignedValue(self):
input = "18446744073709551615"
ujson.decode(input)
def test_decodeBigValue(self):
input = "9223372036854775807"
ujson.decode(input)
def test_decodeSmallValue(self):
input = "-9223372036854775808"
ujson.decode(input)
def test_decodeTooBigValue(self):
input = "18446744073709551616"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeTooSmallValue(self):
input = "-90223372036854775809"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeVeryTooBigValue(self):
input = "18446744073709551616"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeVeryTooSmallValue(self):
input = "-90223372036854775809"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeWithTrailingWhitespaces(self):
input = "{}\n\t "
ujson.decode(input)
def test_decodeWithTrailingNonWhitespaces(self):
input = "{}\n\t a"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeArrayWithBigInt(self):
input = "[18446744073709551616]"
self.assertRaises(ValueError, ujson.decode, input)
def test_decodeFloatingPointAdditionalTests(self):
self.assertAlmostEqual(-1.1234567893, ujson.loads("-1.1234567893"))
self.assertAlmostEqual(-1.234567893, ujson.loads("-1.234567893"))
self.assertAlmostEqual(-1.34567893, ujson.loads("-1.34567893"))
self.assertAlmostEqual(-1.4567893, ujson.loads("-1.4567893"))
self.assertAlmostEqual(-1.567893, ujson.loads("-1.567893"))
self.assertAlmostEqual(-1.67893, ujson.loads("-1.67893"))
self.assertAlmostEqual(-1.7894, ujson.loads("-1.7894"))
self.assertAlmostEqual(-1.893, ujson.loads("-1.893"))
self.assertAlmostEqual(-1.3, ujson.loads("-1.3"))
self.assertAlmostEqual(1.1234567893, ujson.loads("1.1234567893"))
self.assertAlmostEqual(1.234567893, ujson.loads("1.234567893"))
self.assertAlmostEqual(1.34567893, ujson.loads("1.34567893"))
self.assertAlmostEqual(1.4567893, ujson.loads("1.4567893"))
self.assertAlmostEqual(1.567893, ujson.loads("1.567893"))
self.assertAlmostEqual(1.67893, ujson.loads("1.67893"))
self.assertAlmostEqual(1.7894, ujson.loads("1.7894"))
self.assertAlmostEqual(1.893, ujson.loads("1.893"))
self.assertAlmostEqual(1.3, ujson.loads("1.3"))
def test_ReadBadObjectSyntax(self):
input = '{"age", 44}'
self.assertRaises(ValueError, ujson.decode, input)
def test_ReadTrue(self):
self.assertEqual(True, ujson.loads("true"))
def test_ReadFalse(self):
self.assertEqual(False, ujson.loads("false"))
def test_ReadNull(self):
self.assertEqual(None, ujson.loads("null"))
def test_WriteTrue(self):
self.assertEqual("true", ujson.dumps(True))
def test_WriteFalse(self):
self.assertEqual("false", ujson.dumps(False))
def test_WriteNull(self):
self.assertEqual("null", ujson.dumps(None))
def test_ReadArrayOfSymbols(self):
self.assertEqual([True, False, None], ujson.loads(" [ true, false,null] "))
def test_WriteArrayOfSymbolsFromList(self):
self.assertEqual("[true,false,null]", ujson.dumps([True, False, None]))
def test_WriteArrayOfSymbolsFromTuple(self):
self.assertEqual("[true,false,null]", ujson.dumps((True, False, None)))
def test_encodingInvalidUnicodeCharacter(self):
s = "\udc7f"
self.assertRaises(UnicodeEncodeError, ujson.dumps, s)
def test_sortKeys(self):
data = {"a": 1, "c": 1, "b": 1, "e": 1, "f": 1, "d": 1}
sortedKeys = ujson.dumps(data, sort_keys=True)
self.assertEqual(sortedKeys, '{"a":1,"b":1,"c":1,"d":1,"e":1,"f":1}')
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_values(self):
import gc
gc.collect()
value = ["abc"]
data = {"1": value}
ref_count = sys.getrefcount(value)
ujson.dumps(data)
self.assertEqual(ref_count, sys.getrefcount(value))
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_keys(self):
import gc
gc.collect()
key1 = "1"
key2 = "1"
value1 = ["abc"]
value2 = [1, 2, 3]
data = {key1: value1, key2: value2}
ref_count1 = sys.getrefcount(key1)
ref_count2 = sys.getrefcount(key2)
ujson.dumps(data)
self.assertEqual(ref_count1, sys.getrefcount(key1))
self.assertEqual(ref_count2, sys.getrefcount(key2))
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_string_key(self):
import gc
gc.collect()
key1 = "1"
value1 = 1
data = {key1: value1}
ref_count1 = sys.getrefcount(key1)
ujson.dumps(data)
self.assertEqual(ref_count1, sys.getrefcount(key1))
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_tuple_key(self):
import gc
gc.collect()
key1 = ("a",)
value1 = 1
data = {key1: value1}
ref_count1 = sys.getrefcount(key1)
ujson.dumps(data)
self.assertEqual(ref_count1, sys.getrefcount(key1))
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_bytes_key(self):
import gc
gc.collect()
key1 = b"1"
value1 = 1
data = {key1: value1}
ref_count1 = sys.getrefcount(key1)
ujson.dumps(data)
self.assertEqual(ref_count1, sys.getrefcount(key1))
@unittest.skipIf(not hasattr(sys, 'getrefcount') == True, reason="test requires sys.refcount")
def test_does_not_leak_dictionary_None_key(self):
import gc
gc.collect()
key1 = None
value1 = 1
data = {key1: value1}
ref_count1 = sys.getrefcount(key1)
ujson.dumps(data)
self.assertEqual(ref_count1, sys.getrefcount(key1))
"""
def test_decodeNumericIntFrcOverflow(self):
input = "X.Y"
raise NotImplementedError("Implement this test!")
def test_decodeStringUnicodeEscape(self):
input = "\u3131"
raise NotImplementedError("Implement this test!")
def test_decodeStringUnicodeBrokenEscape(self):
input = "\u3131"
raise NotImplementedError("Implement this test!")
def test_decodeStringUnicodeInvalidEscape(self):
input = "\u3131"
raise NotImplementedError("Implement this test!")
def test_decodeStringUTF8(self):
input = "someutfcharacters"
raise NotImplementedError("Implement this test!")
"""
if __name__ == "__main__":
unittest.main()
"""
# Use this to look for memory leaks
if __name__ == '__main__':
from guppy import hpy
hp = hpy()
hp.setrelheap()
while True:
try:
unittest.main()
except SystemExit:
pass
heap = hp.heapu()
print(heap)
"""
@pytest.mark.parametrize("indent", list(range(65537, 65542)))
def test_dump_huge_indent(indent):
ujson.encode({"a": True}, indent=indent)
@pytest.mark.parametrize("first_length", list(range(2, 7)))
@pytest.mark.parametrize("second_length", list(range(10919, 10924)))
def test_dump_long_string(first_length, second_length):
ujson.dumps(["a" * first_length, "\x00" * second_length])
def test_dump_indented_nested_list():
a = _a = []
for i in range(20):
_a.append(list(range(i)))
_a = _a[-1]
ujson.dumps(a, indent=i)
@pytest.mark.parametrize("indent", [0, 1, 2, 4, 5, 8, 49])
def test_issue_334(indent):
path = Path(__file__).with_name("334-reproducer.json")
a = ujson.loads(path.read_bytes())
ujson.dumps(a, indent=indent)
@pytest.mark.parametrize(
"test_input, expected",
[
# Normal cases
(r'"\uD83D\uDCA9"', "\U0001F4A9"),
(r'"a\uD83D\uDCA9b"', "a\U0001F4A9b"),
# Unpaired surrogates
(r'"\uD800"', "\uD800"),
(r'"a\uD800b"', "a\uD800b"),
(r'"\uDEAD"', "\uDEAD"),
(r'"a\uDEADb"', "a\uDEADb"),
(r'"\uD83D\uD83D\uDCA9"', "\uD83D\U0001F4A9"),
(r'"\uDCA9\uD83D\uDCA9"', "\uDCA9\U0001F4A9"),
(r'"\uD83D\uDCA9\uD83D"', "\U0001F4A9\uD83D"),
(r'"\uD83D\uDCA9\uDCA9"', "\U0001F4A9\uDCA9"),
(r'"\uD83D \uDCA9"', "\uD83D \uDCA9"),
# No decoding of actual surrogate characters (rather than escaped ones)
('"\uD800"', "\uD800"),
('"\uDEAD"', "\uDEAD"),
('"\uD800a\uDEAD"', "\uD800a\uDEAD"),
('"\uD83D\uDCA9"', "\uD83D\uDCA9"),
],
)
def test_decode_surrogate_characters(test_input, expected):
assert ujson.loads(test_input) == expected
assert ujson.loads(test_input.encode("utf-8", "surrogatepass")) == expected
# Ensure that this matches stdlib's behaviour
assert json.loads(test_input) == expected