async def test_close_already_closed_game():
    # Given
    guild_id = 1007
    game_id = 'game-id-1'

    # We have a closed game
    game = Game(game_id=game_id, guild_id=guild_id, closed=True)
    games_repository = FakeGamesRepository([game])

    event = _make_event(guild_id=guild_id, options={
        'game-id': game.game_id,
    })

    game_already_closed_message = "Game was already closed closed."
    message_provider = MagicMock(MessageProvider)
    message_provider.game_closed.return_value = game_already_closed_message

    route = CloseGameRoute(
        games_repository=games_repository,
        discord_messaging=FakeDiscordMessaging(),
        message_provider=message_provider,
    )

    # When we close it again
    response = await route.call(event)

    # Then it should just still be closed
    saved_game = games_repository.get(guild_id, game.game_id)
    assert saved_game.closed

    assert response.is_ephemeral
    assert response.content == game_already_closed_message
async def test_post_saves_message_id_to_game():
    # Given
    guild_id = 1001
    game_id = 'game-1'
    channel_id = 50001

    new_message_id = 1000
    discord_messaging = FakeDiscordMessaging()
    discord_messaging.created_channel_message_id = 1000

    game = Game(guild_id=guild_id, game_id=game_id)
    games_repository = FakeGamesRepository([game])

    post_route = PostRoute(
        games_repository=games_repository,
        discord_messaging=discord_messaging,
        message_provider=FakeMessageProvider(),
    )

    # When
    event = _make_event(guild_id=guild_id,
                        options={
                            'game-id': game_id,
                            'channel': channel_id,
                        })
    await post_route.call(event)

    # Then
    updated_game = games_repository.get(guild_id, game_id)
    assert updated_game.channel_messages is not None

    assert any(channel_message.channel_id == channel_id
               and channel_message.message_id == new_message_id
               for channel_message in updated_game.channel_messages)
Esempio n. 3
0
async def test_guess_game_does_not_exist():
    # Given
    guild_id = 1001
    game_id = 'fun-game'
    user_id = 2001
    event_channel_id = 7002
    member = DiscordMember()

    fake_games_repository = FakeGamesRepository([])

    error_message = "error dm"
    message_provider = MagicMock(MessageProvider)
    message_provider.error_game_not_found.return_value = error_message

    guess_route = _route(
        games_repository=fake_games_repository,
        message_provider=message_provider,
    )

    # When
    event = _create_guess_event(
        guild_id=guild_id,
        game_id=game_id,
        user_id=user_id,
        event_channel_id=event_channel_id,
        user_nickname='nickname',
        member=member,
    )
    response = await guess_route.call(event)

    # Then
    assert len(fake_games_repository.get_all(guild_id=guild_id)) == 0

    assert response.is_ephemeral
    assert response.content == error_message
Esempio n. 4
0
async def test_guess_non_numerical_on_numeric_game():
    # Given
    guild_id = 1005
    user_id = 13000
    game_id = 'game-id'

    response_message = "Guess must be a number"
    message_provider = MagicMock(MessageProvider, autospec=True)
    message_provider.invalid_guess.return_value = response_message

    # And we have a game with a min and a max
    game = Game(guild_id=guild_id, game_id=game_id, min_guess=1, max_guess=100)

    games_repository = FakeGamesRepository([game])
    guess_route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When
    event = _create_guess_event(guild_id, game.game_id, user_id, 'nickname')
    response = await guess_route.call(event)

    # Then
    assert response.is_ephemeral
    assert response.content == response_message

    # And the guess was not added
    updated_game = games_repository.get(guild_id=guild_id, game_id=game_id)
    assert len(updated_game.guesses) == 0
