async def test_too_many_pom_descripts_causes_detailed_direct_message(self):
        """Test the user typing `!poms` when the response of the message
        would exceed Discord limits.
        """
        # Deterministically generate pom descriptions.
        random.seed(42)

        # Make our combined pom descriptions over 6,000 characters.
        descriptions, expected_descriptions = itertools.tee("".join(
            random.choice(string.ascii_letters + string.digits)
            for _ in range(30)) for _ in range(201))
        await Storage.add_poms_to_user_session(self.ctx.author, descriptions,
                                               1)

        # Have at least one "Undesignated" pom.
        await Storage.add_poms_to_user_session(self.ctx.author, None, 1)

        # The command succeeds.
        with assert_not_raises():
            self.ctx.invoked_with = "poms"
            await pombot.commands.do_poms(self.ctx)

        # The user was only DM'd.
        self.assertTrue(self.ctx.author.send.called)
        self.assertFalse(any((self.ctx.send.called, self.ctx.reply.called)))

        # All of the user's poms descripts are displayed in the DM's.
        # NOTE: The first element in Mock.called_args_list is the one that
        # caused the exception. Also, this will turn `_Call`'s into strings.
        actual_combined_response = "\n".join(
            (str(a) for a, _ in self.ctx.author.send.call_args_list[1:]))

        for expected_description in expected_descriptions:
            self.assertIn(expected_description, actual_combined_response)
