def test_set_own_property_v5(zork_v5_obj_table: ZMachineObjectTable): # Property #46 is a two-byte property zorkmid = zork_v5_obj_table.object(122) zorkmid.properties.set(46, ZWord(b'\x12\x34')) assert ZWord(b'\x12\x34') == zorkmid.properties.value(46) you = zork_v5_obj_table.object(21) with pytest.raises(ZMachineIllegalOperation, match='size 8 with a value of size '): you.properties.set(46, ZWord(b'\x12\x34'))
def test_attributes_v5(zork_v5_obj_table: ZMachineObjectTable): cretin = zork_v5_obj_table.object(46) assert cretin.attributes == {23, 25, 31, 46} cretin.update_attribute(23, False) cretin.update_attribute(25, False) cretin.update_attribute(31, False) cretin.update_attribute(46, False) assert cretin.attributes == set() # Flip each attribute individually for i in range(48): cretin.update_attribute(i, True) assert cretin.attributes == { i }, f'attribute {i} should be set in the attributes set' assert cretin.is_attribute_set( i) == True, f'attribute {i} should be set' cretin.update_attribute(i, False) assert cretin.attributes == set( ), f'attribute {i} should be set in the attributes set' assert cretin.is_attribute_set( i) == False, f'attribute {i} should be set' # Gotta' set 'em all for i in range(48): cretin.update_attribute(i, True) assert cretin.attributes == set(range(48))
def test_attributes_v3(zork_v3_obj_table: ZMachineObjectTable): cretin = zork_v3_obj_table.object(4) assert cretin.attributes == {7, 9, 14, 30} cretin.update_attribute(7, False) cretin.update_attribute(9, False) cretin.update_attribute(14, False) cretin.update_attribute(30, False) assert cretin.attributes == set() # Flip each attribute individually for i in range(32): cretin.update_attribute(i, True) assert cretin.attributes == { i }, f'attribute {i} should be set in the attributes set' assert cretin.is_attribute_set( i) == True, f'attribute {i} should be set' cretin.update_attribute(i, False) assert cretin.attributes == set( ), f'attribute {i} should be set in the attributes set' assert cretin.is_attribute_set( i) == False, f'attribute {i} should be set' # Gotta' set 'em all for i in range(32): cretin.update_attribute(i, True) assert cretin.attributes == set(range(32))
def main(argv): header, data = header_and_data(argv[1]) obj_table = ZMachineObjectTable(data, header) obj_num = int(argv[2]) obj = obj_table.object(obj_num) print_object(obj_num, obj) return 0
def main(argv): header, data = header_and_data(argv[1]) obj_table = ZMachineObjectTable(data, header) for i in range(1, 223): if obj_table.object(i).parent == 0: obj_tree = obj_table.obj_tree(i) print_obj_tree(obj_tree) return 0
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_remove_obj_from_parent_last_child_v3( zork_v3_obj_table: ZMachineObjectTable): zork_v3_obj_table.remove_obj_from_parent(160) west_of_house_tree = zork_v3_obj_table.obj_tree(180) assert len(west_of_house_tree['children']) == 1 assert west_of_house_tree['children'][0]['number'] == 181 small_mailbox_obj = zork_v3_obj_table.object(160) assert small_mailbox_obj.parent == 0 assert small_mailbox_obj.sibling == 0
def test_remove_obj_from_parent_first_child_v5( zork_v5_obj_table: ZMachineObjectTable): zork_v5_obj_table.remove_obj_from_parent(239) west_of_house_tree = zork_v5_obj_table.obj_tree(68) assert len(west_of_house_tree['children']) == 1 assert west_of_house_tree['children'][0]['number'] == 127 small_mailbox_obj = zork_v5_obj_table.object(239) assert small_mailbox_obj.parent == 0, 'object should no longer have a parent' assert small_mailbox_obj.sibling == 0, 'object should no longer have a sibling'
def test_remove_obj_from_parent_first_child_v3( zork_v3_obj_table: ZMachineObjectTable): zork_v3_obj_table.remove_obj_from_parent(181) west_of_house_tree = zork_v3_obj_table.obj_tree(180) assert len(west_of_house_tree['children']) == 1 assert west_of_house_tree['children'][0]['number'] == 160 door_obj = zork_v3_obj_table.object(181) assert door_obj.parent == 0, 'object should no longer have a parent' assert door_obj.sibling == 0, 'object should no longer have a sibling'
def test_remove_obj_from_parent_last_child_v5( zork_v5_obj_table: ZMachineObjectTable): zork_v5_obj_table.remove_obj_from_parent(127) west_of_house_tree = zork_v5_obj_table.obj_tree(68) assert len(west_of_house_tree['children']) == 1 assert west_of_house_tree['children'][0]['number'] == 239 door_obj = zork_v5_obj_table.object(127) assert door_obj.parent == 0 assert door_obj.sibling == 0
def test_remove_obj_from_parent_middle_child_v3( zork_v3_obj_table: ZMachineObjectTable): zork_v3_obj_table.remove_obj_from_parent(91) maintenance_room_tree = zork_v3_obj_table.obj_tree(199) assert len(maintenance_room_tree['children']) == 8 assert maintenance_room_tree['children'][0]['number'] == 200 assert maintenance_room_tree['children'][1]['number'] == 99 wrench_obj = zork_v3_obj_table.object(91) assert wrench_obj.parent == 0 assert wrench_obj.sibling == 0
def test_default_properties_v5(zork_v5_obj_table: ZMachineObjectTable): door = zork_v5_obj_table.object(127) # Get default properties and spot check default_1 = door.properties.default_value(1) default_63 = door.properties.default_value(63) # ensure default falls through if own property isn't defined assert default_1 == door.properties.value_or_default( 1), 'default property 1 should have been returned' assert default_63 == door.properties.value_or_default( 63), 'default property 63 should have been returned'
def test_remove_obj_from_parent_middle_child_v5( zork_v5_obj_table: ZMachineObjectTable): zork_v5_obj_table.remove_obj_from_parent(203) maintenance_room_tree = zork_v5_obj_table.obj_tree(233) assert len(maintenance_room_tree['children']) == 8 assert maintenance_room_tree['children'][0]['number'] == 245 assert maintenance_room_tree['children'][1]['number'] == 120 tube_obj = zork_v5_obj_table.object(203) assert tube_obj.parent == 0 assert tube_obj.sibling == 0
def test_own_properties_v5(zork_v5_obj_table: ZMachineObjectTable): door = zork_v5_obj_table.object(127) # Get own properties own_properties = door.properties.all() assert 46 in own_properties assert own_properties[46] == ZWord(b'\x4d\xff') assert 45 in own_properties assert own_properties[45] == ZWord(b'\x3e\x24') assert 44 in own_properties assert own_properties[44].hex() == '50364a60' assert own_properties[46] == door.properties.value(46) assert own_properties[45] == door.properties.value(45) assert own_properties[44] == door.properties.value(44)
def test_umem_quetzal_chunk(zork_v3_obj_table: ZMachineObjectTable): original_memory = bytes(zork_v3_obj_table._memory) cretin = zork_v3_obj_table.object(4) cretin.properties.set(18, ZWord(bytes.fromhex('ffff'))) prop_address = cretin.properties.get(18).value_address cmem_chunk = UMemQuetzalChunk(zork_v3_obj_table._memory) restored_chunk, offset = UMemQuetzalChunk.read(cmem_chunk.bytes()) assert offset == len(cmem_chunk.bytes()) restored_memory = restored_chunk.saved_memory() for i in range(len(restored_memory)): if i not in [prop_address, prop_address + 1]: assert restored_memory[i] == original_memory[ i], f'memory different at {hex(i)} should be different at {hex(prop_address)}' else: assert restored_memory[i] != original_memory[ i], f'memory should be different at {hex(i)} for prop at address {hex(prop_address)}'
def test_own_properties_v3(zork_v3_obj_table: ZMachineObjectTable): door = zork_v3_obj_table.object(181) # Get own properties own_properties = door.properties.all() assert 18 in own_properties assert own_properties[18] == ZWord(b'\x3f\x9d') assert 17 in own_properties assert own_properties[17] == ZWord(b'\x6d\x57') assert 16 in own_properties assert own_properties[16] == ZWord(b'\xc9\xca') assert own_properties[18] == door.properties.get(18).value assert own_properties[17] == door.properties.get(17).value assert own_properties[16] == door.properties.get(16).value assert own_properties[18] == door.properties.value(18) assert own_properties[17] == door.properties.value(17) assert own_properties[16] == door.properties.value(16)
def test_first_own_property_v3(zork_v3_obj_table: ZMachineObjectTable): smelly_room = zork_v3_obj_table.object(22) first_prop = next(iter(smelly_room.properties)) assert first_prop.number == 28
def test_object_name_prop_v5(obj_num: int, expected_name: str, zork_v5_obj_table: ZMachineObjectTable): assert zork_v5_obj_table.object(obj_num).name == expected_name
def test_tree_v3(zork_v3_obj_table: ZMachineObjectTable): west_of_house = zork_v3_obj_table.object(180) assert west_of_house.parent == 82 assert west_of_house.child == 181 assert west_of_house.sibling == 15
def compare_machine_state(interpreter: ZMachineInterpreter, state_data_dir: str, num_objects: int = 250) -> dict: """ Compare the state of the interpreter with state saved on disk. The files on disk should have the filenames of: * "mem-{step_num}" : binary file containing all of a Z-Machine's memory * "state-{step_num}.json" : JSON file containing machine state external to the memory in the following format, note that all values are hexadecimal strings, not ints, and only the current routine stack frame is accounted. ```json { "pc": "0x5479", # Program counter "local_vars": ["0x8010", "0xffff"], # Local variables, in oder from 0-n "stack": [], # Routine stack "ret_var": "0x0", # Variable number to return value to "ret_pc": "0x4f0e" : PC to return to after routine exits } ``` :param interpreter: Interpreter to compare the state to :param state_data_dir: Directory where state data can be found :param num_objects: Number of objects to scan :return: Differences in state on disk and interpreter """ with open(path.join(state_data_dir, f'mem-{interpreter.step_count}'), 'br') as f: memory = f.read() with open(path.join(state_data_dir, f'state-{interpreter.step_count}.json'), 'r') as f: state = json.load(f) comp_header = get_header(memory) assert comp_header.version == interpreter.header.version diffs = dict() # Compare objects obj_table = ZMachineObjectTable(memory, comp_header) for obj_num in range(1, num_objects + 1): obj_diffs = dict() comp_obj = obj_table.object(obj_num) obj = interpreter.object_table.object(obj_num) if comp_obj.parent != obj.parent: obj_diffs['parent'] = dict(expected=comp_obj.parent, found=obj.parent) if comp_obj.sibling != obj.sibling: obj_diffs['sibling'] = dict(expected=comp_obj.sibling, found=obj.sibling) if comp_obj.child != obj.child: obj_diffs['child'] = dict(expected=comp_obj.child, found=obj.child) if comp_obj.attributes != obj.attributes: obj_diffs['attributes'] = dict(expected=comp_obj.attributes, found=obj.attributes) if comp_obj.properties.all() != obj.properties.all(): obj_diffs['properties'] = dict(expected=comp_obj.properties.all(), found=obj.properties.all()) if obj_diffs: diffs.setdefault('objects', dict()) diffs['objects'][obj_num] = obj_diffs # Compare global variables variables = ZMachineVariables(memory, comp_header, ZMachineStack()) for global_num in range(0xef): if variables.global_val(global_num) != interpreter.variables.global_val(global_num): diffs.setdefault('globals', dict()) diffs['globals'][global_num] = dict(expected=variables.global_val(global_num), found=interpreter.variables.global_val(global_num)) # Compare external state if state['pc'] != hex(int(interpreter.pc)): diffs['pc'] = dict(expected=state['pc'], found=hex(int(interpreter.pc))) # Local vars if len(state['local_vars']) != len(interpreter.stack.routine_frame.local_vars): diffs['num_local_vars'] = dict(expected=len(state['local_vars'])) else: for i in range(len(state['local_vars'])): expected = state['local_vars'][i] found = '0x' + interpreter.stack.routine_frame.local_vars[i].hex() if expected != found: diffs.setdefault('local_vars', {}) diffs['local_vars'][i] = dict(expected=expected, found=found) # Routine stack if len(state['stack']) != len(interpreter.stack.routine_frame.stack_data): diffs['routine_stack_size'] = dict(expected=len(state['stack']), found=len(interpreter.stack.routine_frame.stack_data)) else: for i in range(len(state['stack'])): expected = state['stack'][i] found = '0x' + interpreter.stack.routine_frame.stack_data[i].hex() if expected != found: diffs.setdefault('routine_stack', {}) diffs['routine_stack'][i] = dict(expected=expected, found=found) # ret var found_res_var = '0x' + interpreter.stack.routine_frame.result_var.hex() if interpreter.stack.routine_frame.result_var is not None else None if state['ret_var'] != found_res_var: diffs['result_var'] = dict(expected=state['ret_var'], found=found_res_var) found_ret_pc = hex(int(interpreter.stack.routine_frame.return_pc)) if interpreter.stack.routine_frame.return_pc is not None else '0x0000' if state['ret_pc'] != found_ret_pc: diffs['return_pc'] = dict(expected=state['ret_pc'], found=found_ret_pc) return diffs