"""
Test cases for record.py
"""
import random
from record import Record, Integer, Int255String
class SingleSignedByte(Record):
__format__ = [('a', Integer(8, True))]
EXPECTED_ENCODED_SIZE = 1
class SingleUnsignedByte(Record):
__format__ = [('a', Integer(8, False))]
EXPECTED_ENCODED_SIZE = 1
class SingleSignedShort(Record):
__format__ = [('a', Integer(16, True))]
EXPECTED_ENCODED_SIZE = 2
class SingleUnsignedShort(Record):
__format__ = [('a', Integer(16, False))]
EXPECTED_ENCODED_SIZE = 2
class SingleSignedLong(Record):
__format__ = [('a', Integer(32, True))]
EXPECTED_ENCODED_SIZE = 4
class SingleUnsignedLong(Record):
__format__ = [('a', Integer(32, False))]
EXPECTED_ENCODED_SIZE = 4
class MultiByte(Record):
__format__ = [('a', Integer(8, True)),
('b', Integer(8, False))]
EXPECTED_ENCODED_SIZE = 2
class MultiType(Record):
__format__ = [('a', Integer(16, True)),
('b', Integer(8, True))]
EXPECTED_ENCODED_SIZE = 3
class SubByteFields(Record):
__format__ = [('a', Integer(2, False)),
('b', Integer(3, False)),
('c', Integer(3, False))]
EXPECTED_ENCODED_SIZE = 1
class MiddleSubByteFields(Record):
__format__ = [('a', Integer(32)),
('b', Integer(4)),
('c', Integer(4)),
('d', Integer(24)),
('e', Integer(8))]
EXPECTED_ENCODED_SIZE = 9
class CrossByteField(Record):
__format__ = [('a', Integer(6)),
('b', Integer(6)),
('c', Integer(6)),
('d', Integer(6))]
EXPECTED_ENCODED_SIZE = 3
records = [SingleSignedByte, SingleUnsignedByte, SingleSignedShort,
SingleUnsignedShort, SingleSignedLong, SingleUnsignedLong,
MultiByte, MultiType, SubByteFields, MiddleSubByteFields,
CrossByteField]
def randomValue(type):
if type.signed:
return random.randrange(-2 ** type.bits + 1, 2 ** type.bits)
return random.randrange(2 ** type.bits)
from twisted.trial import unittest
class RecordPacking(unittest.TestCase):
def testMethodsAdded(self):
for rt in records:
self.failUnless(hasattr(rt, 'encode'))
self.failUnless(hasattr(rt, 'decode'))
def testEncoding(self):
for rt in records:
fmt = rt.__format__
inst = rt()
for (k, t) in fmt:
setattr(inst, k, randomValue(t))
s = inst.encode()
msg = "%s encoded to %d bytes, not %d bytes" % (rt.__name__, len(s), rt.EXPECTED_ENCODED_SIZE)
self.assertEquals(len(s), rt.EXPECTED_ENCODED_SIZE, msg)
decoded, leftover = rt.decode(s)
self.assertEquals(vars(decoded), vars(inst))
self.failIf(leftover)
class DynamicFoo(Record):
def __format__():
def get(self):
yield ('length', Integer(8, False))
yield ('type', Integer(8, False))
if self.type == 0:
yield ('x', Integer(8, False))
else:
yield ('a', Integer(4, False))
yield ('b', Integer(4, False))
yield ('c', Integer(4, False))
yield ('d', Integer(4, False))
return get,
__format__ = property(*__format__())
class DynamicFormatGeneration(unittest.TestCase):
def testDynamicFormat(self):
tests = [('\x0A\x00\xFF',
{'length': 10, 'type': 0, 'x': 255}),
('\xA0\x01\xA7\x4C',
{'length': 160, 'type': 1, 'a': 10, 'b': 7, 'c': 4, 'd': 12})]
for (bytes, attrs) in tests:
i, leftover = DynamicFoo.decode(bytes)
self.assertEquals(vars(i), attrs)
self.assertEquals(i.encode(), bytes)
self.failIf(leftover)
class FirstInnerRecord(Record):
__format__ = [('a', Integer(4)),
('b', Integer(4))]
class SecondInnerRecord(Record):
__format__ = [('x', Integer(16)),
('y', Integer(8)),
('z', Integer(8))]
class OuterRecord(Record):
__format__ = [('a', Integer(32, True)),
('b', FirstInnerRecord),
('c', Integer(8)),
('d', SecondInnerRecord),
('e', Integer(8))]
class NestedRecords(unittest.TestCase):
def testNesting(self):
tests = [
'\xAB\x12\xCD\x34' '\x10' '\x5C' '\xAB\x65' '\xE3' '\x3E' '\x00', ]
for s in tests:
i, bytes = OuterRecord.decode(s + "junk trailing bytes")
self.assertEquals(i.a, 0xAB12CD34)
self.assertEquals(i.b.a, 0x1)
self.assertEquals(i.b.b, 0x0)
self.assertEquals(i.c, 0x5C)
self.assertEquals(i.d.x, 0xAB65)
self.assertEquals(i.d.y, 0xE3)
self.assertEquals(i.d.z, 0x3E)
self.assertEquals(i.e, 0x00)
self.assertEquals(bytes, "junk trailing bytes")
self.assertEquals(i.encode(), s)