Esempio n. 5
0
async def test_edit_guess():
    # Given
    guild_id = 10
    game_id = "game-1"
    guessing_player_id = 100
    old_guess = "<My Guess>"

    guess_edited_message = "Guess has been edited."
    message_provider = MagicMock(MessageProvider)
    message_provider.guess_edited.return_value = guess_edited_message

    game = Game(
        guild_id=guild_id,
        game_id=game_id,
        guesses={
            guessing_player_id: GameGuess(
                user_id=guessing_player_id,
                guess=old_guess,
            )
        }
    )
    games_repository = FakeGamesRepository(games=[game])

    game_post_manager = AsyncMock(GamePostManager)

    route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
        game_post_manager=game_post_manager,
    )

    # When
    new_guess = "500"
    event = _make_event(
        guild_id=guild_id,
        options={
            'game-id': game_id,
            'member': str(guessing_player_id),
            'guess': new_guess,
        }
    )
    response = await route.call(event)

    # Then
    updated_game = games_repository.get(guild_id, game_id)
    assert updated_game.guesses[guessing_player_id].guess == new_guess

    game_post_manager.update.assert_called_with(game)

    assert response.is_ephemeral
    assert response.content == guess_edited_message
Esempio n. 6
0
async def test_guess_replies_with_ephemeral_message():
    # Given
    guild_id = 1005
    user_id = 13000
    game_id = 'game-id'

    response_message = "message with new guess"
    message_provider = MagicMock(MessageProvider, autospec=True)
    message_provider.guess_added.return_value = response_message

    game = Game(guild_id=guild_id, game_id=game_id)
    fake_games_repository = FakeGamesRepository([game])

    guess_route = _route(
        games_repository=fake_games_repository,
        message_provider=message_provider,
    )

    # When
    event = _create_guess_event(guild_id, game.game_id, user_id, 'nickname')
    response = await guess_route.call(event)

    # Then
    assert response.is_ephemeral
    assert response.content == response_message
