Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
def v3_header_and_data(zork1_v3_data: memoryview) -> Tuple[ZCodeHeader, memoryview]:
    header = get_header(zork1_v3_data)
    return header, zork1_v3_data
Beispiel #7
0
def zork_v5_obj_table(zork1_v5_data: memoryview) -> ZMachineObjectTable:
    header = get_header(zork1_v5_data)
    yield ZMachineObjectTable(zork1_v5_data, header)
Beispiel #8
0
def zork_v3_dict(zork1_v3_data: memoryview) -> ZMachineDictionary:
    header = get_header(zork1_v3_data)
    yield ZMachineDictionary(zork1_v3_data, header)
Beispiel #9
0
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