def header_and_data(file_path: str) -> Tuple[ZCodeHeader, memoryview]: with open(file_path, 'rb') as f: data = BytesIO(f.read()) view = data.getbuffer() header = get_header(view) return header, view
def test_header_quetzal_chunk(zork1_v3_data: memoryview): header = get_header(zork1_v3_data) saved_pc = PC(0x1234) quetzal_header_chunk = HeaderQuetzalChunk.create(header, saved_pc) stored_header_chunk, offset = HeaderQuetzalChunk.read( quetzal_header_chunk.bytes()) assert offset == len(quetzal_header_chunk.bytes()) saved_header_info = stored_header_chunk.header_info() assert saved_header_info.restore_pc == saved_pc assert saved_header_info.release_number == header.release_number assert saved_header_info.checksum == header.file_checksum assert saved_header_info.serial_number == header.serial_code
def test_ifzs_container(zork1_v3_data: memoryview): header = get_header(zork1_v3_data) saved_pc = PC(0x1234) new_stack = ZMachineStack() quetzal_stack_chunk = StacksQuetzalChunk.create(new_stack) quetzal_header_chunk = HeaderQuetzalChunk.create(header, saved_pc) quetzal_data = IFZSContainer([quetzal_stack_chunk, quetzal_header_chunk]).bytes() parsed_quetzal_data = IFZSContainer.read(quetzal_data) stacks_chunk: StacksQuetzalChunk = parsed_quetzal_data.chunk('Stks') assert new_stack.frames == stacks_chunk.saved_stack().frames header_chunk: HeaderQuetzalChunk = parsed_quetzal_data.chunk('IFhd') saved_header_info = header_chunk.header_info() assert saved_header_info.restore_pc == saved_pc assert saved_header_info.release_number == header.release_number assert saved_header_info.checksum == header.file_checksum assert saved_header_info.serial_number == header.serial_code
def header_and_data(file_path: str) -> Tuple[ZCodeHeader, bytes]: with open(file_path, 'rb') as f: data = f.read() header = get_header(data) return header, data
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
def v3_header_and_data(zork1_v3_data: memoryview) -> Tuple[ZCodeHeader, memoryview]: header = get_header(zork1_v3_data) return header, zork1_v3_data
def zork_v5_obj_table(zork1_v5_data: memoryview) -> ZMachineObjectTable: header = get_header(zork1_v5_data) yield ZMachineObjectTable(zork1_v5_data, header)
def zork_v3_dict(zork1_v3_data: memoryview) -> ZMachineDictionary: header = get_header(zork1_v3_data) yield ZMachineDictionary(zork1_v3_data, header)
def test_abbreviation_to_ascii(index, expected, zork1_v3_data: memoryview): abbrev_table_addr = get_header(zork1_v3_data).abbreviations_table_address ascii_list = abbreviation_to_ascii(zork1_v3_data, abbrev_table_addr, index) assert bytes(ascii_list).decode('ascii') == expected