Esempio n. 7
0
async def test_list_all_without_closed_option():
    # Given
    list_games_message = "message listing all games, open and closed"
    message_provider = MagicMock(MessageProvider)
    message_provider.channel_manage_list_all_games.return_value = list_games_message

    open_game = Game(closed=False)
    closed_game = Game(closed=True)
    games_repository = FakeGamesRepository([open_game, closed_game])

    route = ListGamesRoute(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When
    event = _make_event(options={})
    response = await route.call(event)

    # Then
    message_provider.channel_manage_list_all_games.assert_called()
    used_games = message_provider.channel_manage_list_all_games.call_args.args[
        0]
    assert closed_game in used_games
    assert open_game in used_games

    assert response.is_ephemeral
    assert response.content == list_games_message
Esempio n. 8
0
async def test_list_all_open_games():
    # Given
    guild_id = 100

    # We have one open and one closed game
    open_game = Game(closed=False)
    closed_game = Game(closed=True)
    games_repository = FakeGamesRepository([open_game, closed_game])

    # And we have a mock message provider
    list_games_message = "message listing all games, open and closed"
    message_provider = MagicMock(MessageProvider)
    message_provider.channel_manage_list_open_games.return_value = list_games_message

    route = ListGamesRoute(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When we list only the open games
    event = _make_event(guild_id=guild_id, options={'closed': False})
    response = await route.call(event)

    # Then: a message is sent based on only the open games
    message_provider.channel_manage_list_open_games.assert_called()
    used_games = message_provider.channel_manage_list_open_games.call_args.args[
        0]
    assert closed_game not in used_games
    assert open_game in used_games

    assert response.is_ephemeral
    assert response.content == list_games_message
Esempio n. 9
0
async def test_edit_guess_game_does_not_exist():
    # Given
    guild_id = 10
    game_id = "game-1"
    guessing_player_id = 100

    game_not_found_message = "No game found."
    message_provider = MagicMock(MessageProvider)
    message_provider.error_game_not_found.return_value = game_not_found_message

    games_repository = FakeGamesRepository(games=[])

    route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When
    event = _make_event(
        guild_id=guild_id,
        options={
            'game-id': game_id,
            'member': str(guessing_player_id),
            'guess': "some new guess",
        }
    )
    response = await route.call(event)

    # Then
    assert response.is_ephemeral
    assert response.content == game_not_found_message
async def test_post_without_channel_uses_event_channel():
    # Given
    guild_id = 1001
    game_id = 'game-1'
    event_channel_id = 50001

    # We have a game
    game = Game(guild_id=guild_id, game_id=game_id)
    games_repository = FakeGamesRepository([game])

    post_embed = discord.Embed()
    message_provider = MagicMock(MessageProvider)
    message_provider.game_post_embed.return_value = post_embed

    discord_messaging = FakeDiscordMessaging()

    post_route = PostRoute(
        games_repository=games_repository,
        discord_messaging=discord_messaging,
        message_provider=message_provider,
    )

    # When we post a channel message without an explicit target channel
    event = _make_event(guild_id=guild_id,
                        channel_id=event_channel_id,
                        options={'game-id': game_id})
    await post_route.call(event)

    # Then a message for that game is posted in the channel we sent this command from
    assert {
        'channel_id': event_channel_id,
        'embed': post_embed
    } in discord_messaging.sent_channel_messages
Esempio n. 11
0
async def test_guess_updates_channel_messages():
    # Given
    guild_id = 1001
    user_id = 12000

    post_embed = discord.Embed()
    message_provider = MagicMock(MessageProvider)
    message_provider.game_post_embed.return_value = post_embed

    game = Game(
        guild_id=guild_id,
        game_id="game-1",
    )

    games_repository = FakeGamesRepository([game])
    game_post_manager = MagicMock(GamePostManager)

    guess_route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
        game_post_manager=game_post_manager,
    )

    # When
    event = _create_guess_event(guild_id, game.game_id, user_id, 'nickname')
    await guess_route.call(event)

    # Then
    game_post_manager.update.assert_called_with(game)
Esempio n. 12
0
async def test_guess_duplicate_guess():
    # Given
    guild_id = 1000
    game_id = 'game-id'
    event_channel_id = 7002
    guessing_user_id = 2000
    member = DiscordMember(user_id=guessing_user_id, )

    old_guess = '100'
    new_guess = '100'
    existing_guesses = {
        guessing_user_id: GameGuess(user_id=guessing_user_id, guess=old_guess),
    }

    # We have a game
    existing_game = Game(guild_id=guild_id,
                         game_id=game_id,
                         guesses=existing_guesses)
    games_repository = FakeGamesRepository(games=[existing_game])

    duplicate_guess_message = "You already placed a guess for this game."
    message_provider = MagicMock(MessageProvider)
    message_provider.error_duplicate_guess.return_value = duplicate_guess_message

    guess_route = _route(games_repository=games_repository,
                         message_provider=message_provider)

    # When we guess '42' as the same user
    event = _create_guess_event(
        guild_id=guild_id,
        user_id=guessing_user_id,
        game_id=game_id,
        guess=new_guess,
        event_channel_id=event_channel_id,
        member=member,
    )
    response = await guess_route.call(event)

    # Then no new guess is added
    saved_game = games_repository.get(guild_id, existing_game.game_id)
    assert saved_game.guesses[guessing_user_id].guess == old_guess

    # And an ephemeral error is the response
    assert response.is_ephemeral
    assert response.content == duplicate_guess_message
Esempio n. 13
0
async def test_guess_closed_game():
    # Given
    guild_id = 1515
    game_id = 'closed-game'
    guessing_user_id = 3000
    other_user_id = 3050
    event_channel_id = 7775
    member = DiscordMember()

    # We have a closed game
    game = Game(game_id=game_id,
                guild_id=guild_id,
                closed=True,
                guesses={
                    other_user_id: GameGuess(),
                })
    games_repository = FakeGamesRepository([game])

    duplicate_guess_message = "This game has been closed for new guesses."
    message_provider = MagicMock(MessageProvider)
    message_provider.error_guess_on_closed_game.return_value = duplicate_guess_message

    route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When
    event = _create_guess_event(
        guild_id=guild_id,
        game_id=game_id,
        user_id=guessing_user_id,
        event_channel_id=event_channel_id,
        member=member,
    )
    response = await route.call(event)

    # Then: no guess is added
    saved_game = games_repository.get(guild_id, game_id)
    assert list(saved_game.guesses.keys()) == [other_user_id]

    # And an ephemeral error is the response
    assert response.is_ephemeral
    assert response.content == duplicate_guess_message
Esempio n. 14
0
async def test_lower_than_min():
    # Given
    guild_id = 1005
    user_id = 13000
    game_id = 'game-id'

    min_guess = -5

    response_message = "Guess must be a number higher than -5"
    message_provider = MagicMock(MessageProvider, autospec=True)
    message_provider.invalid_guess.return_value = response_message

    # And we have a game with a max
    game = Game(
        guild_id=guild_id,
        game_id=game_id,
        min_guess=min_guess,
    )

    games_repository = FakeGamesRepository([game])
    guess_route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
    )

    # When we guess lower than that
    guess = "-6"
    event = _create_guess_event(
        guild_id=guild_id,
        game_id=game.game_id,
        user_id=user_id,
        user_nickname='nickname',
        guess=guess,
    )
    response = await guess_route.call(event)

    # Then
    assert response.is_ephemeral
    assert response.content == response_message

    # And the guess was not added
    updated_game = games_repository.get(guild_id=guild_id, game_id=game_id)
    assert len(updated_game.guesses) == 0
