| | |
| | from __future__ import absolute_import |
| | from __future__ import print_function |
| | from __future__ import unicode_literals |
| | from io import BytesIO |
| | from unittest import TestCase |
| | import sys |
| |
|
| | from six import add_metaclass |
| |
|
| | from hwp5.bintype import read_type |
| | from hwp5.dataio import ARRAY, N_ARRAY |
| | from hwp5.dataio import BSTR |
| | from hwp5.dataio import BYTE |
| | from hwp5.dataio import Enum |
| | from hwp5.dataio import EnumType |
| | from hwp5.dataio import Flags |
| | from hwp5.dataio import INT8 |
| | from hwp5.dataio import INT16 |
| | from hwp5.dataio import INT32 |
| | from hwp5.dataio import UINT8 |
| | from hwp5.dataio import UINT16 |
| | from hwp5.dataio import UINT32 |
| | from hwp5.dataio import ParseError |
| | from hwp5.dataio import Struct |
| | from hwp5.dataio import StructType |
| | from hwp5.dataio import decode_utf16le_with_hypua |
| | from hwp5.dataio import typed_struct_attributes |
| | from hwp5.dataio import _parse_flags_args |
| |
|
| |
|
| | PY3 = sys.version_info.major == 3 |
| | if PY3: |
| | long = int |
| | unicode = str |
| |
|
| |
|
| | class TestArray(TestCase): |
| | def test_new(self): |
| | t1 = ARRAY(INT32, 3) |
| | t2 = ARRAY(INT32, 3) |
| | assert t1 is t2 |
| |
|
| | assert N_ARRAY(INT32, INT32) is N_ARRAY(INT32, INT32) |
| |
|
| | def test_BSTR(self): |
| | assert type(BSTR(u'abc')) is unicode |
| |
|
| | def test_hello(self): |
| | assert INT32.basetype is int |
| |
|
| | def test_slots(self): |
| | a = INT32() |
| | self.assertRaises(Exception, setattr, a, 'randomattr', 1) |
| |
|
| |
|
| | class TestTypedAttributes(TestCase): |
| |
|
| | def test_typed_struct_attributes(self): |
| |
|
| | class SomeRandomStruct(Struct): |
| | @staticmethod |
| | def attributes(): |
| | yield INT32, 'a' |
| | yield BSTR, 'b' |
| | yield ARRAY(INT32, 3), 'c' |
| |
|
| | attributes = dict(a=1, b=u'abc', c=(4, 5, 6)) |
| | typed_attributes = typed_struct_attributes( |
| | SomeRandomStruct, attributes, dict() |
| | ) |
| | typed_attributes = list(typed_attributes) |
| | expected = [dict(name='a', type=INT32, value=1), |
| | dict(name='b', type=BSTR, value='abc'), |
| | dict(name='c', type=ARRAY(INT32, 3), value=(4, 5, 6))] |
| | self.assertEqual(expected, typed_attributes) |
| |
|
| | def test_typed_struct_attributes_inherited(self): |
| |
|
| | class Hello(Struct): |
| | @staticmethod |
| | def attributes(): |
| | yield INT32, 'a' |
| |
|
| | class Hoho(Hello): |
| | @staticmethod |
| | def attributes(): |
| | yield BSTR, 'b' |
| |
|
| | attributes = dict(a=1, b=u'abc', c=(2, 2)) |
| | result = typed_struct_attributes(Hoho, attributes, dict()) |
| | result = list(result) |
| | expected = [dict(name='a', type=INT32, value=1), |
| | dict(name='b', type=BSTR, value='abc'), |
| | dict(name='c', type=tuple, value=(2, 2))] |
| | self.assertEqual(expected, result) |
| |
|
| |
|
| | class TestStructType(TestCase): |
| | def test_assign_enum_flags_name(self): |
| |
|
| | @add_metaclass(StructType) |
| | class Foo(object): |
| | bar = Enum() |
| | baz = Flags(UINT16) |
| | self.assertEqual('bar', Foo.bar.__name__) |
| | self.assertEqual(Foo, Foo.bar.scoping_struct) |
| | self.assertEqual('baz', Foo.baz.__name__) |
| |
|
| | def test_parse_members(self): |
| |
|
| | @add_metaclass(StructType) |
| | class A(object): |
| |
|
| | @classmethod |
| | def attributes(cls): |
| | yield UINT8, 'uint8' |
| | yield UINT16, 'uint16' |
| | yield UINT32, 'uint32' |
| |
|
| | values = dict(uint8=8, uint16=16, uint32=32) |
| |
|
| | def getvalue(member): |
| | return values[member['name']] |
| |
|
| | context = dict() |
| | result = list(A.parse_members(context, getvalue)) |
| | self.assertEqual([dict(name='uint8', type=UINT8, value=8), |
| | dict(name='uint16', type=UINT16, value=16), |
| | dict(name='uint32', type=UINT32, value=32)], result) |
| |
|
| | def test_parse_members_condition(self): |
| |
|
| | def uint32_is_32(context, values): |
| | return values['uint32'] == 32 |
| |
|
| | @add_metaclass(StructType) |
| | class A(object): |
| |
|
| | @classmethod |
| | def attributes(cls): |
| | yield UINT8, 'uint8' |
| | yield UINT16, 'uint16' |
| | yield UINT32, 'uint32' |
| | yield dict(type=UINT32, name='extra', condition=uint32_is_32) |
| |
|
| | values = dict(uint8=8, uint16=16, uint32=32, extra=666) |
| |
|
| | def getvalue(member): |
| | return values[member['name']] |
| |
|
| | context = dict() |
| | result = list(A.parse_members(context, getvalue)) |
| | self.assertEqual([dict(name='uint8', type=UINT8, value=8), |
| | dict(name='uint16', type=UINT16, value=16), |
| | dict(name='uint32', type=UINT32, value=32), |
| | dict(name='extra', type=UINT32, value=666, |
| | condition=uint32_is_32)], |
| | result) |
| |
|
| | def test_parse_members_empty(self): |
| |
|
| | @add_metaclass(StructType) |
| | class A(object): |
| | pass |
| |
|
| | value = dict() |
| |
|
| | def getvalue(member): |
| | return value[member['name']] |
| |
|
| | context = dict() |
| | result = list(A.parse_members_with_inherited(context, getvalue)) |
| | self.assertEqual([], result) |
| |
|
| | def test_parse_members_inherited(self): |
| |
|
| | @add_metaclass(StructType) |
| | class A(object): |
| |
|
| | @classmethod |
| | def attributes(cls): |
| | yield UINT8, 'uint8' |
| | yield UINT16, 'uint16' |
| | yield UINT32, 'uint32' |
| |
|
| | class B(A): |
| | @classmethod |
| | def attributes(cls): |
| | yield INT8, 'int8' |
| | yield INT16, 'int16' |
| | yield INT32, 'int32' |
| |
|
| | value = dict(uint8=8, uint16=16, uint32=32, |
| | int8=-1, int16=-16, int32=-32) |
| |
|
| | def getvalue(member): |
| | return value[member['name']] |
| |
|
| | context = dict() |
| | result = list(B.parse_members_with_inherited(context, getvalue)) |
| | self.assertEqual([dict(name='uint8', type=UINT8, value=8), |
| | dict(name='uint16', type=UINT16, value=16), |
| | dict(name='uint32', type=UINT32, value=32), |
| | dict(name='int8', type=INT8, value=-1), |
| | dict(name='int16', type=INT16, value=-16), |
| | dict(name='int32', type=INT32, value=-32)], |
| | result) |
| |
|
| |
|
| | class TestEnumType(TestCase): |
| | def test_enum(self): |
| | Foo = EnumType( |
| | str('Foo'), |
| | (int,), |
| | dict(items=['a', 'b', 'c'], moreitems=dict(d=1, e=4)) |
| | ) |
| |
|
| | self.assertRaises(AttributeError, getattr, Foo, 'items') |
| | self.assertRaises(AttributeError, getattr, Foo, 'moreitems') |
| |
|
| | |
| | self.assertEqual(0, Foo.a) |
| | self.assertEqual(1, Foo.b) |
| | self.assertEqual(2, Foo.c) |
| | self.assertEqual(1, Foo.d) |
| | self.assertEqual(4, Foo.e) |
| | self.assertTrue(isinstance(Foo.a, Foo)) |
| |
|
| | |
| | self.assertTrue(Foo(0) is Foo(0)) |
| | self.assertTrue(Foo(0) is Foo.a) |
| |
|
| | |
| | self.assertTrue(Foo(0) is not 0) |
| |
|
| | |
| | self.assertEqual('a', Foo.a.name) |
| | self.assertEqual('b', Foo.b.name) |
| |
|
| | |
| | self.assertEqual('b', Foo.d.name) |
| | self.assertTrue(Foo.b is Foo.d) |
| |
|
| | |
| | self.assertEqual('Foo.a', repr(Foo(0))) |
| | self.assertEqual('Foo.b', repr(Foo(1))) |
| | self.assertEqual('Foo.e', repr(Foo(4))) |
| |
|
| | |
| | self.assertRaises(AttributeError, setattr, Foo(0), 'bar', 0) |
| | if sys.platform.startswith('java'): |
| | self.assertRaises(TypeError, setattr, Foo(0), 'name', 'a') |
| | else: |
| | self.assertRaises(AttributeError, setattr, Foo(0), 'name', 'a') |
| |
|
| | |
| | |
| |
|
| | |
| | undefined = Foo(5) |
| | self.assertTrue(isinstance(undefined, Foo)) |
| | self.assertEqual(None, undefined.name) |
| | self.assertEqual('Foo(5)', repr(undefined)) |
| |
|
| | |
| | self.assertRaises(TypeError, Foo, 5, 'f') |
| |
|
| | |
| | self.assertRaises(Exception, Enum, 'a', a=1) |
| |
|
| |
|
| | class TestFlags(TestCase): |
| | def test_parse_args(self): |
| | x = list(_parse_flags_args([0, 1, long, 'bit01'])) |
| | bit01 = ('bit01', (0, 1, long)) |
| | self.assertEqual([bit01], x) |
| |
|
| | x = list(_parse_flags_args([2, 3, 'bit23'])) |
| | bit23 = ('bit23', (2, 3, int)) |
| | self.assertEqual([bit23], x) |
| |
|
| | x = list(_parse_flags_args([4, long, 'bit4'])) |
| | bit4 = ('bit4', (4, 4, long)) |
| | self.assertEqual([bit4], x) |
| |
|
| | x = list(_parse_flags_args([5, 'bit5'])) |
| | bit5 = ('bit5', (5, 5, int)) |
| |
|
| | x = list(_parse_flags_args([0, 1, long, 'bit01', |
| | 2, 3, 'bit23', |
| | 4, long, 'bit4', |
| | 5, 'bit5'])) |
| | self.assertEqual([bit01, bit23, bit4, bit5], x) |
| |
|
| | def test_basetype(self): |
| | MyFlags = Flags(UINT32) |
| | self.assertEqual(UINT32, MyFlags.basetype) |
| |
|
| | def test_bitfields(self): |
| | MyEnum = Enum(a=1, b=2) |
| | MyFlags = Flags( |
| | UINT32, |
| | 0, 1, 'field0', |
| | 2, 4, MyEnum, 'field2' |
| | ) |
| | bitfields = MyFlags.bitfields |
| | f = bitfields['field0'] |
| | self.assertEqual((0, 1, int), |
| | (f.lsb, f.msb, f.valuetype)) |
| | f = bitfields['field2'] |
| | self.assertEqual((2, 4, MyEnum), |
| | (f.lsb, f.msb, f.valuetype)) |
| |
|
| | @property |
| | def ByteFlags(self): |
| | return Flags(BYTE, |
| | 0, 3, 'low', |
| | 4, 7, 'high') |
| |
|
| | def test_dictvalue(self): |
| | flags = self.ByteFlags(0xf0) |
| | self.assertEqual(dict(low=0, high=0xf), |
| | flags.dictvalue()) |
| |
|
| |
|
| | class TestReadStruct(TestCase): |
| |
|
| | def test_read_parse_error(self): |
| |
|
| | class Foo(Struct): |
| |
|
| | def attributes(): |
| | yield INT16, 'a' |
| | attributes = staticmethod(attributes) |
| |
|
| | stream = BytesIO() |
| |
|
| | record = dict() |
| | context = dict(record=record) |
| | try: |
| | read_type(Foo, context, stream) |
| | assert False, 'ParseError expected' |
| | except ParseError as e: |
| | self.assertEqual(Foo, e.binevents[0][1]['type']) |
| | self.assertEqual('a', e.binevents[-1][1]['name']) |
| | self.assertEqual(0, e.offset) |
| |
|
| |
|
| | class TestBSTR(TestCase): |
| |
|
| | def test_read(self): |
| | f = BytesIO(b'\x03\x00' + u'가나다'.encode('utf-16le')) |
| |
|
| | s = BSTR.read(f) |
| | self.assertEqual(u'가나다', s) |
| |
|
| | pua = u'\ub098\ub78f\u302e\ub9d0\u302f\uebd4\ubbf8\u302e' |
| | pua_utf16le = pua.encode('utf-16le') |
| | if PY3: |
| | lengthbyte = bytes([len(pua)]) |
| | else: |
| | lengthbyte = chr(len(pua)) |
| | f = BytesIO(lengthbyte + b'\x00' + pua_utf16le) |
| |
|
| | jamo = BSTR.read(f) |
| | expected = u'\ub098\ub78f\u302e\ub9d0\u302f\uebd4\ubbf8\u302e' |
| | self.assertEqual(expected, jamo) |
| |
|
| |
|
| | class TestDecodeUTF16LEPUA(TestCase): |
| |
|
| | def test_decode(self): |
| | expected = u'가나다' |
| | bytes = expected.encode('utf-16le') |
| | u = decode_utf16le_with_hypua(bytes) |
| | self.assertEqual(expected, u) |
| |
|