from collections import OrderedDict import ctypes import math import struct import sys import unittest from drgn.type import ( ArrayType, BitFieldType, BoolType, EnumType, FloatType, FunctionType, IntType, PointerType, StructType, Type, TypedefType, UnionType, VoidType, ) def compound_type_dict_for_eq(type_): # Compare the result of the type thunks rather than the thunks themselves. d = dict(type_.__dict__) if d['_members'] is not None: d['_members'] = [ (name, offset, type_thunk()) for name, offset, type_thunk in d['_members'] ] del d['_members_by_name'] return d def enum_type_dict_for_eq(type_): d = dict(type_.__dict__) if d['enum'] is not None: d['enum'] = d['enum'].__members__ return d def type_eq(self, other): if not isinstance(other, self.__class__): return False if isinstance(self, (StructType, UnionType)): return compound_type_dict_for_eq(self) == compound_type_dict_for_eq(other) elif isinstance(self, EnumType): return enum_type_dict_for_eq(self) == enum_type_dict_for_eq(other) else: return self.__dict__ == other.__dict__ pointer_size = ctypes.sizeof(ctypes.c_void_p) point_type = StructType('point', 8, [ ('x', 0, lambda: IntType('int', 4, True)), ('y', 4, lambda: IntType('int', 4, True)), ]) anonymous_point_type = StructType(None, 8, [ ('x', 0, lambda: IntType('int', 4, True)), ('y', 4, lambda: IntType('int', 4, True)), ]) const_anonymous_point_type = StructType(None, 8, [ ('x', 0, lambda: IntType('int', 4, True)), ('y', 4, lambda: IntType('int', 4, True)), ], frozenset({'const'})) line_segment_type = StructType('line_segment', 16, [ ('a', 0, lambda: point_type), ('b', 8, lambda: point_type), ]) quadrilateral_type = StructType('quadrilateral', 16, [ ('points', 0, lambda: ArrayType(point_type, 4, pointer_size)), ]) class TypeTestCase(unittest.TestCase): def setUp(self): Type.__eq__ = type_eq def tearDown(self): del Type.__eq__ class TestType(TypeTestCase): def test_void(self): type_ = VoidType() self.assertEqual(str(type_), 'void') self.assertRaises(ValueError, type_.sizeof) self.assertRaises(ValueError, type_.read, b'') self.assertRaises(ValueError, type_.read_pretty, b'') self.assertFalse(type_.is_arithmetic()) self.assertFalse(type_.is_integer()) def test_int(self): type_ = IntType('int', 4, True) self.assertEqual(str(type_), 'int') self.assertEqual(type_.sizeof(), 4) buffer = (99).to_bytes(4, sys.byteorder) self.assertEqual(type_.read(buffer), 99) self.assertEqual(type_.read_pretty(buffer), '(int)99') self.assertEqual(type_.read_pretty(buffer, cast=False), '99') buffer = b'\0\0' + (-1).to_bytes(4, sys.byteorder, signed=True) self.assertEqual(type_.read(buffer, 2), -1) self.assertRaises(ValueError, type_.read, buffer, 3) self.assertEqual(type_.real_type(), type_) self.assertTrue(type_.is_arithmetic()) self.assertTrue(type_.is_integer()) type_ = IntType('unsigned long', 8, False) buffer = b'\0' + (99).to_bytes(8, sys.byteorder) self.assertEqual(type_.read(buffer, 1), 99) buffer = b'\xff\xff\xff' + (0xffffffffffffffff).to_bytes(8, sys.byteorder) self.assertEqual(type_.read(buffer, 3), 0xffffffffffffffff) def test_float(self): type_ = FloatType('double', 8) self.assertEqual(str(type_), 'double') self.assertEqual(type_.sizeof(), 8) buffer = struct.pack('d', 3.14) self.assertEqual(type_.read(buffer), 3.14) self.assertEqual(type_.read(b'\0' + buffer, 1), 3.14) self.assertRaises(ValueError, type_.read, buffer, 1) self.assertTrue(type_.is_arithmetic()) self.assertFalse(type_.is_integer()) type_ = FloatType('float', 4) buffer = struct.pack('f', 1.5) self.assertEqual(type_.read(buffer), 1.5) self.assertEqual(type_.read(b'\0\0\0' + buffer, 3), 1.5) self.assertRaises(ValueError, type_.read, b'') def test_bool(self): type_ = BoolType('_Bool', 1) self.assertEqual(str(type_), '_Bool') self.assertEqual(type_.sizeof(), 1) self.assertEqual(type_.read(b'\0'), 0) self.assertEqual(type_.read_pretty(b'\0'), '(_Bool)0') self.assertEqual(type_.read(b'\0\x01', 1), 1) self.assertEqual(type_.read_pretty(b'\x01'), '(_Bool)1') self.assertRaises(ValueError, type_.read, b'') self.assertRaises(ValueError, type_.read, b'\0', 1) def test_qualifiers(self): type_ = IntType('int', 4, True, {'const'}) self.assertEqual(str(type_), 'const int') self.assertEqual(type_.sizeof(), 4) self.assertEqual(type_.read(b'\0\0\0\0'), 0) type_.qualifiers.add('volatile') self.assertEqual(str(type_), 'const volatile int') self.assertEqual(type_.sizeof(), 4) def test_typedef(self): type_ = TypedefType('INT', IntType('int', 4, True)) self.assertEqual(str(type_), 'typedef int INT') self.assertEqual(type_.sizeof(), 4) self.assertEqual(type_.read(b'\0\0\0\0'), 0) self.assertEqual(type_.read_pretty(b'\0\0\0\0'), '(INT)0') self.assertTrue(type_.is_arithmetic()) self.assertTrue(type_.is_integer()) type_ = TypedefType('string', PointerType(pointer_size, IntType('char', 1, True))) self.assertEqual(str(type_), 'typedef char *string') self.assertEqual(type_.sizeof(), pointer_size) self.assertFalse(type_.is_arithmetic()) self.assertFalse(type_.is_integer()) type_ = TypedefType('CINT', IntType('int', 4, True, {'const'})) self.assertEqual(str(type_), 'typedef const int CINT') self.assertEqual(type_.sizeof(), 4) self.assertEqual(type_.read(b'\0\0\0\0'), 0) type_ = TypedefType('INT', IntType('int', 4, True), {'const'}) self.assertEqual(str(type_), 'const typedef int INT') self.assertEqual(type_.sizeof(), 4) self.assertEqual(type_.read(b'\0\0\0\0'), 0) type1 = TypedefType('INT', IntType('int', 4, True)) type2 = TypedefType('InT', type1) self.assertEqual(type1.real_type(), IntType('int', 4, True)) self.assertEqual(type2.real_type(), IntType('int', 4, True)) def test_struct(self): self.assertEqual(str(point_type), """\ struct point { int x; int y; }""") self.assertEqual(point_type.sizeof(), 8) self.assertEqual(point_type.members(), ['x', 'y']) self.assertEqual(point_type.offsetof('x'), 0) self.assertEqual(point_type.offsetof('y'), 4) self.assertEqual(point_type.typeof('x'), IntType('int', 4, True)) self.assertEqual(point_type.typeof('y'), IntType('int', 4, True)) buffer = ((99).to_bytes(4, sys.byteorder, signed=True) + (-1).to_bytes(4, sys.byteorder, signed=True)) self.assertEqual(point_type.read(buffer), OrderedDict([ ('x', 99), ('y', -1), ])) self.assertEqual(point_type.read(b'\0' + buffer, 1), OrderedDict([ ('x', 99), ('y', -1), ])) self.assertEqual(point_type.read_pretty(b'\0' + buffer, 1), """\ (struct point){ .x = (int)99, .y = (int)-1, }""") self.assertRaises(ValueError, point_type.read, buffer[:7]) self.assertRaises(ValueError, point_type.read, buffer, 1) self.assertEqual(str(line_segment_type), """\ struct line_segment { struct point a; struct point b; }""") self.assertEqual(line_segment_type.offsetof('a.x'), 0) self.assertEqual(line_segment_type.offsetof('a.y'), 4) self.assertEqual(line_segment_type.offsetof('b.x'), 8) self.assertEqual(line_segment_type.offsetof('b.y'), 12) self.assertRaisesRegex(ValueError, 'no member', line_segment_type.offsetof, 'c') self.assertRaisesRegex(ValueError, 'not a struct or union', line_segment_type.offsetof, 'a.x.z') self.assertRaisesRegex(ValueError, 'not an array', line_segment_type.offsetof, 'a[0]') self.assertEqual(str(quadrilateral_type), """\ struct quadrilateral { struct point points[4]; }""") for i in range(5): self.assertEqual(quadrilateral_type.offsetof(f'points[{i}].x'), 8 * i) self.assertEqual(quadrilateral_type.offsetof(f'points[{i}].y'), 8 * i + 4) self.assertEqual(str(anonymous_point_type), """\ struct { int x; int y; }""") type_ = StructType('line_segment', 16, [ (None, 0, lambda: const_anonymous_point_type), ('b', 8, lambda: const_anonymous_point_type), ], {'const', 'volatile'}) self.assertEqual(str(type_), """\ const volatile struct line_segment { const struct { int x; int y; }; const struct { int x; int y; } b; }""") type_ = StructType('foo', None, None) self.assertEqual(str(type_), 'struct foo') self.assertRaises(ValueError, type_.sizeof) type_ = StructType(None, 12, [ ('x', 0, lambda: IntType('int', 4, True)), (None, 4, lambda: StructType('point', 8, [ ('y', 0, lambda: IntType('int', 4, True)), ('z', 4, lambda: IntType('int', 4, True)), ])), ]) self.assertEqual(type_.members(), ['x', 'y', 'z']) self.assertEqual(type_.offsetof('x'), 0) self.assertEqual(type_.offsetof('y'), 4) self.assertEqual(type_.offsetof('z'), 8) self.assertEqual(type_.typeof('x'), IntType('int', 4, True)) self.assertEqual(type_.typeof('y'), IntType('int', 4, True)) self.assertEqual(type_.typeof('z'), IntType('int', 4, True)) type_ = StructType('foo', 0, []) self.assertEqual(type_.members(), []) self.assertEqual(type_.read_pretty(b''), '(struct foo){}') def test_bit_field(self): type_ = StructType(None, 8, [ ('x', 0, lambda: BitFieldType(IntType('int', 4, True), 0, 4)), ('y', 0, lambda: BitFieldType(IntType('int', 4, True, {'const'}), 4, 28)), ('z', 4, lambda: BitFieldType(IntType('int', 4, True), 0, 5)), ]) self.assertEqual(str(type_), """\ struct { int x : 4; const int y : 28; int z : 5; }""") buffer = b'\x07\x10\x5e\x5f\x1f\0\0\0' self.assertEqual(type_.typeof('x').read(buffer), 7) self.assertEqual(type_.typeof('x').read(b'\0' + buffer, 1), 7) self.assertRaises(ValueError, type_.typeof('x').read, b'') self.assertEqual(type_.typeof('y').read(buffer), 100000000) self.assertEqual(type_.typeof('y').read(b'\0\0\0' + buffer, 3), 100000000) self.assertRaises(ValueError, type_.typeof('y').read, buffer[:3]) self.assertEqual(type_.typeof('z').read(buffer, 4), -1) self.assertEqual(type_.typeof('z').read(b'\0\0' + buffer, 6), -1) self.assertRaises(ValueError, type_.typeof('z').read, buffer, 8) self.assertEqual(type_.read(buffer), OrderedDict([ ('x', 7), ('y', 100000000), ('z', -1), ])) self.assertEqual(type_.read_pretty(buffer), """\ { .x = (int)7, .y = (const int)100000000, .z = (int)-1, }""") type_ = BitFieldType(IntType('int', 4, True), 0, 4) self.assertEqual(str(type_), 'int : 4') self.assertRaises(ValueError, type_.type_name) self.assertTrue(type_.is_arithmetic()) def test_union(self): type_ = UnionType('value', 4, [ ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ]) self.assertEqual(str(type_), """\ union value { int i; float f; }""") self.assertEqual(type_.sizeof(), 4) buffer = b'\x00\x00\x80?' self.assertEqual(type_.read(buffer), OrderedDict([ ('i', 1065353216), ('f', 1.0), ])) self.assertEqual(type_.read(b'\0' + buffer, 1), OrderedDict([ ('i', 1065353216), ('f', 1.0), ])) self.assertEqual(type_.read_pretty(buffer), """\ (union value){ .i = (int)1065353216, .f = (float)1.0, }""") type_ = UnionType('value', 8, [ ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ('p', 0, lambda: point_type), ]) self.assertEqual(str(type_), """\ union value { int i; float f; struct point p; }""") type_ = UnionType('foo', None, None) self.assertEqual(str(type_), 'union foo') self.assertRaises(ValueError, type_.sizeof) def test_enum(self): type_ = EnumType('color', IntType('unsigned int', 4, False), [ ('RED', 0), ('GREEN', 1), ('BLUE', 2) ]) self.assertEqual(str(type_), """\ enum color { RED = 0, GREEN = 1, BLUE = 2, }""") self.assertEqual(type_.sizeof(), 4) buffer = (0).to_bytes(4, sys.byteorder) self.assertEqual(type_.read(buffer), type_.enum.RED) buffer = (1).to_bytes(4, sys.byteorder) self.assertEqual(type_.read(b'\0' + buffer, 1), type_.enum.GREEN) self.assertEqual(type_.read_pretty(b'\0' + buffer, 1), '(enum color)GREEN') buffer = (4).to_bytes(4, sys.byteorder) self.assertEqual(type_.read(b'\0\0\0' + buffer, 3), 4) self.assertEqual(type_.read_pretty(b'\0\0\0' + buffer, 3), '(enum color)4') self.assertRaises(ValueError, type_.read, buffer, 3) self.assertRaises(ValueError, type_.read, b'') type_.qualifiers = frozenset({'const'}) self.assertEqual(str(type_), """\ const enum color { RED = 0, GREEN = 1, BLUE = 2, }""") type_.qualifiers = frozenset({'const', 'volatile'}) self.assertEqual(str(type_), """\ const volatile enum color { RED = 0, GREEN = 1, BLUE = 2, }""") type_ = EnumType(None, IntType('int', 4, True), [ ('RED', 10), ('GREEN', 11), ('BLUE', -1) ]) self.assertEqual(str(type_), """\ enum { RED = 10, GREEN = 11, BLUE = -1, }""") buffer = (-1).to_bytes(4, sys.byteorder, signed=True) self.assertEqual(type_.read(buffer), -1) type_ = EnumType('foo', None, None) self.assertEqual(str(type_), 'enum foo') self.assertRaises(ValueError, type_.sizeof) def test_pointer(self): type_ = PointerType(pointer_size, IntType('int', 4, True)) self.assertEqual(str(type_), 'int *') self.assertEqual(type_.sizeof(), pointer_size) buffer = (0x7fffffff).to_bytes(pointer_size, sys.byteorder) self.assertEqual(type_.read(buffer), 0x7fffffff) self.assertEqual(type_.read(b'\0' + buffer, 1), 0x7fffffff) self.assertEqual(type_.read_pretty(b'\0' + buffer, 1), '(int *)0x7fffffff') type_ = PointerType(pointer_size, IntType('int', 4, True), {'const'}) self.assertEqual(str(type_), 'int * const') type_ = PointerType(pointer_size, point_type) self.assertEqual(str(type_), 'struct point *') type_ = PointerType(pointer_size, PointerType(pointer_size, IntType('int', 4, True))) self.assertEqual(str(type_), 'int **') type_ = PointerType(pointer_size, VoidType()) self.assertEqual(str(type_), 'void *') def test_array(self): type_ = ArrayType(IntType('int', 4, True), 2, pointer_size) self.assertEqual(str(type_), 'int [2]') self.assertEqual(type_.sizeof(), 8) buffer = ((99).to_bytes(4, sys.byteorder, signed=True) + (-1).to_bytes(4, sys.byteorder, signed=True)) self.assertEqual(type_.read(buffer), [99, -1]) self.assertEqual(type_.read(b'\0\0\0' + buffer, 3), [99, -1]) self.assertEqual(type_.read_pretty(b'\0\0\0' + buffer, 3), """\ (int [2]){ 99, -1, }""") buffer = ((99).to_bytes(4, sys.byteorder, signed=True) + (0).to_bytes(4, sys.byteorder, signed=True)) self.assertEqual(type_.read_pretty(b'\0\0\0' + buffer, 3), """\ (int [2]){ 99, }""") buffer = ((0).to_bytes(4, sys.byteorder, signed=True) + (-1).to_bytes(4, sys.byteorder, signed=True)) self.assertEqual(type_.read_pretty(b'\0\0\0' + buffer, 3), """\ (int [2]){ 0, -1, }""") self.assertRaises(ValueError, type_.read, buffer, 3) self.assertRaises(ValueError, type_.read_pretty, buffer, 3) type_ = ArrayType(ArrayType(IntType('int', 4, True), 3, pointer_size), 2, pointer_size) self.assertEqual(str(type_), 'int [2][3]') type_ = ArrayType(ArrayType(ArrayType(IntType('int', 4, True), 4, pointer_size), 3, pointer_size), 2, pointer_size) self.assertEqual(str(type_), 'int [2][3][4]') def test_char_array(self): type_ = ArrayType(IntType('char', 1, True), 4, pointer_size) self.assertEqual(type_.read_pretty(b'hello\0'), '(char [4])"hell"') self.assertEqual(type_.read_pretty(b'hi\0\0'), '(char [4])"hi"') type_ = ArrayType(IntType('char', 1, True), 8, pointer_size) self.assertEqual(type_.read_pretty(b'hello\0world\0'), '(char [8])"hello"') type_ = ArrayType(IntType('char', 1, True), 0, pointer_size) self.assertEqual(type_.read_pretty(b'hi\0'), '(char [0]){}') def test_array_with_empty_element(self): type_ = ArrayType(StructType('empty', 0, []), 2, pointer_size) self.assertEqual(str(type_), 'struct empty [2]') self.assertEqual(type_.sizeof(), 0) self.assertEqual(type_.read(b''), [OrderedDict(), OrderedDict()]) self.assertEqual(type_.read_pretty(b''), '(struct empty [2]){}') self.assertRaises(ValueError, type_.read_pretty, b'', 1) def test_incomplete_array(self): type_ = ArrayType(IntType('int', 4, True), None, pointer_size) self.assertEqual(str(type_), 'int []') self.assertRaises(ValueError, type_.sizeof) self.assertEqual(type_.read(b''), []) self.assertEqual(type_.read_pretty(b''), '(int []){}') type_ = ArrayType(ArrayType(IntType('int', 4, True), 2, pointer_size), None, pointer_size) self.assertEqual(str(type_), 'int [][2]') def test_array_of_structs(self): type_ = ArrayType(point_type, 2, pointer_size) self.assertEqual(str(type_), 'struct point [2]') self.assertEqual(type_.sizeof(), 16) buffer = ((1).to_bytes(4, sys.byteorder, signed=True) + (2).to_bytes(4, sys.byteorder, signed=True) + (3).to_bytes(4, sys.byteorder, signed=True) + (4).to_bytes(4, sys.byteorder, signed=True)) self.assertEqual(type_.read(buffer), [ OrderedDict([('x', 1), ('y', 2)]), OrderedDict([('x', 3), ('y', 4)]), ]) self.assertEqual(type_.read_pretty(buffer), """\ (struct point [2]){ { .x = (int)1, .y = (int)2, }, { .x = (int)3, .y = (int)4, }, }""") class TestConvert(unittest.TestCase): def test_void(self): self.assertIsNone(VoidType().convert(4)) def test_int(self): type_ = IntType('unsigned int', 4, False) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(4096), 4096) self.assertEqual(type_.convert(999999), 999999) self.assertEqual(type_.convert(2**32 - 1), 2**32 - 1) self.assertEqual(type_.convert(2**32 + 4), 4) self.assertEqual(type_.convert(-1), 2**32 - 1) self.assertEqual(type_.convert(-2 * 2**32), 0) self.assertEqual(type_.convert(-4 * 2**32 - 1), 2**32 - 1) self.assertEqual(type_.convert(-2**31), 2**31) self.assertEqual(type_.convert(1.5), 1) type_ = IntType('int', 4, True) self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(4096), 4096) self.assertEqual(type_.convert(999999), 999999) self.assertEqual(type_.convert(2**32 - 1), -1) self.assertEqual(type_.convert(2**32 + 4), 4) self.assertEqual(type_.convert(-1), -1) self.assertEqual(type_.convert(-2 * 2**32), 0) self.assertEqual(type_.convert(-4 * 2**32 - 1), -1) self.assertEqual(type_.convert(-2**31), -2**31) self.assertEqual(type_.convert(2**31), -2**31) self.assertEqual(type_.convert(2**31 - 1), 2**31 - 1) self.assertEqual(type_.convert(-1.5), -1) def test_bool(self): type_ = BoolType('_Bool', 1) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('') with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert([1, 2, 3]) self.assertEqual(type_.convert(0), False) self.assertEqual(type_.convert(1), True) self.assertEqual(type_.convert(-1), True) self.assertEqual(type_.convert(0.0), False) self.assertEqual(type_.convert(-0.0), False) self.assertEqual(type_.convert(-0.0), False) self.assertEqual(type_.convert(0.5), True) self.assertEqual(type_.convert(-0.5), True) self.assertEqual(type_.convert(float('nan')), True) def test_float(self): type_ = FloatType('double', 8) self.assertEqual(type_.convert(0.0), 0.0) self.assertEqual(type_.convert(0.5), 0.5) self.assertEqual(type_.convert(-0.5), -0.5) self.assertEqual(type_.convert(55), 55.0) self.assertEqual(type_.convert(float('inf')), float('inf')) self.assertEqual(type_.convert(float('-inf')), float('-inf')) self.assertTrue(math.isnan(type_.convert(float('nan')))) type_ = FloatType('float', 4) self.assertEqual(type_.convert(0.0), 0.0) self.assertEqual(type_.convert(0.5), 0.5) self.assertEqual(type_.convert(-0.5), -0.5) self.assertEqual(type_.convert(55), 55.0) self.assertEqual(type_.convert(float('inf')), float('inf')) self.assertEqual(type_.convert(float('-inf')), float('-inf')) self.assertTrue(math.isnan(type_.convert(float('nan')))) self.assertEqual(type_.convert(1e-50), 0.0) def test_bit_field(self): type_ = BitFieldType(IntType('unsigned int', 4, False), 0, 4) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(10), 10) self.assertEqual(type_.convert(15), 15) self.assertEqual(type_.convert(20), 4) self.assertEqual(type_.convert(-1), 15) self.assertEqual(type_.convert(32), 0) self.assertEqual(type_.convert(-17), 15) self.assertEqual(type_.convert(-8), 8) self.assertEqual(type_.convert(1.5), 1) type_ = BitFieldType(IntType('int', 4, True), 0, 4) self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(10), -6) self.assertEqual(type_.convert(15), -1) self.assertEqual(type_.convert(20), 4) self.assertEqual(type_.convert(-1), -1) self.assertEqual(type_.convert(32), 0) self.assertEqual(type_.convert(-17), -1) self.assertEqual(type_.convert(-8), -8) self.assertEqual(type_.convert(1.5), 1) def test_no_convert(self): union_type = UnionType('value', 4, [ ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ]) array_type = ArrayType(IntType('int', 4, True), 2, pointer_size) incomplete_array_type = ArrayType(IntType('int', 4, True), None, pointer_size) for type_ in [point_type, union_type, array_type, incomplete_array_type]: with self.subTest(type=type_): with self.assertRaisesRegex(TypeError, 'cannot convert'): point_type.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): point_type.convert({}) with self.assertRaisesRegex(TypeError, 'cannot convert'): point_type.convert(1) def test_enum(self): type_ = EnumType('color', IntType('unsigned int', 4, False), [ ('RED', 0), ('GREEN', 1), ('BLUE', 2) ]) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') self.assertEqual(type_.convert(1), type_.enum.GREEN) self.assertEqual(type_.convert(3), 3) self.assertEqual(type_.convert(-1), 2**32 - 1) self.assertEqual(type_.convert(0.1), type_.enum.RED) def test_typedef(self): type_ = TypedefType('u32', IntType('unsigned int', 4, False)) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(2**32 - 1), 2**32 - 1) self.assertEqual(type_.convert(-1), 2**32 - 1) def test_pointer(self): type_ = PointerType(8, VoidType()) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(None) with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert('0') with self.assertRaisesRegex(TypeError, 'cannot convert'): type_.convert(0.0) self.assertEqual(type_.convert(0), 0) self.assertEqual(type_.convert(0xffffffff93000000), 0xffffffff93000000) self.assertEqual(type_.convert(2**64 - 1), 2**64 - 1) self.assertEqual(type_.convert(-1), 2**64 - 1) self.assertEqual(type_.convert(2**64 + 1), 1) class TestOperandType(TypeTestCase): def assertOperandType(self, type_, expected): for i in range(2): type_ = type_.operand_type() self.assertEqual(type_, expected) def test_void(self): self.assertOperandType(VoidType(frozenset({'const'})), VoidType()) def test_int(self): self.assertOperandType(IntType('int', 4, True, frozenset({'const'})), IntType('int', 4, True)) def test_bool(self): self.assertOperandType(BoolType('_Bool', 1, frozenset({'const'})), BoolType('_Bool', 1)) def test_float(self): self.assertOperandType(FloatType('double', 8, frozenset({'const'})), FloatType('double', 8)) def test_bit_field(self): self.assertOperandType(BitFieldType(IntType('int', 4, True, frozenset({'const'})), 0, 4), BitFieldType(IntType('int', 4, True), 0, 4)) def test_struct(self): const_point_type = StructType('point', 8, [ ('x', 0, lambda: IntType('int', 4, True)), ('y', 4, lambda: IntType('int', 4, True)), ], frozenset({'const'})) self.assertOperandType(const_point_type, point_type) def test_union(self): union_type = UnionType('value', 4, [ ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ]) const_union_type = UnionType('value', 4, [ ('i', 0, lambda: IntType('int', 4, True)), ('f', 0, lambda: FloatType('float', 4)), ], frozenset({'const'})) self.assertOperandType(const_union_type, union_type) def test_enum(self): enum_type = EnumType(None, IntType('int', 4, True), [ ('RED', 10), ('GREEN', 11), ('BLUE', -1) ]) const_enum_type = EnumType(None, IntType('int', 4, True), [ ('RED', 10), ('GREEN', 11), ('BLUE', -1) ], frozenset({'const'})) self.assertOperandType(const_enum_type, enum_type) def test_typedef(self): const_typedef_type = TypedefType( 'u32', IntType('unsigned int', 4, False), frozenset({'const'})) typedef_const_type = TypedefType('u32', IntType('unsigned int', 4, False, frozenset({'const'}))) const_typedef_const_type = TypedefType( 'u32', IntType('unsigned int', 4, False, frozenset({'const'})), frozenset({'const'})) typedef_type = TypedefType('u32', IntType('unsigned int', 4, False)) self.assertOperandType(const_typedef_type, typedef_type) self.assertOperandType(typedef_const_type, IntType('unsigned int', 4, False)) self.assertOperandType(const_typedef_const_type, IntType('unsigned int', 4, False)) def test_pointer(self): const_pointer_type = PointerType( 8, IntType('unsigned int', 4, False), frozenset({'const'})) pointer_type = PointerType(8, IntType('unsigned int', 4, False)) self.assertOperandType(const_pointer_type, pointer_type) const_pointer_const_type = PointerType( 8, IntType('unsigned int', 4, False, frozenset({'const'})), frozenset({'const'})) pointer_const_type = PointerType(8, IntType('unsigned int', 4, False, frozenset({'const'}))) self.assertOperandType(const_pointer_const_type, pointer_const_type) def test_array(self): type_ = ArrayType(IntType('int', 4, True), 2, pointer_size) self.assertOperandType(type_, PointerType(pointer_size, type_.type)) typedef_type = TypedefType('pair_t', type_) self.assertOperandType(typedef_type, PointerType(pointer_size, type_.type)) def test_function(self): type_ = FunctionType(pointer_size, VoidType, []) self.assertOperandType(type_, PointerType(pointer_size, type_)) typedef_type = TypedefType('callback_t', type_) self.assertOperandType(typedef_type, PointerType(pointer_size, type_))