def test_zbyte_bitwise_operations(): zb = ZByte.from_unsigned_int(0b1010_1010) << 1 assert zb.unsigned_int == 0b0101_0100 zb = ZByte.from_unsigned_int(0b0000_1111) << 4 assert zb.unsigned_int == 0b1111_0000 zb = ZByte.from_unsigned_int(0b1111_0000) >> 4 assert zb.unsigned_int == 0b0000_1111 zb = ZByte.from_unsigned_int(0b0001_0000) >> 1 assert zb.unsigned_int == 0b0000_1000 zb = ZByte.from_unsigned_int(0b1111_1111) & 0b0101_0101 assert zb.bytes == b'\x55' zb = ZByte.from_unsigned_int(0b1111_0000) | 0b0000_1111 assert zb.bytes == b'\xff' zb = ~ZByte.from_unsigned_int(0b0101_0101) assert zb.unsigned_int == 0b1010_1010 zb = ~ZByte.from_unsigned_int(0b0000_1111) assert zb.unsigned_int == 0b1111_0000 zb = ZByte.from_unsigned_int(0b1010_1100) assert zb.is_bit_set(7) is True assert zb.is_bit_set(0) is False assert zb.is_bit_set(3) is True assert zb.is_bit_clear(7) is False assert zb.is_bit_clear(0) is True assert zb.is_bit_clear(3) is False assert ZByte.from_int(1) == ZByte(b'\x01') assert ZByte.from_int(42) != ZByte(b'\x01')
def test_instantiating_zbyte(): zb = ZByte(bytes.fromhex('12')) assert zb.bytes == b'\x12', 'Instantiate ZByte from bytes' zb = ZByte(memoryview(bytes.fromhex('42'))) assert zb.bytes == b'\x42', 'Instantiate ZByte from memoryview' zb = ZByte.from_int(-1) assert zb.bytes == b'\xff', 'Instantiate ZByte from int' zb = ZByte.from_unsigned_int(0xf0) assert zb.bytes == b'\xf0', 'Instantiate ZByte from unsigned int' with pytest.raises(TypeError): ZByte(22) with pytest.raises(ValueError): ZByte(b'') with pytest.raises(ValueError): ZByte.from_int(-129) with pytest.raises(ValueError): ZByte.from_int(128) with pytest.raises(ValueError): ZByte.from_unsigned_int(-1) with pytest.raises(ValueError): ZByte.from_unsigned_int(256)
def test_long_form_opcodes(opcodes_v3: ZMachineOpcodeParserV3): add, next_pc = opcodes_v3.parse(0x4e83) assert add.name == 'add' assert len(add.operand_types) == 2 assert len(add.operands) == 2 assert add.operand_types == (ZMachineOperandTypes.VARIABLE, ZMachineOperandTypes.SMALL_CONSTANT) assert add.operands == (ZByte(b'\x01'), ZByte(b'\x02')) assert next_pc == 0x4e83 + 4
def test_short_form_opcodes(opcodes_v3: ZMachineOpcodeParserV3): # One operand of type LARGE_CONSTANT jump, next_pc = opcodes_v3.parse(0x85ab) assert jump.name == 'jump' assert len(jump.operand_types) == 1 assert len(jump.operands) == 1 assert jump.operand_types[0] == ZMachineOperandTypes.LARGE_CONSTANT assert jump.operands[0] == ZWord(bytes([0x00, 0x0b])) assert next_pc == 0x85ab + 3 # One operand of type VARIABLE load, next_pc = opcodes_v3.parse(0x7d58) assert load.name == 'load' assert len(load.operand_types) == 1 assert len(load.operands) == 1 assert load.operand_types[0] == ZMachineOperandTypes.VARIABLE assert load.operands[0] == ZByte(b'\x00') assert next_pc == 0x7d58 + 3 # Zero operands print_ret, next_pc = opcodes_v3.parse(0x4fb1) assert print_ret.name == 'print_ret' assert print_ret.operand_types is None assert print_ret.operands is None assert next_pc == 0x4fc4
def test_set_own_property_v3(zork_v3_obj_table: ZMachineObjectTable): # Property #16 is a single-byte property pair_of_hands = zork_v3_obj_table.object(1) # Set with a single byte pair_of_hands.properties.set(16, ZByte(b'\x42')) assert ZByte(b'\x42') == pair_of_hands.properties.value(16), \ 'a single byte property is set with a single byte value' # Set with two bytes pair_of_hands.properties.set(16, ZWord.from_int(-6)) assert ZByte.from_int(-6) == pair_of_hands.properties.value(16), \ 'a single byte property is set with a two byte value' # Property #18 is a two-byte property zorkmid = zork_v3_obj_table.object(2) zorkmid.properties.set(18, ZWord(b'\x12\x34')) assert ZWord(b'\x12\x34') == zorkmid.properties.value(18)
def test_zbyte_to_zbyte_math(): zb = ZByte.from_int(0) + ZByte.from_int(12) assert zb.bytes == b'\x0c', 'ZByte + ZByte' zb = ZByte.from_int(0) - ZByte.from_int(1) assert zb.bytes == b'\xff', 'ZByte - ZByte' zb = ZByte.from_int(-128) - ZByte.from_int(1) assert zb.bytes == b'\x7f', 'Zbyte arithmetic truncation' zb = ZByte.from_int(-2) * ZByte.from_int(8) assert zb.int == -16, 'ZByte * ZByte' zb = ZByte.from_int(127) * ZByte.from_int(127) assert zb.bytes == b'\x01', 'ZByte multiplication truncation' zb = ZByte.from_int(3) // ZByte.from_int(2) assert zb.bytes == b'\x01', 'ZByte integer division' with pytest.raises(ZMachineIllegalOperation, match='Divide by zero'): ZByte.from_int(45) // ZByte.from_int(0) with pytest.raises(ZMachineIllegalOperation): zb.from_int(4) / zb.from_int(8) zb = ZByte(b'\x01').inc() assert zb.bytes == b'\x02' zb = ZByte(b'\xff').inc() assert zb.bytes == b'\x00', 'Rollover on increment' zb = ZByte.from_int(0).dec() assert zb.int == -1 zb = ZByte(b'\x00').dec() assert zb.bytes == b'\xff', 'Rollover on decrement' zb = ZByte.from_int(127) % ZByte.from_int(2) assert zb.int == 1 zb = ZByte.from_int(-128) % ZByte.from_int(2) assert zb.int == 0
def test_variable_form_opcodes(opcodes_v3: ZMachineOpcodeParserV3): # Test variable form of 2OP opcode instructions call, next_pc = opcodes_v3.parse(0x5157) assert call.name == 'je' assert len(call.operand_types) == 3 assert call.operand_types == (ZMachineOperandTypes.VARIABLE, ZMachineOperandTypes.SMALL_CONSTANT, ZMachineOperandTypes.SMALL_CONSTANT) assert call.operands == (ZByte(b'\x88'), ZByte(b'\x32'), ZByte(b'\x12')) assert next_pc == 0x5157 + 6 # Test unique variable opcode instructions call, next_pc = opcodes_v3.parse(0x4f05) assert call.name == 'call' assert len(call.operand_types) == 3 assert call.operand_types == (ZMachineOperandTypes.LARGE_CONSTANT, ZMachineOperandTypes.LARGE_CONSTANT, ZMachineOperandTypes.LARGE_CONSTANT) assert len(call.operands) == 3 assert call.operands == (ZWord(bytes([0x2a, 0x39])), ZWord(bytes([0x80, 0x10])), ZWord(bytes([0xff, 0xff]))) assert next_pc == 0x4f05 + 9