Exemple #2
0
    def test_actions_get_random_story_from_correct_tier(
        self,
        average_daily_actions,
        expected_tier,
    ):
        """Test actions are retrieved from the correct tier in the actions XMLs
        given a player's average number of daily actions.
        """
        team_name = Pomwars.KNIGHT_ROLE

        tiered_stories = {
            1: {
                "nrm": "tier 1 normal attack",
                "hvy": "tier 1 heavy attack",
                "dfn": "tier 1 defend",
            },
            2: {
                "nrm": "tier 2 normal attack",
                "hvy": "tier 2 heavy attack",
                "dfn": "tier 2 defend",
            },
            3: {
                "nrm": "tier 3 normal attack",
                "hvy": "tier 3 heavy attack",
                "dfn": "tier 3 defend",
            },
        }

        tiers = "".join([f"""\
            <tier level="{tier}">
                <normal_attack>{stories["nrm"]}</normal_attack>
                <heavy_attack>{stories["hvy"]}</heavy_attack>
                <defend>{stories["dfn"]}</defend>
            </tier>
        """ for tier, stories in tiered_stories.items()])

        self.write_actions_xml(textwrap.dedent(f"""\
            <actions>
                <team name="{team_name}">
                    {tiers}
                </team>
            </actions>
        """))

        with assert_not_raises():
            attacks, defends, _ = self.instantiate_actions()

        average = {"average_daily_actions": average_daily_actions}
        team = {"team": team_name}
        team_and_crit = {"critical": False, **team}

        actual_nrm = attacks.get_random(**average, **team_and_crit, heavy=False)
        actual_hvy = attacks.get_random(**average, **team_and_crit, heavy=True)
        actual_dfn = defends.get_random(**average, **team)

        self.assertEqual(tiered_stories[expected_tier]["nrm"], actual_nrm._story)
        self.assertEqual(tiered_stories[expected_tier]["hvy"], actual_hvy._story)
        self.assertEqual(tiered_stories[expected_tier]["dfn"], actual_dfn._story)
    async def test_do_attack_happy_day(
        self,
        user_supplied_args,
        expected_action_type,
        is_action_successful_return_value,
    ):
        """Test `do_attack` does not raise an exception, succeeds, sends an
        embed to the user, updates the scoreboard and adds a pom and action to
        the DB.
        """
        attack.is_action_successful.return_value = is_action_successful_return_value
        State.scoreboard.update = AsyncMock()

        expected_team = Team.KNIGHTS
        role = mock_discord.MockRole(name=expected_team)

        await Storage.add_user(
            user_id=self.ctx.author.id,
            zone=timezone(timedelta(hours=0)),
            team=expected_team.value,
        )
        self.ctx.author.roles.append(role)

        with semantics.assert_not_raises():
            await attack.do_attack(self.ctx, *user_supplied_args)

        actual_poms = await Storage.get_poms()
        self.assertEqual(1, len(actual_poms))
        self.assertEqual(self.ctx.author.id, actual_poms[0].user_id)

        self.assertEqual(1, self.ctx.reply.call_count)
        self.assertIsNotNone(
            self.ctx.reply.call_args_list[0].kwargs.get("embed"))

        self.assertEqual(1, State.scoreboard.update.call_count)

        actual_actions = await Storage.get_actions()
        self.assertEqual(1, len(actual_actions))

        actual_action, = actual_actions
        self.assertEqual(self.ctx.author.id, actual_action.user_id)
        self.assertEqual(is_action_successful_return_value,
                         actual_action.was_successful)
        self.assertEqual(expected_action_type, ActionType(actual_action.type))
        self.assertEqual(expected_team, Team(actual_action.team))
    async def test_attack_does_less_damage_after_enemy_defends(
        self,
        number_of_defenders,
        user_supplied_args,
        attack_is_critical,
        expected_damage_output,
    ):
        """Test that the !attack command does less damage after some amount of
        enemies do their own !defend actions.
        """
        Pomwars.BASE_DAMAGE_FOR_NORMAL_ATTACKS = 10
        Pomwars.BASE_DAMAGE_FOR_HEAVY_ATTACKS = 40
        Pomwars.BASE_CHANCE_FOR_CRITICAL = float(attack_is_critical)
        Pomwars.DAMAGE_MULTIPLIER_FOR_CRITICAL = 1.35

        # For this test, all defenders are level 1.
        Pomwars.DEFEND_LEVEL_MULTIPLIERS = {1: 0.05}

        attack.is_action_successful.return_value = True
        State.scoreboard.update = AsyncMock()

        async def add_player(ctx: Context, team: Team):
            await Storage.add_user(user_id=ctx.author.id,
                                   zone=timezone(timedelta(hours=0)),
                                   team=team.value)
            ctx.author.roles.append(mock_discord.MockRole(name=team.value))

        for _ in range(number_of_defenders):
            new_ctx = mock_discord.MockContext()
            await add_player(new_ctx, Team.VIKINGS)
            await defend.do_defend(new_ctx)

        with semantics.assert_not_raises():
            await add_player(self.ctx, Team.KNIGHTS)
            await attack.do_attack(self.ctx, *user_supplied_args)

        all_actions = await Storage.get_actions()
        assert len(all_actions) == number_of_defenders + 1

        attacker_action = next(a for a in all_actions
                               if a.user_id == self.ctx.author.id)
        self.assertEqual(expected_damage_output, attacker_action.damage)
    def test_actions_get_random_story_from_correct_node(self):
        """Test actions can be retrieved from correctly formed actions XMLs."""
        average_daily_actions = 1

        stories = {
            "kn_crit_nrm": "knight critical normal attack",
            "kn_crit_hvy": "knight critical heavy attack",
            "kn_miss_nrm": "knight missed normal attack",
            "kn_miss_hvy": "knight missed heavy attack",
            "kn_nrm": "knight normal attack",
            "kn_hvy": "knight heavy attack",
            "kn_miss_dfn": "knight missed defend",
            "kn_dfn": "knight defend",
            "vk_crit_nrm": "viking critical normal attack",
            "vk_crit_hvy": "viking critical heavy attack",
            "vk_miss_nrm": "viking missed normal attack",
            "vk_miss_hvy": "viking missed heavy attack",
            "vk_nrm": "viking normal attack",
            "vk_hvy": "viking heavy attack",
            "vk_miss_dfn": "viking missed defend",
            "vk_dfn": "viking defend",
            "br": "bribe",
        }

        self.write_actions_xml(
            textwrap.dedent(f"""\
            <actions>
                <team name="{Pomwars.KNIGHT_ROLE}">
                    <tier level="{average_daily_actions}">
                        <normal_attack outcome="critical">{stories["kn_crit_nrm"]}</normal_attack>
                        <heavy_attack outcome="critical">{stories["kn_crit_hvy"]}</heavy_attack>
                        <normal_attack outcome="missed">{stories["kn_miss_nrm"]}</normal_attack>
                        <heavy_attack outcome="missed">{stories["kn_miss_hvy"]}</heavy_attack>
                        <normal_attack>{stories["kn_nrm"]}</normal_attack>
                        <heavy_attack>{stories["kn_hvy"]}</heavy_attack>
                        <defend outcome="missed">{stories["kn_miss_dfn"]}</defend>
                        <defend>{stories["kn_dfn"]}</defend>
                    </tier>
                </team>
                <team name="{Pomwars.VIKING_ROLE}">
                    <tier level="{average_daily_actions}">
                        <normal_attack outcome="critical">{stories["vk_crit_nrm"]}</normal_attack>
                        <heavy_attack outcome="critical">{stories["vk_crit_hvy"]}</heavy_attack>
                        <normal_attack outcome="missed">{stories["vk_miss_nrm"]}</normal_attack>
                        <heavy_attack outcome="missed">{stories["vk_miss_hvy"]}</heavy_attack>
                        <normal_attack>{stories["vk_nrm"]}</normal_attack>
                        <heavy_attack>{stories["vk_hvy"]}</heavy_attack>
                        <defend outcome="missed">{stories["vk_miss_dfn"]}</defend>
                        <defend>{stories["vk_dfn"]}</defend>
                    </tier>
                </team>
                <bribe>{stories["br"]}</bribe>
            </actions>
        """))

        with assert_not_raises():
            attacks, defends, bribes = self.instantiate_actions()

        average = {"average_daily_actions": average_daily_actions}
        user = {"user": DUMMY_USER}
        timestamp = {"timestamp": DUMMY_TIMESTAMP}

        for action, kwargs, expected_story in (
                # pylint: disable=line-too-long
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.REGULAR,
                "heavy": False
            }, stories["kn_nrm"]),
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.REGULAR,
                "heavy": True
            }, stories["kn_hvy"]),
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.CRITICAL,
                "heavy": False
            }, stories["kn_crit_nrm"]),
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.CRITICAL,
                "heavy": True
            }, stories["kn_crit_hvy"]),
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.MISSED,
                "heavy": False
            }, stories["kn_miss_nrm"]),
            (attacks, {
                **timestamp, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.MISSED,
                "heavy": True
            }, stories["kn_miss_hvy"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.REGULAR,
                "heavy": False
            }, stories["vk_nrm"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.REGULAR,
                "heavy": True
            }, stories["vk_hvy"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.CRITICAL,
                "heavy": False
            }, stories["vk_crit_nrm"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.CRITICAL,
                "heavy": True
            }, stories["vk_crit_hvy"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.MISSED,
                "heavy": False
            }, stories["vk_miss_nrm"]),
            (attacks, {
                **timestamp, "team": Team.VIKINGS,
                **average, "outcome": Outcome.MISSED,
                "heavy": True
            }, stories["vk_miss_hvy"]),
            (defends, {
                **user, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.REGULAR
            }, stories["kn_dfn"]),
            (defends, {
                **user, "team": Team.KNIGHTS,
                **average, "outcome": Outcome.MISSED
            }, stories["kn_miss_dfn"]),
            (defends, {
                **user, "team": Team.VIKINGS,
                **average, "outcome": Outcome.REGULAR
            }, stories["vk_dfn"]),
            (defends, {
                **user, "team": Team.VIKINGS,
                **average, "outcome": Outcome.MISSED
            }, stories["vk_miss_dfn"]),
            (bribes, {}, stories["br"])
                # pylint: enable=line-too-long
        ):
            actual_story = action.get_random(**kwargs)._story
            self.assertEqual(expected_story, actual_story)
