finish implementing @plain_data()
[nmutil.git] / src / nmutil / test / test_plain_data.py
1 # SPDX-License-Identifier: LGPL-3-or-later
2 # Copyright 2022 Jacob Lifshay programmerjake@gmail.com
3
4 import operator
5 import pickle
6 import unittest
7 from nmutil.plain_data import FrozenPlainDataError, plain_data
8
9
10 @plain_data(order=True)
11 class PlainData0:
12 __slots__ = ()
13
14
15 @plain_data(order=True)
16 class PlainData1:
17 __slots__ = "a", "b", "x", "y"
18
19 def __init__(self, a, b, *, x, y):
20 self.a = a
21 self.b = b
22 self.x = x
23 self.y = y
24
25
26 @plain_data(order=True)
27 class PlainData2(PlainData1):
28 __slots__ = "a", "z"
29
30 def __init__(self, a, b, *, x, y, z):
31 super().__init__(a, b, x=x, y=y)
32 self.z = z
33
34
35 @plain_data(order=True, frozen=True, unsafe_hash=True)
36 class PlainDataF0:
37 __slots__ = ()
38
39
40 @plain_data(order=True, frozen=True, unsafe_hash=True)
41 class PlainDataF1:
42 __slots__ = "a", "b", "x", "y"
43
44 def __init__(self, a, b, *, x, y):
45 self.a = a
46 self.b = b
47 self.x = x
48 self.y = y
49
50
51 @plain_data(order=True, frozen=True, unsafe_hash=True)
52 class PlainDataF2(PlainDataF1):
53 __slots__ = "a", "z"
54
55 def __init__(self, a, b, *, x, y, z):
56 super().__init__(a, b, x=x, y=y)
57 self.z = z
58
59
60 class TestPlainData(unittest.TestCase):
61 def test_fields(self):
62 self.assertEqual(PlainData0._fields, ())
63 self.assertEqual(PlainData1._fields, ("a", "b", "x", "y"))
64 self.assertEqual(PlainData2._fields, ("a", "b", "x", "y", "z"))
65 self.assertEqual(PlainDataF0._fields, ())
66 self.assertEqual(PlainDataF1._fields, ("a", "b", "x", "y"))
67 self.assertEqual(PlainDataF2._fields, ("a", "b", "x", "y", "z"))
68
69 def test_eq(self):
70 self.assertTrue(PlainData0() == PlainData0())
71 self.assertFalse('a' == PlainData0())
72 self.assertFalse(PlainDataF0() == PlainData0())
73 self.assertTrue(PlainData1(1, 2, x="x", y="y")
74 == PlainData1(1, 2, x="x", y="y"))
75 self.assertFalse(PlainData1(1, 2, x="x", y="y")
76 == PlainData1(1, 2, x="x", y="z"))
77 self.assertFalse(PlainData1(1, 2, x="x", y="y")
78 == PlainData2(1, 2, x="x", y="y", z=3))
79
80 def test_hash(self):
81 def check_op(v, tuple_v):
82 with self.subTest(v=v, tuple_v=tuple_v):
83 self.assertEqual(hash(v), hash(tuple_v))
84
85 def check(a, b, x, y, z):
86 tuple_v = a, b, x, y, z
87 v = PlainDataF2(a=a, b=b, x=x, y=y, z=z)
88 check_op(v, tuple_v)
89
90 check(1, 2, "x", "y", "z")
91
92 check(1, 2, "x", "y", "a")
93 check(1, 2, "x", "y", "zz")
94
95 check(1, 2, "x", "a", "z")
96 check(1, 2, "x", "zz", "z")
97
98 check(1, 2, "a", "y", "z")
99 check(1, 2, "zz", "y", "z")
100
101 check(1, -10, "x", "y", "z")
102 check(1, 10, "x", "y", "z")
103
104 check(-10, 2, "x", "y", "z")
105 check(10, 2, "x", "y", "z")
106
107 def test_order(self):
108 def check_op(l, r, tuple_l, tuple_r, op):
109 with self.subTest(l=l, r=r,
110 tuple_l=tuple_l, tuple_r=tuple_r, op=op):
111 self.assertEqual(op(l, r), op(tuple_l, tuple_r))
112 self.assertEqual(op(r, l), op(tuple_r, tuple_l))
113
114 def check(a, b, x, y, z):
115 tuple_l = 1, 2, "x", "y", "z"
116 l = PlainData2(a=1, b=2, x="x", y="y", z="z")
117 tuple_r = a, b, x, y, z
118 r = PlainData2(a=a, b=b, x=x, y=y, z=z)
119 check_op(l, r, tuple_l, tuple_r, operator.eq)
120 check_op(l, r, tuple_l, tuple_r, operator.ne)
121 check_op(l, r, tuple_l, tuple_r, operator.lt)
122 check_op(l, r, tuple_l, tuple_r, operator.le)
123 check_op(l, r, tuple_l, tuple_r, operator.gt)
124 check_op(l, r, tuple_l, tuple_r, operator.ge)
125
126 check(1, 2, "x", "y", "z")
127
128 check(1, 2, "x", "y", "a")
129 check(1, 2, "x", "y", "zz")
130
131 check(1, 2, "x", "a", "z")
132 check(1, 2, "x", "zz", "z")
133
134 check(1, 2, "a", "y", "z")
135 check(1, 2, "zz", "y", "z")
136
137 check(1, -10, "x", "y", "z")
138 check(1, 10, "x", "y", "z")
139
140 check(-10, 2, "x", "y", "z")
141 check(10, 2, "x", "y", "z")
142
143 def test_repr(self):
144 self.assertEqual(repr(PlainData0()), "PlainData0()")
145 self.assertEqual(repr(PlainData1(1, 2, x="x", y="y")),
146 "PlainData1(a=1, b=2, x='x', y='y')")
147 self.assertEqual(repr(PlainData2(1, 2, x="x", y="y", z=3)),
148 "PlainData2(a=1, b=2, x='x', y='y', z=3)")
149 self.assertEqual(repr(PlainDataF2(1, 2, x="x", y="y", z=3)),
150 "PlainDataF2(a=1, b=2, x='x', y='y', z=3)")
151
152 def test_frozen(self):
153 not_frozen = PlainData0()
154 not_frozen.a = 1
155 frozen0 = PlainDataF0()
156 with self.assertRaises(AttributeError):
157 frozen0.a = 1
158 frozen1 = PlainDataF1(1, 2, x="x", y="y")
159 with self.assertRaises(FrozenPlainDataError):
160 frozen1.a = 1
161
162 def test_pickle(self):
163 def check(v):
164 with self.subTest(v=v):
165 self.assertEqual(v, pickle.loads(pickle.dumps(v)))
166
167 check(PlainData0())
168 check(PlainData1(a=1, b=2, x="x", y="y"))
169 check(PlainData2(a=1, b=2, x="x", y="y", z="z"))
170 check(PlainDataF0())
171 check(PlainDataF1(a=1, b=2, x="x", y="y"))
172 check(PlainDataF2(a=1, b=2, x="x", y="y", z="z"))
173
174
175 if __name__ == "__main__":
176 unittest.main()