update Bits; tests passing

This commit is contained in:
S Groesz 2020-10-13 06:32:50 +00:00
parent 37782f4b8b
commit e8772e9931
3 changed files with 217 additions and 9 deletions

View File

@ -2,6 +2,7 @@ init:
pip install -r requirements.txt pip install -r requirements.txt
test: test:
python -m unittest -v tests/test_bit.py
python -m unittest -v tests/test_bits.py python -m unittest -v tests/test_bits.py
.PHONY: init test .PHONY: init test

View File

@ -72,8 +72,9 @@ class Bits:
Provide bit operation helpers. Provide bit operation helpers.
""" """
def __init__(self, var=0): def __init__(self, var=0, msb_last=False):
self.__value = 0 self.__value = 0
self.__r_to_l = bool(msb_last)
self.__setvalue(var) self.__setvalue(var)
def __bytes__(self): def __bytes__(self):
@ -86,9 +87,7 @@ class Bits:
return self.__value return self.__value
def __repr__(self): def __repr__(self):
ret = f'{self.__class__.__module__}.{self.__class__.__name__}' return f'{self.__class__.__name__}({self.__value!r})'
ret += f'({bytes(self)})'
return ret
def __str__(self): def __str__(self):
return self.bin() return self.bin()
@ -127,15 +126,165 @@ class Bits:
# we'll take the easy way for now # we'll take the easy way for now
l = self.list() l = self.list()
# str->int->bool->int : accept bool, str, int, return either "0" or "1" # str->int->bool->int : accept bool, str, int, return either "0" or "1"
l[index] = bool(int(value)) l[index] = Bit(value)
self.__setvalue(l) self.__setvalue(l)
def __get__(self, instance, owner): def __get__(self, instance, owner):
return self.bin() return self.bin()
def __add__(self, other):
return Bits(int(self) + int(Bits(other)))
def __sub__(self, other):
return Bits(int(self) - int(Bits(other)))
def __mul__(self, other):
return Bits(int(self) * int(Bits(other)))
def __matmul__(self, other):
return NotImplemented
def __truediv__(self, other):
return NotImplemented
def __floordiv__(self, other):
return Bits(int(self) // int(Bits(other)))
def __mod__(self, other):
return Bits(int(self) % int(Bits(other)))
def __divmod__(self, other):
return (self // Bits(other), self % Bits(other))
def __pow__(self, other, mod=None):
ret = Bits(0)
if mod is None:
ret = Bits(int(self) ** int(Bits(other)))
else:
ret = Bits(int(self) ** int(Bits(other)) % int(Bits(mod)))
return ret
def __lshift__(self, other):
return Bits(int(self) << int(Bits(other)))
def __rshift__(self, other):
return Bits(int(self) >> int(Bits(other)))
def __and__(self, other):
return Bits(int(self) & int(Bits(other)))
def __xor__(self, other):
return Bits(int(self) ^ int(Bits(other)))
def __or__(self, other):
return Bits(int(self) | int(Bits(other)))
def __radd__(self, other):
return Bits(other) + self
def __rsub__(self, other):
return Bits(other) - self
def __rmul__(self, other):
return Bits(other) * self
def __rmatmul__(self, other):
return NotImplemented
def __rtruediv__(self, other):
return NotImplemented
def __rfloordiv__(self, other):
return Bits(other) // self
def __rmod__(self, other):
return Bits(other) % self
def __rdivmod__(self, other):
return (Bits(other) // self, Bits(other) % self)
def __rpow__(self, other, mod=None):
ret = Bits(0)
if mod is None:
ret = Bits(other) ** self
else:
ret = Bits(other) ** self % Bits(mod)
return ret
def __rlshift__(self, other):
return Bits(other) << self
def __rrshift__(self, other):
return Bits(other) >> self
def __rand__(self, other):
return Bits(other) & self
def __rxor__(self, other):
return Bits(other) ^ self
def __ror__(self, other):
return Bits(other) | self
def __iadd__(self, other):
self = self + Bits(other)
return self
def __isub__(self, other):
self = self - Bits(other)
return self
def __imul__(self, other):
self = self * Bits(other)
return self
def __imatmul__(self, other):
return NotImplemented
def __itruediv__(self, other):
return NotImplemented
def __ifloordiv__(self, other):
self = self // Bits(other)
return self
def __imod__(self, other):
self = self % Bits(other)
return self
def __ipow__(self, other):
self = self ** Bits(other)
return self
def __ilshift__(self, other):
self = self << Bits(other)
return self
def __irshift__(self, other):
self = self >> Bits(other)
return self
def __iand__(self, other):
self = self & Bits(other)
return self
def __ixor__(self, other):
self = self ^ Bits(other)
return self
def __ior__(self, other):
self = self | Bits(other)
return self
def __contains__(self, item):
val = Bits(item) & self
return val == Bits(item)
def __setvalue(self, var): def __setvalue(self, var):
self.__value = 0 self.__value = 0
if isinstance(var, int): if isinstance(var, Bits):
self.__value = int(var)
elif isinstance(var, int):
if var < 0 or var > 255: if var < 0 or var > 255:
raise ValueError("Integer must be between 0 and 255") raise ValueError("Integer must be between 0 and 255")
self.__value = var self.__value = var
@ -166,6 +315,14 @@ class Bits:
def chr(self): def chr(self):
return chr(self.__value) return chr(self.__value)
@property
def int(self):
return int(self)
@int.setter
def int(self, value):
self.__setvalue(value)
@property @property
def byte(self): def byte(self):
return bytes(self) return bytes(self)
@ -185,11 +342,19 @@ class Bits:
def nibble(self): def nibble(self):
return [self.bin()[:4], self.bin()[4:]] return [self.bin()[:4], self.bin()[4:]]
@property
def rtl(self):
return self.__r_to_l
@rtl.setter
def rtl(self, msb_last):
self.__r_to_l = bool(msb_last)
def list(self, pad=True, reverse=False): def list(self, pad=True, reverse=False):
ret = [] ret = []
bits = self.bin(pad=pad, reverse=reverse) bits = self.bin(pad=pad, reverse=reverse)
for bit in bits: for b in bits:
ret.append(bool(int(bit))) ret.append(Bit(b))
return ret return ret

View File

@ -90,7 +90,7 @@ class TestBits(TestCase):
with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \ with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \
+ " [without leading zeros]"): + " [without leading zeros]"):
self.assertEqual(testcase["bitsObject"].bin(pad=False), self.assertEqual(testcase["bitsObject"].bin(pad=False),
testcase["bits"].strip("0")) testcase["bits"].lstrip("0"))
def test_reverse(self): def test_reverse(self):
""" """
@ -102,6 +102,48 @@ class TestBits(TestCase):
self.assertEqual(testcase["bitsObject"].bin(), self.assertEqual(testcase["bitsObject"].bin(),
testcase["bits"][::-1]) testcase["bits"][::-1])
def test_membership_operators(self):
"""
Test the membership operator (x in y)
"""
with self.subTest("should all be True"):
for i in range(1, 256):
self.assertTrue(i in Bits(255), f"Bits({i}) in Bits(255) fail")
with self.subTest("should all be False"):
for i in range(1, 256):
self.assertFalse(i in Bits(0), f"Bits({i}) in Bits(0) fail")
with self.subTest("should pass"):
self.assertIn(1, Bits("00100111"), "1 in Bits(39)")
self.assertIn(2, Bits(39), "2 in Bits(39)")
self.assertIn(4, Bits(39), "4 in Bits(39)")
self.assertNotIn(8, Bits(39), "8 in Bits(39)")
self.assertNotIn(16, Bits(39), "16 in Bits(39)")
self.assertIn(32, Bits(39), "32 in Bits(39)")
self.assertNotIn(64, Bits(39), "64 in Bits(39)")
self.assertNotIn(128, Bits(39), "128 in Bits(39)")
def test_binary_operations(self):
self.assertEqual((Bits("00000100") << 3), Bits("00100000"),
"Bits(4) << 3 == Bits(32)")
self.assertEqual((Bits("00100000") << 1), Bits("01000000"),
"Bits(32) << 1 == Bits(64)")
self.assertEqual((Bits(64) >> 2), Bits(16),
"Bits(64) >> 2 == Bits(16)")
self.assertEqual(( 2 << Bits(6)), Bits(128),
"2 << Bits(6) == Bits(128)")
self.assertEqual((Bits(255) & Bits(64)), Bits(64),
"Bits(255) and Bits(64) == Bits(64)")
self.assertNotEqual((Bits(32) & Bits(64)), Bits(64),
"Bits(32) and Bits(64) != Bits(64)")
self.assertEqual((Bits(2) | Bits(32)), 34,
"Bits(2) or Bits(32) == 34")
self.assertEqual((Bits(80) | Bits(64)), Bits(80),
"Bits(80) or Bits(64) == Bits(80)")
self.assertEqual((Bits(80) ^ Bits(64)), Bits(16),
"Bits(80) xor Bits(64) == Bits(16)")
self.assertEqual((Bits(80) & Bits(64)), Bits(64),
"Bits(80) and Bits(64) == Bits(64)")
def test_comparisons(self): def test_comparisons(self):
""" """
Test the comparison operators Test the comparison operators