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
|
import uuid
from datetime import date
from datetime import datetime
from datetime import time
from datetime import timedelta
from decimal import Decimal
from unittest import TestCase
from constance.codecs import dumps
from constance.codecs import loads
from constance.codecs import register_type
class TestJSONSerialization(TestCase):
def setUp(self):
self.datetime = datetime(2023, 10, 5, 15, 30, 0)
self.date = date(2023, 10, 5)
self.time = time(15, 30, 0)
self.decimal = Decimal('10.5')
self.uuid = uuid.UUID('12345678123456781234567812345678')
self.string = 'test'
self.integer = 42
self.float = 3.14
self.boolean = True
self.none = None
self.timedelta = timedelta(days=1, hours=2, minutes=3)
self.list = [1, 2, self.date]
self.dict = {'key': self.date, 'key2': 1}
def test_serializes_and_deserializes_default_types(self):
self.assertEqual(dumps(self.datetime), '{"__type__": "datetime", "__value__": "2023-10-05T15:30:00"}')
self.assertEqual(dumps(self.date), '{"__type__": "date", "__value__": "2023-10-05"}')
self.assertEqual(dumps(self.time), '{"__type__": "time", "__value__": "15:30:00"}')
self.assertEqual(dumps(self.decimal), '{"__type__": "decimal", "__value__": "10.5"}')
self.assertEqual(dumps(self.uuid), '{"__type__": "uuid", "__value__": "12345678123456781234567812345678"}')
self.assertEqual(dumps(self.string), '{"__type__": "default", "__value__": "test"}')
self.assertEqual(dumps(self.integer), '{"__type__": "default", "__value__": 42}')
self.assertEqual(dumps(self.float), '{"__type__": "default", "__value__": 3.14}')
self.assertEqual(dumps(self.boolean), '{"__type__": "default", "__value__": true}')
self.assertEqual(dumps(self.none), '{"__type__": "default", "__value__": null}')
self.assertEqual(dumps(self.timedelta), '{"__type__": "timedelta", "__value__": 93780.0}')
self.assertEqual(
dumps(self.list),
'{"__type__": "default", "__value__": [1, 2, {"__type__": "date", "__value__": "2023-10-05"}]}',
)
self.assertEqual(
dumps(self.dict),
'{"__type__": "default", "__value__": {"key": {"__type__": "date", "__value__": "2023-10-05"}, "key2": 1}}',
)
for t in (
self.datetime,
self.date,
self.time,
self.decimal,
self.uuid,
self.string,
self.integer,
self.float,
self.boolean,
self.none,
self.timedelta,
self.dict,
self.list,
):
self.assertEqual(t, loads(dumps(t)))
def test_invalid_deserialization(self):
with self.assertRaisesRegex(ValueError, 'Expecting value'):
loads('THIS_IS_NOT_RIGHT')
with self.assertRaisesRegex(ValueError, 'Invalid object'):
loads('{"__type__": "THIS_IS_NOT_RIGHT", "__value__": "test", "THIS_IS_NOT_RIGHT": "THIS_IS_NOT_RIGHT"}')
with self.assertRaisesRegex(ValueError, 'Unsupported type'):
loads('{"__type__": "THIS_IS_NOT_RIGHT", "__value__": "test"}')
def test_handles_unknown_type(self):
class UnknownType:
pass
with self.assertRaisesRegex(TypeError, 'Object of type UnknownType is not JSON serializable'):
dumps(UnknownType())
def test_custom_type_serialization(self):
class CustomType:
def __init__(self, value):
self.value = value
register_type(CustomType, 'custom', lambda o: o.value, lambda o: CustomType(o))
custom_data = CustomType('test')
json_data = dumps(custom_data)
self.assertEqual(json_data, '{"__type__": "custom", "__value__": "test"}')
deserialized_data = loads(json_data)
self.assertTrue(isinstance(deserialized_data, CustomType))
self.assertEqual(deserialized_data.value, 'test')
def test_register_known_type(self):
with self.assertRaisesRegex(ValueError, 'Discriminator must be specified'):
register_type(int, '', lambda o: o.value, lambda o: int(o))
with self.assertRaisesRegex(ValueError, 'Type with discriminator default is already registered'):
register_type(int, 'default', lambda o: o.value, lambda o: int(o))
register_type(int, 'new_custom_type', lambda o: o.value, lambda o: int(o))
with self.assertRaisesRegex(ValueError, 'Type with discriminator new_custom_type is already registered'):
register_type(int, 'new_custom_type', lambda o: o.value, lambda o: int(o))
def test_nested_collections(self):
data = {'key': [[[[{'key': self.date}]]]]}
self.assertEqual(
dumps(data),
(
'{"__type__": "default", '
'"__value__": {"key": [[[[{"key": {"__type__": "date", "__value__": "2023-10-05"}}]]]]}}'
),
)
self.assertEqual(data, loads(dumps(data)))
|