def test_contains(self): "frame __contains__ method works as expected" self.assertTrue(True in frame.Frame(16, 0xaa55)) self.assertTrue(False in frame.Frame(16, 0xaa55)) self.assertFalse(True in frame.Frame(16, 0)) self.assertFalse(False in frame.Frame(16, 0xffff)) self.assertFalse("wibble" in frame.Frame(16))
def test_add(self): """frame concatenation works as expected""" self.assertEqual( frame.Frame(16, 0x1234) + frame.Frame(16, 0x5678), frame.Frame(32, 0x12345678)) self.assertRaises(TypeError, lambda: frame.Frame(8, 0xff) + 1) self.assertRaises(TypeError, lambda: 1 + frame.Frame(8, 0xff))
def test_frame_bits(self): "frames can only be initialised with an appropriate number of bits" self.assertRaises(TypeError, frame.Frame, None) self.assertRaises(TypeError, frame.Frame, "wibble") self.assertRaises(TypeError, frame.Frame, 16.0) self.assertRaises(ValueError, frame.Frame, 0) self.assertRaises(ValueError, frame.Frame, 16, 0x1ffff) self.assertRaises(ValueError, frame.Frame, 16, -1) self.assertEqual(len(frame.Frame(16, 0xffff)), 16) self.assertEqual(len(frame.Frame(256, 1 << 255)), 256)
def test_pack_len(self): """frame packing with length returns expected byte strings""" f = frame.Frame(28, 0x2345678) self.assertRaises(ValueError, lambda: f.pack_len(3)) self.assertEqual(f.pack_len(4), b'\x02\x34\x56\x78') self.assertEqual(f.pack_len(5), b'\x00\x02\x34\x56\x78') f = frame.Frame(16, 0xaa55) self.assertRaises(ValueError, lambda: f.pack_len(0)) self.assertEqual(f.pack_len(2), b'\xaa\x55') self.assertEqual(f.pack_len(4), b'\x00\x00\xaa\x55')
def test_comparisons(self): "frame comparisons" self.assertNotEqual(frame.Frame(24, 1), 1) self.assertNotEqual(frame.Frame(24, 1), frame.Frame(16, 1)) self.assertEqual(frame.Frame(1), frame.Frame(1)) self.assertEqual(frame.Frame(1) == frame.Frame(2), False) self.assertEqual(frame.Frame(1) != frame.Frame(2), True)
def __init__(self, shortaddr=None, groups=set(), devicetypes=[], random_preload=[]): self.shortaddr = shortaddr self.scenes = [255] * 16 self.groups = set(groups) self.devicetypes = devicetypes self.random_preload = random_preload self.initialising = False self.withdrawn = False self.dt_gap = 1 # Number of commands since last QueryNextDeviceType self.dt_queue = [ ] # Devices still to be returned by QueryNextDeviceType self.randomaddr = frame.Frame(24) self.searchaddr = frame.Frame(24) self.dtr0 = 0 self.dtr1 = 0 self.dtr2 = 0
def test_write(self): """writing to frames works correctly using indices and slices""" f = frame.Frame(24) f[1] = True self.assertEqual(f[23:0], 2) f[2] = True self.assertEqual(f[23:0], 6) f[1] = False self.assertEqual(f[23:0], 4) f[0] = 'yes' self.assertEqual(f[23:0], 5) f[2] = 0 self.assertEqual(f[23:0], 1) with self.assertRaises(IndexError): f[24] = True with self.assertRaises(IndexError): f[-24] = True with self.assertRaises(TypeError): f['wobble'] = False with self.assertRaises(TypeError): f[4:3:2] = 2 # Test large frame that stores data as a long f = frame.Frame(256) f[200] = True f[202] = True self.assertEqual(f[202:199], 10) f = frame.Frame(24) f[7:4] = 0xf self.assertEqual(f[23:0], 0xf0) f[4:4] = 0 self.assertEqual(f[23:0], 0xe0) f[20:23] = 0xa self.assertEqual(f[23:0], 0xa000e0) with self.assertRaises(ValueError): f[3:0] = 0x10 with self.assertRaises(TypeError): f[20:20] = 'wibble' with self.assertRaises(IndexError): f[24:20] = 10 with self.assertRaises(ValueError): f[7:4] = -2
def test_write(self): f = frame.Frame(24) f[1] = True self.assertEqual(f[23:0], 2) f[2] = True self.assertEqual(f[23:0], 6) f[1] = False self.assertEqual(f[23:0], 4) f[0] = "yes" self.assertEqual(f[23:0], 5) f[2] = 0 self.assertEqual(f[23:0], 1) with self.assertRaises(IndexError): f[24] = True with self.assertRaises(IndexError): f[-24] = True with self.assertRaises(TypeError): f["wobble"] = False with self.assertRaises(TypeError): f[4:3:2] = 2 # Test large frame that stores data as a long f = frame.Frame(256) f[200] = True f[202] = True self.assertEqual(f[202:199], 10) f = frame.Frame(24) f[7:4] = 0xf self.assertEqual(f[23:0], 0xf0) f[4:4] = 0 self.assertEqual(f[23:0], 0xe0) f[20:23] = 0xa self.assertEqual(f[23:0], 0xa000e0) with self.assertRaises(ValueError): f[3:0] = 0x10 with self.assertRaises(TypeError): f[20:20] = "wibble" with self.assertRaises(IndexError): f[24:20] = 10 with self.assertRaises(ValueError): f[7:4] = -2
def test_frame_init_data(self): """frames can be initialised with integer or iterable data""" self.assertEqual(frame.Frame(16, 0xffff), frame.Frame(16, (0xff, 0xff))) self.assertNotEqual(frame.Frame(16, 0xffff), frame.Frame(16, (0xff, 0xfe))) self.assertEqual(frame.Frame(16, 0xffff), frame.Frame(16, (0, 0, 0xff, 0xff)))
def test_read(self): "frames return correct values when read using index" # Frame will be 0001 0010 0011 0100 0101 0110 # Index: 3210 9876 5432 1098 7654 3210 f = frame.Frame(24, (0x12, 0x34, 0x56)) self.assertEqual(f[0], False) self.assertEqual(f[1], True) self.assertEqual(f[20], True) self.assertRaises(IndexError, lambda: f[24]) self.assertRaises(IndexError, lambda: f[-1]) self.assertRaises(TypeError, lambda: f["wibble"]) self.assertRaises(TypeError, lambda: f[3:0:2]) self.assertRaises(IndexError, lambda: f[24:20]) self.assertEqual(f[3:0], 6) self.assertEqual(f[7:4], 5) self.assertEqual(f[4:7], 5) self.assertEqual(f[23:20], 1) self.assertEqual(f[2:0], 6) self.assertEqual(f[0:0], 0) self.assertEqual(f[1:1], 1) self.assertEqual(f[2:1], 3) self.assertEqual(f[17:10], int("10001101", 2))
def test_add(self): self.assertEquals( frame.Frame(16, 0x1234) + frame.Frame(16, 0x5678), frame.Frame(32, 0x12345678)) self.assertRaises(TypeError, lambda: frame.Frame(8, 0xff) + 1) self.assertRaises(TypeError, lambda: 1 + frame.Frame(8, 0xff))
def test_as_integer(self): """returning frame as integer works as expected""" self.assertEqual(frame.Frame(32, 0x12345678).as_integer, 0x12345678)
def test_as_byte_sequence(self): """constructing frames from byte sequence works as expected""" f = frame.Frame(29, 0x12345678) self.assertEqual(frame.Frame(29, f.as_byte_sequence), f)
def test_unicode(self): "frame objects return unicode from their __unicode__ method" self.assertTrue( isinstance(frame.Frame(123, 0x12345).__unicode__(), unicode))
def test_pack(self): """frame packing return expected byte strings""" f = frame.Frame(28, 0x2345678) self.assertEqual(f.pack, b'\x02\x34\x56\x78') f = frame.Frame(16, 0xaa55) self.assertEqual(f.pack, b'\xaa\x55')
def test_pack(self): f = frame.Frame(28, 0x2345678) self.assertEquals(f.pack, b'\x02\x34\x56\x78') f = frame.Frame(16, 0xaa55) self.assertEquals(f.pack, b'\xaa\x55')
def test_as_byte_sequence(self): f = frame.Frame(29, 0x12345678) self.assertEquals(frame.Frame(29, f.as_byte_sequence), f)
def test_unicode(self): """frame objects return unicode from their __unicode__ method""" # This test applies to python 2 only if sys.version_info[0] == 2: self.assertIsInstance( frame.Frame(123, 0x12345).__unicode__(), unicode)
def test_str(self): """frame objects can be converted to strings""" self.assertIsInstance(str(frame.Frame(123, 0x12345)), str)
def send(self, cmd): self.dt_gap += 1 if not self.valid_address(cmd): return # Command is either addressed to us, or is a broadcast if isinstance(cmd, general.SetScene): self.scenes[cmd.param] = self.dtr0 elif isinstance(cmd, general.RemoveFromScene): self.scenes[cmd.param] = 255 elif isinstance(cmd, general.AddToGroup): self.groups.add(cmd.param) elif isinstance(cmd, general.RemoveFromGroup): self.groups.discard(cmd.param) elif isinstance(cmd, general.SetShortAddress): if self.dtr0 == 0xff: self.shortaddr = None elif (self.dtr0 & 1) == 1: self.shortaddr = (self.dtr0 & 0x7e) >> 1 elif isinstance(cmd, general.QueryControlGearPresent): return _yes elif isinstance(cmd, general.QueryMissingShortAddress): if self.shortaddr == None: return _yes elif isinstance(cmd, general.QueryContentDTR0): return self.dtr0 elif isinstance(cmd, general.QueryDeviceType): if len(self.devicetypes) == 0: return 254 elif len(self.devicetypes) == 1: return self.devicetypes[0] else: self.dt_gap = 0 self.dt_queue = list(self.devicetypes) return 0xff elif isinstance(cmd, general.QueryContentDTR1): return self.dtr1 elif isinstance(cmd, general.QueryContentDTR2): return self.dtr2 elif isinstance(cmd, general.QueryNextDeviceType): # self.dt_gap must be 1 for this command to be valid; otherwise # there was an intervening command if self.dt_gap == 1: if self.dt_queue: self.dt_gap = 0 return self.dt_queue.pop(0) return 254 elif isinstance(cmd, general.QuerySceneLevel): return self.scenes[cmd.param] elif isinstance(cmd, general.QueryGroupsZeroToSeven): r = frame.Frame(8) for i in range(0, 8): if i in self.groups: r[i] = True return r.as_integer elif isinstance(cmd, general.QueryGroupsEightToFifteen): r = frame.Frame(8) for i in range(8, 16): if i in self.groups: r[i - 8] = True return r.as_integer elif isinstance(cmd, general.QueryRandomAddressH): return self.randomaddr[23:16] elif isinstance(cmd, general.QueryRandomAddressM): return self.randomaddr[15:8] elif isinstance(cmd, general.QueryRandomAddressL): return self.randomaddr[7:0] elif isinstance(cmd, general.Terminate): self.initialising = False self.withdrawn = False elif isinstance(cmd, general.DTR0): self.dtr0 = cmd.param elif isinstance(cmd, general.Initialise): if cmd.broadcast \ or (cmd.address == self.shortaddr): self.initialising = True self.withdrawn = False # We don't implement the 15 minute timer elif isinstance(cmd, general.Randomise): self.randomaddr = frame.Frame(24, self._next_random_address()) elif isinstance(cmd, general.Compare): if self.initialising \ and not self.withdrawn \ and self.randomaddr.as_integer <= self.searchaddr.as_integer: return _yes elif isinstance(cmd, general.Withdraw): if self.initialising \ and self.randomaddr == self.searchaddr: self.withdrawn = True elif isinstance(cmd, general.SearchaddrH): self.searchaddr[23:16] = cmd.param elif isinstance(cmd, general.SearchaddrM): self.searchaddr[15:8] = cmd.param elif isinstance(cmd, general.SearchaddrL): self.searchaddr[7:0] = cmd.param elif isinstance(cmd, general.ProgramShortAddress): if self.initialising \ and self.randomaddr == self.searchaddr: if cmd.address == 'MASK': self.shortaddr = None else: self.shortaddr = cmd.address elif isinstance(cmd, general.VerifyShortAddress): if self.initialising \ and self.shortaddr == cmd.address: return _yes elif isinstance(cmd, general.DTR1): self.dtr1 = cmd.param elif isinstance(cmd, general.DTR2): self.dtr2 = cmd.param
def test_as_integer(self): self.assertEquals(frame.Frame(32, 0x12345678).as_integer, 0x12345678)