Esempio n. 15
0
async def test_guess_updates_game_guesses(mock_datetime):
    # Given
    game_id = 'game-id'
    guild_id = 1000
    other_user_id = 5000

    user_id = 100
    user_nickname = 'user-1'
    guess_answer = '42'
    guess_timestamp = datetime.now()

    mock_datetime.now.return_value = guess_timestamp

    existing_game = Game(guild_id=guild_id,
                         game_id=game_id,
                         guesses={
                             other_user_id: GameGuess(),
                         })

    fake_games_repository = FakeGamesRepository([existing_game])

    guess_route = _route(games_repository=fake_games_repository, )

    # When we make a guess
    event = _create_guess_event(guild_id=guild_id,
                                game_id=game_id,
                                user_id=user_id,
                                user_nickname=user_nickname,
                                guess=guess_answer)
    await guess_route.call(event)

    # Then
    saved_game = fake_games_repository.get(guild_id, game_id)
    assert saved_game.guild_id == guild_id
    assert saved_game.game_id == game_id
    assert other_user_id in saved_game.guesses.keys()

    saved_guess = saved_game.guesses[user_id]
    assert saved_guess.user_id == user_id
    assert saved_guess.user_nickname == user_nickname
    assert saved_guess.timestamp == guess_timestamp
    assert saved_guess.guess == guess_answer
async def test_post_creates_channel_message():
    # Given
    guild_id = 1001
    game_id = 'game-1'
    channel_id = 50001

    # We have a game
    game = Game(guild_id=guild_id, game_id=game_id)
    games_repository = FakeGamesRepository([game])

    # And we have a mock message provider
    post_embed = discord.Embed()
    message_provider = MagicMock(MessageProvider)
    message_provider.game_post_embed.return_value = post_embed

    discord_messaging = FakeDiscordMessaging()
    post_route = PostRoute(
        games_repository=games_repository,
        discord_messaging=discord_messaging,
        message_provider=message_provider,
    )

    # When we post a channel message for our game with an explicit channel
    event = _make_event(guild_id=guild_id,
                        options={
                            'game-id': game_id,
                            'channel': channel_id,
                        })
    await post_route.call(event)

    # Then a message about that game is posted in the given channel
    assert {
        'channel_id': channel_id,
        'embed': post_embed
    } in discord_messaging.sent_channel_messages

    # And the channel id is saved in the game
    saved_game = games_repository.get(guild_id, game_id)
    assert len(saved_game.channel_messages) == 1
Esempio n. 17
0
def _route(games_repository=None, message_provider=None, game_post_manager=None):
    if games_repository is None:
        games_repository = FakeGamesRepository()

    if message_provider is None:
        message_provider = MagicMock(MessageProvider)

    if game_post_manager is None:
        game_post_manager = AsyncMock(GamePostManager)

    return EditGuessRoute(
        games_repository=games_repository,
        message_provider=message_provider,
        game_post_manager=game_post_manager,
    )
