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)
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)
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)