|
7 | 7 | import unittest |
8 | 8 | from enum import IntEnum |
9 | 9 |
|
10 | | -from libdestruct import c_int, c_long, c_uint, inflater, struct, ptr, ptr_to_self, array_of, enum, enum_of |
| 10 | +from libdestruct import array, c_int, c_long, c_short, c_uint, inflater, struct, ptr, ptr_to_self, array_of, enum, enum_of |
11 | 11 |
|
12 | 12 |
|
13 | 13 | class StructMemberCollisionTest(unittest.TestCase): |
@@ -264,6 +264,96 @@ class TreeNode(struct): |
264 | 264 | self.assertEqual(node.data.value, 42) |
265 | 265 |
|
266 | 266 |
|
| 267 | +class SubscriptSyntaxTest(unittest.TestCase): |
| 268 | + """Test the subscript syntax: enum[T], array[T, N], ptr[T].""" |
| 269 | + |
| 270 | + def test_enum_subscript(self): |
| 271 | + """enum[MyEnum] works as a type annotation for struct fields.""" |
| 272 | + class Color(IntEnum): |
| 273 | + RED = 0 |
| 274 | + GREEN = 1 |
| 275 | + BLUE = 2 |
| 276 | + |
| 277 | + class s_t(struct): |
| 278 | + color: enum[Color] |
| 279 | + |
| 280 | + memory = (1).to_bytes(4, "little") |
| 281 | + s = s_t.from_bytes(memory) |
| 282 | + self.assertEqual(s.color.value, Color.GREEN) |
| 283 | + |
| 284 | + def test_enum_subscript_custom_backing(self): |
| 285 | + """enum[MyEnum, c_short] uses a custom backing type.""" |
| 286 | + class Status(IntEnum): |
| 287 | + OFF = 0 |
| 288 | + ON = 1 |
| 289 | + |
| 290 | + class s_t(struct): |
| 291 | + status: enum[Status, c_short] |
| 292 | + |
| 293 | + memory = (1).to_bytes(2, "little") |
| 294 | + s = s_t.from_bytes(memory) |
| 295 | + self.assertEqual(s.status.value, Status.ON) |
| 296 | + from libdestruct import size_of |
| 297 | + self.assertEqual(size_of(s_t), 2) |
| 298 | + |
| 299 | + def test_array_subscript(self): |
| 300 | + """array[c_int, 3] works as a type annotation for struct fields.""" |
| 301 | + class s_t(struct): |
| 302 | + data: array[c_int, 3] |
| 303 | + |
| 304 | + memory = b"" |
| 305 | + for v in [10, 20, 30]: |
| 306 | + memory += v.to_bytes(4, "little") |
| 307 | + |
| 308 | + s = s_t.from_bytes(memory) |
| 309 | + self.assertEqual(s.data[0].value, 10) |
| 310 | + self.assertEqual(s.data[1].value, 20) |
| 311 | + self.assertEqual(s.data[2].value, 30) |
| 312 | + |
| 313 | + def test_array_subscript_size(self): |
| 314 | + """array[c_int, 3] has correct size.""" |
| 315 | + class s_t(struct): |
| 316 | + data: array[c_int, 3] |
| 317 | + |
| 318 | + from libdestruct import size_of |
| 319 | + self.assertEqual(size_of(s_t), 12) |
| 320 | + |
| 321 | + def test_ptr_subscript(self): |
| 322 | + """ptr[T] works as a type annotation (already supported).""" |
| 323 | + class s_t(struct): |
| 324 | + val: c_int |
| 325 | + ref: ptr[c_int] |
| 326 | + |
| 327 | + memory = b"" |
| 328 | + memory += (42).to_bytes(4, "little") |
| 329 | + memory += (0).to_bytes(8, "little") |
| 330 | + |
| 331 | + s = s_t.from_bytes(memory) |
| 332 | + self.assertEqual(s.val.value, 42) |
| 333 | + |
| 334 | + def test_mixed_subscript_struct(self): |
| 335 | + """Struct mixing all subscript syntaxes.""" |
| 336 | + class Direction(IntEnum): |
| 337 | + UP = 0 |
| 338 | + DOWN = 1 |
| 339 | + |
| 340 | + class s_t(struct): |
| 341 | + dir: enum[Direction] |
| 342 | + coords: array[c_int, 2] |
| 343 | + next: ptr["s_t"] |
| 344 | + |
| 345 | + memory = b"" |
| 346 | + memory += (1).to_bytes(4, "little") # dir = DOWN |
| 347 | + memory += (10).to_bytes(4, "little") # coords[0] |
| 348 | + memory += (20).to_bytes(4, "little") # coords[1] |
| 349 | + memory += (0).to_bytes(8, "little") # next = null |
| 350 | + |
| 351 | + s = s_t.from_bytes(memory) |
| 352 | + self.assertEqual(s.dir.value, Direction.DOWN) |
| 353 | + self.assertEqual(s.coords[0].value, 10) |
| 354 | + self.assertEqual(s.coords[1].value, 20) |
| 355 | + |
| 356 | + |
267 | 357 | class StructEqualityTest(unittest.TestCase): |
268 | 358 | def test_struct_eq_non_struct_returns_not_implemented(self): |
269 | 359 | """struct.__eq__ returns NotImplemented for non-struct values.""" |
|
0 commit comments