Exemple #6
0
    def test_actions_get_random_story_from_correct_node(self):
        """Test actions can be retrieved from correctly formed actions XMLs."""
        average_daily_actions = 1

        stories = {
            "kn_crit_norm": "knight critical normal attack",
            "kn_crit_heav": "knight critical heavy attack",
            "kn_norm":      "knight normal attack",
            "kn_heav":      "knight heavy attack",
            "kn_def":       "knight defend",
            "vk_crit_norm": "viking critical normal attack",
            "vk_crit_heav": "viking critical heavy attack",
            "vk_norm":      "viking normal attack",
            "vk_heav":      "viking heavy attack",
            "vk_def":       "viking defend",
            "br":           "bribe",
        }

        self.write_actions_xml(textwrap.dedent(f"""\
            <actions>
                <team name="{Pomwars.KNIGHT_ROLE}">
                    <tier level="{average_daily_actions}">
                        <normal_attack critical="true">{stories["kn_crit_norm"]}</normal_attack>
                        <heavy_attack critical="true">{stories["kn_crit_heav"]}</heavy_attack>
                        <normal_attack>{stories["kn_norm"]}</normal_attack>
                        <heavy_attack>{stories["kn_heav"]}</heavy_attack>
                        <defend>{stories["kn_def"]}</defend>
                    </tier>
                </team>
                <team name="{Pomwars.VIKING_ROLE}">
                    <tier level="{average_daily_actions}">
                        <normal_attack critical="true">{stories["vk_crit_norm"]}</normal_attack>
                        <heavy_attack critical="true">{stories["vk_crit_heav"]}</heavy_attack>
                        <normal_attack>{stories["vk_norm"]}</normal_attack>
                        <heavy_attack>{stories["vk_heav"]}</heavy_attack>
                        <defend>{stories["vk_def"]}</defend>
                    </tier>
                </team>
                <bribe>{stories["br"]}</bribe>
            </actions>
        """))

        with assert_not_raises():
            attacks, defends, bribes = self.instantiate_actions()

        for action, kwargs, expected_story in (
            # pylint: disable=line-too-long
            (attacks, {"team": Team.KNIGHTS, "average_daily_actions": average_daily_actions, "critical": False, "heavy": False}, stories["kn_norm"]),
            (attacks, {"team": Team.KNIGHTS, "average_daily_actions": average_daily_actions, "critical": False, "heavy": True},  stories["kn_heav"]),
            (attacks, {"team": Team.KNIGHTS, "average_daily_actions": average_daily_actions, "critical": True,  "heavy": False}, stories["kn_crit_norm"]),
            (attacks, {"team": Team.KNIGHTS, "average_daily_actions": average_daily_actions, "critical": True,  "heavy": True},  stories["kn_crit_heav"]),
            (attacks, {"team": Team.VIKINGS, "average_daily_actions": average_daily_actions, "critical": False, "heavy": False}, stories["vk_norm"]),
            (attacks, {"team": Team.VIKINGS, "average_daily_actions": average_daily_actions, "critical": False, "heavy": True},  stories["vk_heav"]),
            (attacks, {"team": Team.VIKINGS, "average_daily_actions": average_daily_actions, "critical": True,  "heavy": False}, stories["vk_crit_norm"]),
            (attacks, {"team": Team.VIKINGS, "average_daily_actions": average_daily_actions, "critical": True,  "heavy": True},  stories["vk_crit_heav"]),

            (defends, {"team": Team.KNIGHTS, "average_daily_actions": average_daily_actions}, stories["kn_def"]),
            (defends, {"team": Team.VIKINGS, "average_daily_actions": average_daily_actions}, stories["vk_def"]),

            (bribes,  {}, stories["br"])
            # pylint: enable=line-too-long
        ):
            actual_story = action.get_random(**kwargs)._story
            self.assertEqual(expected_story, actual_story)