Exemplo n.º 1
0
async def test_interact_with_game(backend, depth: int,
                                  failure_at: Optional[int]):
    # Setup
    backend._fetch_game_status = AsyncMock()
    backend._world = MagicMock() if depth > 0 else None
    backend._get_inventory = AsyncMock()
    if failure_at == 1:
        backend._get_inventory.side_effect = MemoryOperationException(
            "error at _get_inventory")
    backend._has_pending_op = depth <= 1
    backend._update_magic_item = AsyncMock()
    if failure_at == 2:
        backend._update_magic_item.side_effect = MemoryOperationException(
            "error at _check_for_collected_index")
    backend.message_cooldown = 2

    expected_depth = min(depth,
                         failure_at) if failure_at is not None else depth

    # Run
    await backend._interact_with_game(1)

    # Assert
    assert backend.message_cooldown == (2 if expected_depth < 2 else 1)
    backend._fetch_game_status.assert_awaited_once_with()

    if expected_depth > 0:
        backend._get_inventory.assert_awaited_once_with()
    else:
        backend._get_inventory.assert_not_awaited()

    if expected_depth > 1:
        backend._update_magic_item.assert_awaited_once_with()
    else:
        backend._update_magic_item.assert_not_awaited()

    if 0 < depth < (failure_at or 999):
        assert backend._world is not None
    else:
        assert backend._world is None
async def test_update_current_world_invalid(backend, query_result):
    # Setup
    backend.patches = dol_patcher.ALL_VERSIONS_PATCHES[0]
    if query_result is None:
        backend._perform_memory_operations.side_effect = MemoryOperationException("Error")
    else:
        add_memory_op_result(backend, query_result)

    # Run
    await backend._update_current_world()

    # Assert
    assert backend._world is None
Exemplo n.º 3
0
    async def _send_requests_to_socket(self, requests: List[RequestBatch]) -> List[bytes]:
        all_responses = []
        try:
            for request in requests:
                data = request.build_request_data()
                self._socket.writer.write(data)
                await self._socket.writer.drain()
                if request.output_bytes > 0:
                    response = await asyncio.wait_for(self._socket.reader.read(1024), timeout=15)
                    all_responses.append(response)
                else:
                    all_responses.append(b"")

        except (OSError, asyncio.TimeoutError) as e:
            if isinstance(e, asyncio.TimeoutError):
                self.logger.warning(f"Timeout when reading response from {self._ip}")
                self._socket_error = MemoryOperationException(f"Timeout when reading response")
            else:
                self.logger.warning(f"Unable to send {len(requests)} request to {self._ip}:{self._port}: {e}")
                self._socket_error = MemoryOperationException(f"Unable to send {len(requests)} requests: {e}")
            self._disconnect()
            raise self._socket_error from e

        return all_responses
Exemplo n.º 4
0
    def _memory_operation(
            self, op: MemoryOperation,
            pointers: Dict[int, Optional[int]]) -> Optional[bytes]:
        op.validate_byte_sizes()

        address = op.address
        if op.offset is not None:
            if address not in pointers:
                raise MemoryOperationException(
                    f"Invalid op: {address} is not in pointers")
            address = pointers[address] + op.offset

        _validate_range(address, op.byte_count)

        result = None
        if op.read_byte_count is not None:
            result = self.dolphin.read_bytes(address, op.read_byte_count)

        if op.write_bytes is not None:
            self.dolphin.write_bytes(address, op.write_bytes)
            self.logger.debug(f"Wrote {op.write_bytes.hex()} to {address:x}")
        return result
Exemplo n.º 5
0
def _validate_range(address: int, size: int):
    if address < MEM1_START or address + size > MEM1_END:
        raise MemoryOperationException(
            f"Range {address:x} -> {address + size:x} is outside of the GameCube memory range."
        )
Exemplo n.º 6
0
def _was_invalid_address(response: bytes, i: int) -> bool:
    try:
        return not response[i // 8] & (1 << (i % 8))
    except IndexError:
        raise MemoryOperationException("Server response too short for validator bytes")