diff options
Diffstat (limited to 'tests/unit/test_bitwise.py')
| -rw-r--r-- | tests/unit/test_bitwise.py | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/tests/unit/test_bitwise.py b/tests/unit/test_bitwise.py new file mode 100644 index 0000000..2b674e8 --- /dev/null +++ b/tests/unit/test_bitwise.py @@ -0,0 +1,341 @@ +# Copyright 2013 Dan Smith <dsmith@danplanet.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from builtins import bytes + +import struct +import unittest + +import six + +from chirp import bitwise +from chirp import memmap + + +class BaseTest(unittest.TestCase): + def _compare_structure(self, obj, primitive): + for key, value in primitive.items(): + if isinstance(value, dict): + self._compare_structure(getattr(obj, key), value) + else: + self.assertEqual(type(value)(getattr(obj, key)), value) + + +class TestMemoryMapCoherence(BaseTest): + def test_byte_char_coherence(self): + charmmap = memmap.MemoryMap('00') + # This will to a get_byte_compatible() from chars + obj = bitwise.parse('char foo[2];', charmmap) + self.assertEqual('00', str(obj.foo)) + obj.foo = '11' + # The above assignment happens on the byte-compatible mmap, + # make sure it is still visible in the charmmap we know about. + # This confirms that get_byte_compatible() links the backing + # store of the original mmap to the new one. + self.assertEqual('11', charmmap.get_packed()) + + +class TestBitwiseBaseIntTypes(BaseTest): + def _test_type(self, datatype, _data, value): + data = memmap.MemoryMapBytes(bytes(_data)) + obj = bitwise.parse("%s foo;" % datatype, data) + self.assertEqual(int(obj.foo), value) + self.assertEqual(obj.foo.size(), len(data) * 8) + + obj.foo = 0 + self.assertEqual(int(obj.foo), 0) + self.assertEqual(data.get_packed(), (b"\x00" * (obj.size() // 8))) + + obj.foo = value + self.assertEqual(int(obj.foo), value) + self.assertEqual(data.get_packed(), _data) + + obj.foo = 7 + # Compare against the equivalent real division so we get consistent + # results on py2 and py3 + self.assertEqual(7 // 2, obj.foo // 2) + self.assertEqual(7 / 2, obj.foo / 2) + self.assertEqual(7 / 2.0, obj.foo / 2.0) + + def test_type_u8(self): + self._test_type("u8", b"\x80", 128) + + def test_type_u16(self): + self._test_type("u16", b"\x01\x00", 256) + + def test_type_u24(self): + self._test_type("u24", b"\x80\x00\x00", 2**23) + + def test_type_u32(self): + self._test_type("u32", b"\x80\x00\x00\x00", 2**31) + + def test_type_ul16(self): + self._test_type("ul16", b"\x00\x01", 256) + + def test_type_ul24(self): + self._test_type("ul24", b"\x00\x00\x80", 2**23) + + def test_type_ul32(self): + self._test_type("ul32", b"\x00\x00\x00\x80", 2**31) + + def test_int_array(self): + data = memmap.MemoryMapBytes(bytes(b'\x00\x01\x02\x03')) + obj = bitwise.parse('u8 foo[4];', data) + for i in range(4): + self.assertEqual(i, obj.foo[i]) + obj.foo[i] = i * 2 + self.assertEqual(b'\x00\x02\x04\x06', data.get_packed()) + + def test_int_array(self): + data = memmap.MemoryMapBytes(bytes(b'\x00\x01\x02\x03')) + obj = bitwise.parse('u8 foo[4];', data) + for i in range(4): + self.assertEqual(i, obj.foo[i]) + obj.foo[i] = i * 2 + self.assertEqual(b'\x00\x02\x04\x06', data.get_packed()) + + +class TestBitfieldTypes(BaseTest): + def test_bitfield_u8(self): + defn = "u8 foo:4, bar:4;" + data = memmap.MemoryMapBytes(bytes(b"\x12")) + obj = bitwise.parse(defn, data) + self.assertEqual(obj.foo, 1) + self.assertEqual(obj.bar, 2) + self.assertEqual(obj.foo.size(), 4) + self.assertEqual(obj.bar.size(), 4) + obj.foo = 0x8 + obj.bar = 0x1 + self.assertEqual(data.get_packed(), b"\x81") + + def _test_bitfield_16(self, variant, data): + defn = "u%s16 foo:4, bar:8, baz:4;" % variant + data = memmap.MemoryMapBytes(bytes(data)) + obj = bitwise.parse(defn, data) + self.assertEqual(int(obj.foo), 1) + self.assertEqual(int(obj.bar), 0x23) + self.assertEqual(int(obj.baz), 4) + self.assertEqual(obj.foo.size(), 4) + self.assertEqual(obj.bar.size(), 8) + self.assertEqual(obj.baz.size(), 4) + obj.foo = 0x2 + obj.bar = 0x11 + obj.baz = 0x3 + if variant == "l": + self.assertEqual(data.get_packed(), b"\x13\x21") + else: + self.assertEqual(data.get_packed(), b"\x21\x13") + + def test_bitfield_u16(self): + self._test_bitfield_16("", b"\x12\x34") + + def test_bitfield_ul16(self): + self._test_bitfield_16('l', b"\x34\x12") + + def _test_bitfield_24(self, variant, data): + defn = "u%s24 foo:12, bar:6, baz:6;" % variant + data = memmap.MemoryMapBytes(bytes(data)) + obj = bitwise.parse(defn, data) + self.assertEqual(int(obj.foo), 4) + self.assertEqual(int(obj.bar), 3) + self.assertEqual(int(obj.baz), 2) + self.assertEqual(obj.foo.size(), 12) + self.assertEqual(obj.bar.size(), 6) + self.assertEqual(obj.baz.size(), 6) + obj.foo = 1 + obj.bar = 2 + obj.baz = 3 + if variant == 'l': + self.assertEqual(data.get_packed(), b"\x83\x10\x00") + else: + self.assertEqual(data.get_packed(), b"\x00\x10\x83") + + def test_bitfield_u24(self): + self._test_bitfield_24("", b"\x00\x40\xC2") + + def test_bitfield_ul24(self): + self._test_bitfield_24("l", b"\xC2\x40\x00") + + +class TestBitType(BaseTest): + def test_bit_array(self): + defn = "bit foo[24];" + data = memmap.MemoryMapBytes(bytes(b"\x00\x80\x01")) + obj = bitwise.parse(defn, data) + for i, v in [(0, False), (8, True), (23, True)]: + self.assertEqual(bool(obj.foo[i]), v) + for i in range(0, 24): + obj.foo[i] = i % 2 + self.assertEqual(data.get_packed(), b"\x55\x55\x55") + + def test_bit_array_fail(self): + self.assertRaises(ValueError, bitwise.parse, "bit foo[23];", b"000") + + +class TestBitwiseBCDTypes(BaseTest): + def _test_def(self, definition, name, _data, value): + data = memmap.MemoryMapBytes(bytes(_data)) + obj = bitwise.parse(definition, data) + self.assertEqual(int(getattr(obj, name)), value) + self.assertEqual(getattr(obj, name).size(), len(_data) * 8) + setattr(obj, name, 0) + self.assertEqual(data.get_packed(), (b"\x00" * len(_data))) + setattr(obj, name, 42) + if definition.startswith("b"): + expected = (len(_data) == 2 and b"\x00" or b"") + b"\x42" + else: + expected = b"\x42" + (len(_data) == 2 and b"\x00" or b"") + raw = data.get_packed() + self.assertEqual(raw, expected) + + def test_bbcd(self): + self._test_def("bbcd foo;", "foo", b"\x12", 12) + + def test_lbcd(self): + self._test_def("lbcd foo;", "foo", b"\x12", 12) + + def test_bbcd_array(self): + self._test_def("bbcd foo[2];", "foo", b"\x12\x34", 1234) + + def test_lbcd_array(self): + self._test_def("lbcd foo[2];", "foo", b"\x12\x34", 3412) + + +class TestBitwiseCharTypes(BaseTest): + def test_char(self): + data = memmap.MemoryMapBytes(bytes(b"c")) + obj = bitwise.parse("char foo;", data) + self.assertEqual(str(obj.foo), "c") + self.assertEqual(obj.foo.size(), 8) + obj.foo = "d" + self.assertEqual(data.get_packed(), b"d") + + def test_string(self): + data = memmap.MemoryMapBytes(bytes(b"foobar")) + obj = bitwise.parse("char foo[6];", data) + self.assertEqual(str(obj.foo), "foobar") + self.assertEqual(obj.foo.size(), 8 * 6) + obj.foo = "bazfoo" + self.assertEqual(data.get_packed(), b"bazfoo") + + def test_string_invalid_chars(self): + data = memmap.MemoryMapBytes(bytes(b"\xFFoobar1")) + obj = bitwise.parse("struct {char foo[7];} bar;", data) + + if six.PY3: + expected = '\xffoobar1' + else: + expected = '\\xffoobar1' + + self.assertIn(expected, repr(obj.bar)) + + def test_string_wrong_length(self): + data = memmap.MemoryMapBytes(bytes(b"foobar")) + obj = bitwise.parse("char foo[6];", data) + self.assertRaises(ValueError, setattr, obj, "foo", "bazfo") + self.assertRaises(ValueError, setattr, obj, "foo", "bazfooo") + + def test_string_with_various_input_types(self): + data = memmap.MemoryMapBytes(bytes(b"foobar")) + obj = bitwise.parse("char foo[6];", data) + self.assertEqual('foobar', str(obj.foo)) + self.assertEqual(6, len(b'barfoo')) + obj.foo = b'barfoo' + self.assertEqual('barfoo', str(obj.foo)) + obj.foo = [ord(c) for c in 'fffbbb'] + self.assertEqual('fffbbb', str(obj.foo)) + + def test_string_get_raw(self): + data = memmap.MemoryMapBytes(bytes(b"foobar")) + obj = bitwise.parse("char foo[6];", data) + self.assertEqual('foobar', obj.foo.get_raw()) + self.assertEqual(b'foobar', obj.foo.get_raw(asbytes=True)) + + +class TestBitwiseStructTypes(BaseTest): + def _test_def(self, definition, data, primitive): + obj = bitwise.parse(definition, data) + self._compare_structure(obj, primitive) + self.assertEqual(obj.size(), len(data) * 8) + + def test_struct_one_element(self): + defn = "struct { u8 bar; } foo;" + value = {"foo": {"bar": 128}} + self._test_def(defn, b"\x80", value) + + def test_struct_two_elements(self): + defn = "struct { u8 bar; u16 baz; } foo;" + value = {"foo": {"bar": 128, "baz": 256}} + self._test_def(defn, b"\x80\x01\x00", value) + + def test_struct_writes(self): + data = memmap.MemoryMapBytes(bytes(b"..")) + defn = "struct { u8 bar; u8 baz; } foo;" + obj = bitwise.parse(defn, data) + obj.foo.bar = 0x12 + obj.foo.baz = 0x34 + self.assertEqual(data.get_packed(), b"\x12\x34") + + def test_struct_get_raw(self): + data = memmap.MemoryMapBytes(bytes(b"..")) + defn = "struct { u8 bar; u8 baz; } foo;" + obj = bitwise.parse(defn, data) + self.assertEqual('..', obj.get_raw()) + self.assertEqual(b'..', obj.get_raw(asbytes=True)) + + def test_struct_get_raw_small(self): + data = memmap.MemoryMapBytes(bytes(b".")) + defn = "struct { u8 bar; } foo;" + obj = bitwise.parse(defn, data) + self.assertEqual('.', obj.get_raw()) + self.assertEqual(b'.', obj.get_raw(asbytes=True)) + + +class TestBitwiseSeek(BaseTest): + def test_seekto(self): + defn = "#seekto 4; char foo;" + obj = bitwise.parse(defn, b"abcdZ") + self.assertEqual(str(obj.foo), "Z") + + def test_seek(self): + defn = "char foo; #seek 3; char bar;" + obj = bitwise.parse(defn, b"AbcdZ") + self.assertEqual(str(obj.foo), "A") + self.assertEqual(str(obj.bar), "Z") + + +class TestBitwiseErrors(BaseTest): + def test_missing_semicolon(self): + self.assertRaises(SyntaxError, bitwise.parse, "u8 foo", "") + + +class TestBitwiseComments(BaseTest): + def test_comment_inline_cppstyle(self): + obj = bitwise.parse('u8 foo; // test', b'\x10') + self.assertEqual(16, obj.foo) + + def test_comment_cppstyle(self): + obj = bitwise.parse('// Test this\nu8 foo;', b'\x10') + self.assertEqual(16, obj.foo) + + +class TestBitwiseStringEncoders(BaseTest): + def test_encode_bytes(self): + self.assertEqual(b'foobar\x00', + bitwise.string_straight_encode('foobar\x00')) + + def test_decode_bytes(self): + self.assertEqual('foobar\x00', + bitwise.string_straight_decode(b'foobar\x00')) |