Esempio n. 18
0
async def test_edit_guess_does_not_exist():
    # Given
    guild_id = 10
    game_id = "game-1"
    delete_member_id = 200

    guess_not_found_message = "No guess found."
    message_provider = MagicMock(MessageProvider)
    message_provider.error_guess_not_found.return_value = guess_not_found_message

    game = Game(
        guild_id=guild_id,
        game_id=game_id,
        guesses={
            -1: GameGuess(
                user_id=-1,
                guess="<your guess>",
            )
        }
    )
    games_repository = FakeGamesRepository(games=[game])

    game_post_manager = AsyncMock(GamePostManager)

    route = _route(
        games_repository=games_repository,
        message_provider=message_provider,
        game_post_manager=game_post_manager,
    )

    # When
    event = _make_event(
        guild_id=guild_id,
        options={
            'game-id': game_id,
            'member': str(delete_member_id),
            'guess': "some new guess",
        }
    )
    response = await route.call(event)

    # Then
    game_post_manager.update.assert_not_called()

    assert response.is_ephemeral
    assert response.content == guess_not_found_message
async def test_close_updates_channel_messages():
    guild_id = 1007
    game_id = 'game-id-1'

    # We have an open game with channel messages
    channel_message_1 = ChannelMessage(channel_id=1, message_id=10)
    channel_message_2 = ChannelMessage(channel_id=2, message_id=11)
    game = Game(game_id=game_id,
                guild_id=guild_id,
                closed=False,
                channel_messages=[channel_message_1, channel_message_2])
    games_repository = FakeGamesRepository([game])

    post_embed = discord.Embed()
    message_provider = MagicMock(MessageProvider)
    message_provider.game_post_embed.return_value = post_embed

    discord_messaging = FakeDiscordMessaging()
    route = CloseGameRoute(
        games_repository=games_repository,
        discord_messaging=discord_messaging,
        message_provider=message_provider,
    )

    # When we close it
    event = _make_event(guild_id=guild_id, options={
        'game-id': game.game_id,
    })
    await route.call(event)

    # Then the channel messages are updated
    assert len(discord_messaging.updated_channel_messages) == 2

    assert {
        'channel_id': channel_message_1.channel_id,
        'message_id': channel_message_1.message_id,
        'embed': post_embed,
    } in discord_messaging.updated_channel_messages

    assert {
        'channel_id': channel_message_2.channel_id,
        'message_id': channel_message_2.message_id,
        'embed': post_embed,
    } in discord_messaging.updated_channel_messages
Esempio n. 20
0
def _route(games_repository: GamesRepository = None,
           message_provider: MessageProvider = None,
           game_post_manager: GamePostManager = None):

    if games_repository is None:
        games_repository = FakeGamesRepository([])

    if message_provider is None:
        message_provider = FakeMessageProvider()

    if game_post_manager is None:
        game_post_manager = AsyncMock(GamePostManager, autospec=True)

    guess_route = GuessRoute(
        games_repository=games_repository,
        message_provider=message_provider,
        game_post_manager=game_post_manager,
    )
    return guess_route
async def test_post_invalid_game_id_sends_dm_error():
    # Given
    guild_id = 1001
    game_id = 'game-1'
    channel_id = 50001
    event_channel_id = 7733

    # We have no games
    games_repository = FakeGamesRepository([])
    discord_messaging = FakeDiscordMessaging()

    formatted_error = "mock formatted error"
    message_provider = MagicMock(MessageProvider)
    message_provider.error_game_not_found.return_value = formatted_error

    post_route = PostRoute(
        games_repository=games_repository,
        discord_messaging=discord_messaging,
        message_provider=message_provider,
    )

    discord_member = DiscordMember()

    # When
    event = _make_event(guild_id=guild_id,
                        discord_member=discord_member,
                        channel_id=event_channel_id,
                        options={
                            'game-id': game_id,
                            'channel': channel_id,
                        })
    response = await post_route.call(event)

    # Then
    message_provider.error_game_not_found.assert_called_with(game_id)

    assert response.is_ephemeral
    assert response.content == formatted_error