async def test_multiworld_interaction_missing_remote_pickups(backend: ConnectionBackend, has_message: bool,
                                                             has_cooldown: bool, has_patches: bool):
    # Setup
    if has_cooldown:
        initial_cooldown = 2.0
    else:
        initial_cooldown = 0.0
    backend.message_cooldown = initial_cooldown

    game_enum = RandovaniaGame.METROID_PRIME_CORRUPTION
    backend.set_expected_game(game_enum)
    patches = [MagicMock()]

    connector = AsyncMock()
    connector.game_enum = game_enum
    backend.connector = connector
    backend._inventory = MagicMock()
    backend._permanent_pickups = MagicMock()

    connector.known_collected_locations.return_value = ([], [])
    connector.find_missing_remote_pickups.return_value = (patches if has_patches else [], has_message)

    # Run
    await backend._multiworld_interaction()

    # Assert
    if has_patches and not (has_cooldown and has_message):
        connector.execute_remote_patches.assert_awaited_once_with(backend.executor, patches)
        if has_message:
            assert backend.message_cooldown == 4.0
        else:
            assert backend.message_cooldown == initial_cooldown
    else:
        connector.execute_remote_patches.assert_not_awaited()
        assert backend.message_cooldown == initial_cooldown
async def test_multiworld_interaction(backend: ConnectionBackend, depth: int):
    # Setup
    # depth 0: wrong game
    # depth 1: non-empty known_collected_locations with patch
    # depth 2: empty known_collected_locations and empty find_missing_remote_pickups

    game_enum = RandovaniaGame.METROID_PRIME_CORRUPTION
    patches = [MagicMock()]

    location_collected = AsyncMock()
    backend.set_location_collected_listener(location_collected)
    if depth > 0:
        backend.set_expected_game(game_enum)

    connector = AsyncMock()
    connector.game_enum = game_enum
    backend.connector = connector
    backend._inventory = MagicMock()
    backend._permanent_pickups = MagicMock()

    connector.find_missing_remote_pickups.return_value = ([], False)
    if depth == 1:
        connector.known_collected_locations.return_value = ([PickupIndex(2), PickupIndex(5)], patches)
    else:
        connector.known_collected_locations.return_value = ([], [])

    # Run
    await backend._multiworld_interaction()

    # Assert
    connector.known_collected_locations.assert_has_awaits(
        [call(backend.executor)]
        if depth > 0 else []
    )
    if depth == 1:
        location_collected.assert_has_awaits([
            call(game_enum, PickupIndex(2)),
            call(game_enum, PickupIndex(5)),
        ])
        connector.execute_remote_patches.assert_awaited_once_with(backend.executor, patches)
    else:
        location_collected.assert_not_awaited()
        connector.execute_remote_patches.assert_not_awaited()

    if depth == 2:
        connector.find_missing_remote_pickups.assert_awaited_once_with(
            backend.executor, backend._inventory, backend._permanent_pickups, False
        )
    else:
        connector.find_missing_remote_pickups.assert_not_awaited()