test_ext_json.py
177 lines
| 5.2 KiB
| text/x-python
|
PythonLexer
r5608 | import dataclasses# Copyright (C) 2010-2024 RhodeCode GmbH | |||
r1 | # | |||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
r5012 | import io | |||
r1 | import datetime | |||
import decimal | ||||
import textwrap | ||||
import pytest | ||||
r5012 | from rhodecode.lib import ext_json | |||
r2351 | from rhodecode.translation import _, _pluralize | |||
r1 | ||||
class Timezone(datetime.tzinfo): | ||||
def __init__(self, hours): | ||||
self.hours = hours | ||||
def utcoffset(self, unused_dt): | ||||
return datetime.timedelta(hours=self.hours) | ||||
r5012 | class SerializableObject(object): | |||
def __json__(self): | ||||
return 'foo' | ||||
r1 | def test_dumps_set(): | |||
r5012 | result = ext_json.json.dumps(set((1, 2, 3))) | |||
r1 | # We cannot infer what the order of result is going to be | |||
r5012 | result = ext_json.json.loads(result) | |||
r1 | assert isinstance(result, list) | |||
assert [1, 2, 3] == sorted(result) | ||||
def test_dumps_decimal(): | ||||
r5012 | assert b'"1.5"' == ext_json.json.dumps(decimal.Decimal('1.5')) | |||
r1 | ||||
def test_dumps_complex(): | ||||
r5012 | assert b"[0.0,1.0]" == ext_json.json.dumps(1j) | |||
assert b"[1.0,0.0]" == ext_json.json.dumps(1 + 0j) | ||||
assert b"[1.1,1.2]" == ext_json.json.dumps(1.1 + 1.2j) | ||||
r1 | ||||
def test_dumps_object_with_json_method(): | ||||
r5012 | assert '"foo"' == ext_json.str_json(SerializableObject()) | |||
r1 | ||||
def test_dumps_object_with_json_attribute(): | ||||
r5012 | assert '"foo"' == ext_json.str_json(SerializableObject()) | |||
r1 | ||||
def test_dumps_time(): | ||||
r5012 | assert '"03:14:15.926535"' == ext_json.str_json(datetime.time(3, 14, 15, 926535)) | |||
r1 | ||||
def test_dumps_time_no_microseconds(): | ||||
r5012 | assert '"03:14:15"' == ext_json.str_json(datetime.time(3, 14, 15)) | |||
r1 | ||||
def test_dumps_time_with_timezone(): | ||||
with pytest.raises(TypeError) as excinfo: | ||||
r5012 | ext_json.json.dumps(datetime.time(3, 14, 15, 926535, Timezone(0))) | |||
r1 | ||||
error_msg = str(excinfo.value) | ||||
r5012 | ||||
assert 'timezone library is not supported' in error_msg | ||||
# only for simplejson | ||||
#assert 'Time-zone aware times are not JSON serializable' in error_msg | ||||
r1 | ||||
def test_dumps_date(): | ||||
r5012 | assert b'"1969-07-20"' == ext_json.json.dumps(datetime.date(1969, 7, 20)) | |||
r1 | ||||
def test_dumps_datetime(): | ||||
r5012 | json_data = ext_json.json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15, 926535)) | |||
assert b'"1969-07-20T03:14:15.926535"' == json_data | ||||
r1 | ||||
def test_dumps_datetime_no_microseconds(): | ||||
r5012 | json_data = ext_json.json.dumps(datetime.datetime(1969, 7, 20, 3, 14, 15)) | |||
assert b'"1969-07-20T03:14:15"' == json_data | ||||
r1 | ||||
def test_dumps_datetime_with_utc_timezone(): | ||||
r5012 | json_data = ext_json.json.dumps( | |||
r1 | datetime.datetime(1969, 7, 20, 3, 14, 15, 926535, Timezone(0))) | |||
r5012 | assert b'"1969-07-20T03:14:15.926535+00:00"' == json_data | |||
r1 | ||||
def test_dumps_datetime_with_plus1_timezone(): | ||||
r5012 | json_data = ext_json.json.dumps( | |||
r1 | datetime.datetime(1969, 7, 20, 3, 14, 15, 926535, Timezone(1))) | |||
r5012 | assert b'"1969-07-20T03:14:15.926535+01:00"' == json_data | |||
r1 | ||||
def test_dumps_unserializable_class(): | ||||
unserializable_obj = object() | ||||
with pytest.raises(TypeError) as excinfo: | ||||
r5012 | ext_json.json.dumps(unserializable_obj) | |||
r1 | ||||
r5012 | assert 'object' in str(excinfo.value) | |||
r1 | assert 'is not JSON serializable' in str(excinfo.value) | |||
def test_dump_is_like_dumps(): | ||||
data = { | ||||
'decimal': decimal.Decimal('1.5'), | ||||
'set': set([1]), # Just one element to guarantee the order | ||||
'complex': 1 - 1j, | ||||
'datetime': datetime.datetime(1969, 7, 20, 3, 14, 15, 926535), | ||||
'time': datetime.time(3, 14, 15, 926535), | ||||
'date': datetime.date(1969, 7, 20), | ||||
} | ||||
r5012 | json_buffer = io.StringIO() # StringIO because dump uses simplejson not orjson | |||
ext_json.json.dump(data, json_buffer) | ||||
r1 | ||||
r5012 | assert ext_json.sjson.dumps(data) == json_buffer.getvalue() | |||
r1 | ||||
def test_formatted_json(): | ||||
data = { | ||||
'b': {'2': 2, '1': 1}, | ||||
'a': {'3': 3, '4': 4}, | ||||
} | ||||
expected_data = textwrap.dedent(''' | ||||
{ | ||||
r5012 | "a": { | |||
"3": 3, | ||||
"4": 4 | ||||
}, | ||||
"b": { | ||||
"1": 1, | ||||
"2": 2 | ||||
} | ||||
r1 | }''').strip() | |||
r5012 | assert expected_data == ext_json.formatted_str_json(data) | |||
r1 | ||||
r2358 | def test_lazy_translation_string(baseapp): | |||
r1 | data = {'label': _('hello')} | |||
r2351 | data2 = {'label2': _pluralize('singular', 'plural', 1)} | |||
r1 | ||||
r5012 | assert b'{"label":"hello"}' == ext_json.json.dumps(data) | |||
assert b'{"label2":"singular"}' == ext_json.json.dumps(data2) | ||||
r5169 | ||||
def test_serialize_dataclass(): | ||||
@dataclasses.dataclass | ||||
class ExampleStruct: | ||||
field_str: str | ||||
field_int: int | ||||
struct = ExampleStruct(field_int=1, field_str='hello') | ||||
raw_struct = b'{"field_str":"hello","field_int":1}' | ||||
assert raw_struct == ext_json.json.dumps(struct) | ||||
assert struct == ExampleStruct(**ext_json.json.loads(raw_struct)) | ||||