Last active
February 22, 2021 15:25
-
-
Save JakeTheCorn/020d9b59b1bdbd677fcf27251949ec1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import unittest | |
# todo: make this a "parameterized" test | |
HEX_NUGGET_MAP = { | |
'0': '0000', | |
'1': '0001', | |
'2': '0010', | |
'3': '0011', | |
'4': '0100', | |
'5': '0101', | |
'6': '0110', | |
'7': '0111', | |
'8': '1000', | |
'9': '1001', | |
'A': '1010', | |
'B': '1011', | |
'C': '1100', | |
'D': '1101', | |
'E': '1110', | |
'F': '1111', | |
} | |
def hex_to_nugget(hex_value): | |
return HEX_NUGGET_MAP[hex_value] | |
def hex_to_binary(hex_string): | |
binary_string = '' | |
result = HexResult() | |
original = hex_string | |
result.original = original | |
sanitized_hex_string = hex_string.strip().upper() | |
for hex_char in sanitized_hex_string: | |
if hex_char not in HEX_NUGGET_MAP: | |
result.error = ValueError('Received non hexadecimal value - "%s"' % original) | |
result._empty_bits() | |
return result | |
result.bits += hex_to_nugget(hex_char) | |
result.original = hex_string | |
result.bit_count = len(result.bits) | |
return result | |
class Tests(unittest.TestCase): | |
def test1(self): | |
tables = [ | |
Table( | |
input='0', | |
expected=HexResult( | |
bits='0000', | |
bit_count=4, | |
original='0', | |
error=None, | |
) | |
), | |
Table( | |
input='1', | |
expected=HexResult( | |
bits='0001', | |
bit_count=4, | |
original='1', | |
error=None, | |
) | |
), | |
Table( | |
input='2', | |
expected=HexResult( | |
bits='0010', | |
bit_count=4, | |
original='2', | |
error=None, | |
) | |
), | |
Table( | |
input='3', | |
expected=HexResult( | |
bits='0011', | |
bit_count=4, | |
original='3', | |
error=None, | |
) | |
), | |
Table( | |
input='4', | |
expected=HexResult( | |
bits='0100', | |
bit_count=4, | |
original='4', | |
error=None, | |
) | |
), | |
Table( | |
input='F', | |
expected=HexResult( | |
bits='1111', | |
bit_count=4, | |
original='F', | |
error=None, | |
) | |
), | |
Table( | |
input='f', | |
expected=HexResult( | |
bits='1111', | |
bit_count=4, | |
original='f', | |
error=None, | |
) | |
), | |
Table( | |
input='FF', | |
expected=HexResult( | |
bits='11111111', | |
bit_count=8, | |
original='FF', | |
error=None, | |
) | |
), | |
Table( | |
input='GF', | |
expected=HexResult( | |
bits='', | |
bit_count=0, | |
original='GF', | |
error=ValueError('Received non hexadecimal value - "GF"'), | |
) | |
), | |
Table( | |
input='P', | |
expected=HexResult( | |
bits='', | |
bit_count=0, | |
original='', | |
error=ValueError('Received non hexadecimal value - "P"'), | |
) | |
), | |
Table( | |
input=' F', | |
expected=HexResult( | |
bits='1111', | |
bit_count=4, | |
original=' F', | |
error=None, | |
) | |
), | |
Table( | |
input=' F F', | |
expected=HexResult( | |
bits='', | |
bit_count=0, | |
original=' F F', | |
error=ValueError('Received non hexadecimal value - " F F"'), | |
) | |
), | |
] | |
for table in tables: | |
result = hex_to_binary(table.input) | |
self.assertEqual(type(table.expected.error), type(result.error)) | |
if table.expected.error: | |
self.assertEqual(str(table.expected.error), str(result.error)) | |
self.assertEqual(table.expected.bits, result.bits) | |
self.assertEqual(table.expected, result) | |
class Table(object): | |
input = None | |
expected = None | |
def __init__(self, input, expected): | |
self.input = input | |
self.expected = expected | |
class HexResult(object): | |
bits = '' | |
bit_count = 0 | |
original = '' | |
error = None | |
def __init__( | |
self, | |
bits='', | |
bit_count=0, | |
original='', | |
error=None, | |
): | |
self.bits = bits | |
self.bit_count = bit_count | |
self.original = original | |
self.error = error | |
def __eq__(self, other): | |
if not isinstance(other, HexResult): | |
return False | |
bits_equal = self.bits == other.bits | |
bit_count_equal = self.bit_count == other.bit_count | |
error_types_equal = type(self.error) == type(other.error) | |
error_messages_equal = True | |
if not error_types_equal: | |
return False | |
if self.error is not None: | |
error_messages_equal = str(self.error) == str(other.error) | |
return bits_equal and bit_count_equal and error_messages_equal | |
# Private | |
def _empty_bits(self): | |
self.bits = '' | |
self.bit_count = 0 | |
# TODO: test errors | |
HEX_CHAR_MAP = { | |
'0': 0, | |
'1': 1, | |
'2': 2, | |
'3': 3, | |
'4': 4, | |
'5': 5, | |
'6': 6, | |
'7': 7, | |
'8': 8, | |
'9': 9, | |
'A': 10, | |
'B': 11, | |
'C': 12, | |
'D': 13, | |
'E': 14, | |
'F': 15, | |
} | |
def hex_to_decimal(hex_value): | |
result = HexToDecimalResult() | |
result.hex = hex_value | |
total = 0 | |
for idx, hex_char in enumerate(hex_value[::-1]): | |
current_multiplier = _get_current_multiplier(idx) | |
current_hex_decimal_value = HEX_CHAR_MAP[hex_char] | |
total += current_hex_decimal_value * current_multiplier | |
result.decimal = total | |
return result | |
def _get_current_multiplier(idx): | |
return 16 ** idx | |
class HexToDecimalTests(unittest.TestCase): | |
def test(self): | |
tables = [ | |
Table( | |
input='0', | |
expected=HexToDecimalResult( | |
decimal=0, | |
hex='0', | |
error=None, | |
) | |
), | |
Table( | |
input='1', | |
expected=HexToDecimalResult( | |
decimal=1, | |
hex='1', | |
error=None, | |
) | |
), | |
Table( | |
input='A', | |
expected=HexToDecimalResult( | |
decimal=10, | |
hex='A', | |
error=None, | |
) | |
), | |
Table( | |
input='10', | |
expected=HexToDecimalResult( | |
decimal=16, | |
hex='10', | |
error=None, | |
) | |
), | |
Table( | |
input='20', | |
expected=HexToDecimalResult( | |
decimal=32, | |
hex='20', | |
error=None, | |
) | |
), | |
Table( | |
input='AA', | |
expected=HexToDecimalResult( | |
decimal=170, | |
hex='AA', | |
error=None, | |
) | |
), | |
Table( | |
input='AAA', | |
expected=HexToDecimalResult( | |
decimal=2730, | |
hex='AAA', | |
error=None, | |
) | |
), | |
Table( | |
input='FF', | |
expected=HexToDecimalResult( | |
decimal=255, | |
hex='FF', | |
error=None, | |
) | |
), | |
Table( | |
input='FFF', | |
expected=HexToDecimalResult( | |
decimal=4095, | |
hex='FFF', | |
error=None, | |
) | |
), | |
] | |
for table in tables: | |
result = hex_to_decimal(table.input) | |
self.assertEqual(table.expected, result) | |
class HexToDecimalResult(object): | |
decimal = 0 | |
hex = '' | |
error = None | |
def __init__( | |
self, | |
decimal=0, | |
hex='', | |
error=None, | |
): | |
self.decimal = decimal | |
self.hex = hex | |
self.error = error | |
def __eq__(self, other): | |
if not isinstance(other, HexToDecimalResult): | |
return False | |
hex_values_equal = self.hex == other.hex | |
decimal_values_equal = self.decimal == other.decimal | |
return hex_values_equal and decimal_values_equal | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
todo: this needs redesign... it's overengineered, but I did it for fun