blob: 54906d1e7e9f90b14c702df7397b6fa6eb4ea8d0 [file] [log] [blame]
# Copyright 2024 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
from dataclasses import dataclass, field
from typing import Any, List, Optional, Sequence
from dataclasses_json_lite import config, dataclass_json
class DataclassesJsonLite(unittest.TestCase):
def test_simple_field(self) -> None:
@dataclass_json()
@dataclass
class MyClass:
number: int
numbers: List[int]
maybe_number: Optional[int] = None
maybe_number2: int | None = None
self.assertEquals(
MyClass(
number=12,
numbers=[1, 2, 3],
maybe_number=None,
maybe_number2=None,
),
MyClass.from_dict(dict(number=12, numbers=[1, 2, 3])), # type: ignore[attr-defined]
)
self.assertEquals(
MyClass(
number=12, numbers=[1, 2, 3], maybe_number=13, maybe_number2=14
),
MyClass.from_dict( # type: ignore[attr-defined]
dict(
number=12,
numbers=[1, 2, 3],
maybe_number=13,
maybe_number2=14,
)
),
)
def test_rename(self) -> None:
@dataclass_json()
@dataclass
class MyClass:
number: int = field(metadata=config(field_name="n"))
numbers: List[int] = field(metadata=config(field_name="ns"))
numbers2: Sequence[int] = field(metadata=config(field_name="ns2"))
self.assertEquals(
MyClass(number=12, numbers=[1, 2, 3], numbers2=[2, 3]),
MyClass.from_dict(dict(n=12, ns=[1, 2, 3], ns2=[2, 3])), # type: ignore[attr-defined]
)
def test_sub_class(self) -> None:
@dataclass_json()
@dataclass
class UserClass:
name: str
age: int
@dataclass_json()
@dataclass
class MyClass:
member: UserClass
members: List[List[UserClass]]
self.assertEquals(
MyClass(
member=UserClass(name="A", age=1),
members=[[UserClass(name="B", age=2)]],
),
MyClass.from_dict( # type: ignore[attr-defined]
dict(
member=dict(name="A", age=1),
members=[[dict(name="B", age=2)]],
)
),
)
def test_decoder(self) -> None:
@dataclass_json()
@dataclass
class UserClass:
name: str
age: int
def decoder(json_data: List[Any]) -> UserClass:
return UserClass(*json_data)
@dataclass_json()
@dataclass
class MyClass:
member: UserClass = field(metadata=config(decoder=decoder))
other: UserClass = field(
metadata=config(decoder=decoder, field_name="O")
)
self.assertEquals(
MyClass(
member=UserClass(name="A", age=1),
other=UserClass(name="B", age=2),
),
MyClass.from_dict(dict(member=["A", 1], O=["B", 2])), # type: ignore[attr-defined]
)
def test_unknown_field(self) -> None:
@dataclass_json()
@dataclass
class MyClass:
age: int = field(metadata=config(field_name="AA"))
with self.assertRaises(ValueError) as ctx:
MyClass.from_dict(dict(age=1)) # type: ignore[attr-defined]
self.assertIn("age", str(ctx.exception))
with self.assertRaises(ValueError) as ctx:
MyClass.from_dict(dict(banana=1)) # type: ignore[attr-defined]
self.assertIn("banana", str(ctx.exception))
def test_missing_field(self) -> None:
@dataclass_json()
@dataclass
class MyClass:
age: int
town: str = "Paris"
with self.assertRaises(TypeError) as ctx:
MyClass.from_dict(dict()) # type: ignore[attr-defined]
self.assertIn(
"missing 1 required positional argument: 'age'", str(ctx.exception)
)
def test_composition(self) -> None:
self.assertEquals(
MyComposedClass.from_dict( # type: ignore[attr-defined]
dict(opt_sub=dict(list_sub=[]), list_sub=[dict(list_sub=[])])
),
MyComposedClass(
opt_sub=MyComposedClass(
list_sub=[],
),
list_sub=[MyComposedClass(list_sub=[])],
),
)
@dataclass_json()
@dataclass
class MyComposedClass:
"""This class needs to be in the module scope so that it can be resolved."""
list_sub: List["MyComposedClass"]
opt_sub: Optional["MyComposedClass"] = None
if __name__ == "__main__":
unittest.main()