def __init__(self, *args): super().__init__(*args) content = ( '04AD7150' 'FADA2E80' '8E48E000' '00000000' '00000000' '31880220' '633C0000' 'E92D2412' '00000000' '00000000' '00013634' '0000907B' '00000000' '00000000' '00000000' '00000000' ) content = bytearray.fromhex(content) self.card = MFUCard(bytes=content)
class MFUTests(unittest.TestCase): def __init__(self, *args): super().__init__(*args) content = ( '04AD7150' 'FADA2E80' '8E48E000' '00000000' '00000000' '31880220' '633C0000' 'E92D2412' '00000000' '00000000' '00013634' '0000907B' '00000000' '00000000' '00000000' '00000000' ) content = bytearray.fromhex(content) self.card = MFUCard(bytes=content) def test_iter_bytes(self): iterator = iter(self.card) firstbytes = [next(iterator) for i in range(4)] self.assertEqual(firstbytes, [0x04, 0xad, 0x71, 0x50]) for i in range(len(self.card) - 4): next(iterator) with self.assertRaises(StopIteration): next(iterator) def test_length(self): self.assertEqual(len(self.card), 64) def test_hexdump(self): output = [] def myprint(data, *args, **kwargs): output.append(str(data)) output.append('\n') mock_print = Mock(side_effect=myprint) # patching sys.stdout doesn't work since the function already has # a reference to the real sys.stdout at define time with patch('builtins.print', mock_print): self.card.hexdump() expected = ( '04ad7150\n' 'fada2e80\n' '8e48e000\n' '00000000\n' '00000000\n' '31880220\n' '633c0000\n' 'e92d2412\n' '00000000\n' '00000000\n' '00013634\n' '0000907b\n' '00000000\n' '00000000\n' '00000000\n' '00000000\n' ) self.assertEqual(''.join(output), expected) def test_hexdump_with_custom_output(self): output = [] def write(data): output.append(data) filemock = Mock() filemock.write.side_effect = write self.card.hexdump(file=filemock) expected = ( '04ad7150\n' 'fada2e80\n' '8e48e000\n' '00000000\n' '00000000\n' '31880220\n' '633c0000\n' 'e92d2412\n' '00000000\n' '00000000\n' '00013634\n' '0000907b\n' '00000000\n' '00000000\n' '00000000\n' '00000000\n' ) self.assertEqual(''.join(output), expected) def test_dump(self): output = [] def write(data): output.append(data) filemock = Mock(sys.stdout) filemock.write.side_effect = write self.card.dump(filemock) expected = ( b'\x04\xad\x71\x50' b'\xfa\xda\x2e\x80' b'\x8e\x48\xe0\x00' b'\x00\x00\x00\x00' b'\x00\x00\x00\x00' b'\x31\x88\x02\x20' b'\x63\x3c\x00\x00' b'\xe9\x2d\x24\x12' b'\x00\x00\x00\x00' b'\x00\x00\x00\x00' b'\x00\x01\x36\x34' b'\x00\x00\x90\x7b' b'\x00\x00\x00\x00' b'\x00\x00\x00\x00' b'\x00\x00\x00\x00' b'\x00\x00\x00\x00' ) self.assertEqual(b''.join(output), expected) def test_page_view_is_singleton(self): view1 = self.card.pages view2 = self.card.pages self.assertIs(view1, view2) def test_get_byte_by_index(self): self.assertEqual(self.card[0], 4) self.assertEqual(self.card[4], 0xfa) self.assertEqual(self.card[8], 0x8e) self.assertEqual(self.card[47], 0x7b) self.assertEqual(self.card[-1], 0) self.assertEqual(self.card[-len(self.card)], 4) def test_get_bytes_by_slice(self): data = self.card[:4] self.assertEqual(data, b'\x04\xad\x71\x50') data = self.card[10:12] self.assertEqual(data, b'\xe0\x00') data = self.card[60:] self.assertEqual(data, b'\x00\x00\x00\x00') def test_get_bytes_by_invalid_index(self): for i in (str, dict, list, tuple, set, bytes, bytearray, complex, lambda: None, object()): with self.assertRaises(TypeError): self.card[i] with self.assertRaises(IndexError): self.card[-len(self.card)-1] with self.assertRaises(IndexError): self.card[len(self.card)] def test_get_page(self): self.assertEqual(bytes(self.card.pages[0]), b'\x04\xAD\x71\x50') def test_byte_by_getitem(self): self.assertEqual(self.card[0], 0x04) def test_bytes_by_slice(self): self.assertEqual(self.card[:2], b'\x04\xAD') def test_basic_attributes(self): self.assertEqual(self.card.id, 0x04ad71fada2e80) self.assertEqual(self.card.manufacturer, 0x04) self.assertEqual(self.card.bcc0, 0x50) self.assertEqual(self.card.bcc1, 0x8e) self.assertEqual(self.card.id0, 0x04) self.assertEqual(self.card.id1, 0xad) self.assertEqual(self.card.id2, 0x71) self.assertEqual(self.card.id3, 0xfa) self.assertEqual(self.card.id4, 0xda) self.assertEqual(self.card.id5, 0x2e) self.assertEqual(self.card.id6, 0x80) def test_first_pages_are_readonly(self): for p in [0, 1]: self.assertTrue(self.card.pages[p].readonly) def test_locked_pages_are_read_only(self): self.skipTest('not implemented') #self.assertTrue(card.otp_locked) #self.assertTrue(card.pages4to9_blocked) #self.assertFalse(card.pages10to15_blocked) #self.assertFalse(card.otp_blocked) def test_init_default_empty(self): # initialized to all zeroes card = MFUCard() self.assertEqual(bytes(card), b'\x00' * 64) def test_init_one_param_only(self): with self.assertRaises(RuntimeError): mfu = MFUCard(bytes=b'abcd'*4, file=1) with self.assertRaises(RuntimeError): mfu = MFUCard(bytes=b'abcd'*4, hexfile=1) with self.assertRaises(RuntimeError): mfu = MFUCard(file=1, hexfile=1) with self.assertRaises(RuntimeError): mfu = MFUCard(bytes=b'abcd'*4, file=1, hexfile=1) def test_init_bytestring(self): # initialized with bytes, must be 64 bytes card = MFUCard(bytes=b'\x01' * 64) self.assertEqual(bytes(card), b'\x01' * 64) def test_init_bytes(self): card = MFUCard(bytes=bytes(64)) self.assertEqual(bytes(card), b'\x00' * 64) card = MFUCard(bytes=bytearray([i for i in range(64)])) self.assertEqual(list(card), [i for i in range(64)]) def test_init_from_file(self): # load from a 64-byte binary file content = b'\x01\x02\03\x04' * 16 fp_mock = Mock(sys.stdin) fp_mock.fileno.return_value = 3 with patch('builtins.open', return_value=fp_mock) as mock_open, \ patch('os.read', return_value=content) as mock_sysread: card = MFUCard(file='card.bin') self.assertEqual(bytes(card), content) def test_init_from_file_descriptor(self): def sysread(desc, n): return b'\x01' * n with patch('os.read', wraps=sysread) as mock_sysread: card = MFUCard(file=3) mock_sysread.assert_called_with(3, ANY) self.assertEqual(bytes(card), b'\x01' * 64) def test_init_from_hexfile(self): # load from an ASCII hex file, spaces ignored, case-insensitive content = b'0badc0de' * 16 fp_mock = Mock(sys.stdin) fp_mock.fileno.return_value = 3 with patch('builtins.open', return_value=fp_mock) as mock_open, \ patch('os.read', return_value=content) as mock_sysread: card = MFUCard(hexfile='card.txt') self.assertEqual(bytes(card), b'\x0b\xad\xc0\xde' * 16) def test_init_from_hexfile_file_descriptor(self): def sysread(desc, n): if not hasattr(sysread, 'filepos'): sysread.filepos = 0 filedata = ( b'00010203' b'01020304' b'02030405' b'03040506' b'04050607' b'05060708' b'06070809' b'0708090a' b'08090a0b' b'090a0b0c' b'0a0b0c0d' b'0b0c0d0e' b'0c0d0e0f' b'0d0e0f00' b'0e0f0001' b'0f000102' ) chunk = filedata[sysread.filepos:sysread.filepos+n] sysread.filepos = min(sysread.filepos + n, len(filedata)) return chunk with patch('os.read', wraps=sysread) as mock_sysread: card = MFUCard(hexfile=3) mock_sysread.assert_called_with(3, ANY) expected = b''.join(bytes([i, (i + 1) % 16, (i + 2) % 16, (i + 3) % 16]) for i in range(16)) self.assertEqual(bytes(card), expected)