def setUp(self): super().setUp() self.cog.patch_user = mock.AsyncMock(spec_set=self.cog.patch_user) self.guild_id_patcher = mock.patch("bot.exts.backend.sync._cog.constants.Guild.id", 5) self.guild_id = self.guild_id_patcher.start() self.guild = helpers.MockGuild(id=self.guild_id) self.other_guild = helpers.MockGuild(id=0)
async def test_sync_confirmation_context_redirect(self): """If ctx is given, a new message should be sent and author should be ctx's author.""" mock_member = helpers.MockMember() subtests = ( (None, self.bot.user, None), (helpers.MockContext(author=mock_member), mock_member, helpers.MockMessage()), ) for ctx, author, message in subtests: with self.subTest(ctx=ctx, author=author, message=message): if ctx is not None: ctx.send.return_value = message # Make sure `_get_diff` returns a MagicMock, not an AsyncMock self.syncer._get_diff.return_value = mock.MagicMock() self.syncer._get_confirmation_result = mock.AsyncMock( return_value=(False, None)) guild = helpers.MockGuild() await self.syncer.sync(guild, ctx) if ctx is not None: ctx.send.assert_called_once() self.syncer._get_confirmation_result.assert_called_once() self.assertEqual( self.syncer._get_confirmation_result.call_args[0][1], author) self.assertEqual( self.syncer._get_confirmation_result.call_args[0][2], message)
def setUp(self): self.bot = helpers.MockBot(user=helpers.MockMember(bot=True)) self.syncer = TestSyncer(self.bot) self.guild = helpers.MockGuild() # Make sure `_get_diff` returns a MagicMock, not an AsyncMock self.syncer._get_diff.return_value = mock.MagicMock()
async def test_sync_respects_confirmation_result(self): """The sync should abort if confirmation fails and continue if confirmed.""" mock_message = helpers.MockMessage() subtests = ( (True, mock_message), (False, None), ) for confirmed, message in subtests: with self.subTest(confirmed=confirmed): self.syncer._sync.reset_mock() self.syncer._get_diff.reset_mock() diff = _Diff({1, 2, 3}, {4, 5}, None) self.syncer._get_diff.return_value = diff self.syncer._get_confirmation_result = mock.AsyncMock( return_value=(confirmed, message)) guild = helpers.MockGuild() await self.syncer.sync(guild) self.syncer._get_diff.assert_called_once_with(guild) self.syncer._get_confirmation_result.assert_called_once() if confirmed: self.syncer._sync.assert_called_once_with(diff) else: self.syncer._sync.assert_not_called()
def test_mock_guild_default_initialization(self): """Test if the default initialization of Mockguild results in the correct object.""" guild = helpers.MockGuild() # The `spec` argument makes sure `isistance` checks with `discord.Guild` pass self.assertIsInstance(guild, discord.Guild) self.assertListEqual(guild.roles, [helpers.MockRole("@everyone", 1)]) self.assertListEqual(guild.members, [])
def test_mock_guild_accepts_dynamic_arguments(self): """Test if MockGuild accepts and sets abitrary keyword arguments.""" guild = helpers.MockGuild( emojis=(":hyperjoseph:", ":pensive_ela:"), premium_subscription_count=15, ) self.assertTupleEqual(guild.emojis, (":hyperjoseph:", ":pensive_ela:")) self.assertEqual(guild.premium_subscription_count, 15)
def test_mock_guild_alternative_arguments(self): """Test if MockGuild initializes with the arguments provided.""" core_developer = helpers.MockRole(name="Core Developer", position=2) guild = helpers.MockGuild( roles=[core_developer], members=[helpers.MockMember(id=54321)], ) self.assertListEqual(guild.roles, [helpers.MockRole(name="@everyone", position=1, id=0), core_developer]) self.assertListEqual(guild.members, [helpers.MockMember(id=54321)])
async def test_ship_command(self): context = helpers.MockContext( guild=helpers.MockGuild( members=[helpers.MockMember(), helpers.MockMember()] ) ) await self.cog.ship(self.cog, context) self.assertEqual(context.send.call_args.kwargs.get("embed"), None)
def setUp(self): patcher = mock.patch("bot.instance", new=helpers.MockBot(user=helpers.MockMember(bot=True))) self.bot = patcher.start() self.addCleanup(patcher.stop) self.guild = helpers.MockGuild() TestSyncer._get_diff.reset_mock(return_value=True, side_effect=True) TestSyncer._sync.reset_mock(return_value=True, side_effect=True) # Make sure `_get_diff` returns a MagicMock, not an AsyncMock TestSyncer._get_diff.return_value = mock.MagicMock()
def get_guild(*roles): """Fixture to return a guild object with the given roles.""" guild = helpers.MockGuild() guild.roles = [] for role in roles: mock_role = helpers.MockRole(**role) mock_role.colour = discord.Colour(role["colour"]) mock_role.permissions = discord.Permissions(role["permissions"]) guild.roles.append(mock_role) return guild
def get_guild(*members): """Fixture to return a guild object with the given members.""" guild = helpers.MockGuild() guild.members = [] for member in members: member = member.copy() del member["in_guild"] mock_member = helpers.MockMember(**member) mock_member.roles = [helpers.MockRole(id=role_id) for role_id in member["roles"]] guild.members.append(mock_member) return guild
def test_mocks_rejects_access_to_attributes_not_part_of_spec(self): """Accessing attributes that are invalid for the objects they mock should fail.""" mocks = ( helpers.MockGuild(), helpers.MockRole(), helpers.MockMember(), helpers.MockBot(), helpers.MockContext(), helpers.MockTextChannel(), helpers.MockMessage(), ) for mock in mocks: with self.subTest(mock=mock): with self.assertRaises(AttributeError): mock.the_cake_is_a_lie
def test_mocks_allows_access_to_attributes_part_of_spec(self): """Accessing attributes that are valid for the objects they mock should succeed.""" mocks = ( (helpers.MockGuild(), 'name'), (helpers.MockRole(), 'hoist'), (helpers.MockMember(), 'display_name'), (helpers.MockBot(), 'user'), (helpers.MockContext(), 'invoked_with'), (helpers.MockTextChannel(), 'last_message'), (helpers.MockMessage(), 'mention_everyone'), ) for mock, valid_attribute in mocks: with self.subTest(mock=mock): try: getattr(mock, valid_attribute) except AttributeError: msg = f"accessing valid attribute `{valid_attribute}` raised an AttributeError" self.fail(msg)
async def test_sync_cog_sync_guild(self): """Roles and users should be synced only if a guild is successfully retrieved.""" for guild in (helpers.MockGuild(), None): with self.subTest(guild=guild): self.bot.reset_mock() self.RoleSyncer.reset_mock() self.UserSyncer.reset_mock() self.bot.get_guild = mock.MagicMock(return_value=guild) await self.cog.sync_guild() self.bot.wait_until_guild_available.assert_called_once() self.bot.get_guild.assert_called_once_with(constants.Guild.id) if guild is None: self.RoleSyncer.sync.assert_not_called() self.UserSyncer.sync.assert_not_called() else: self.RoleSyncer.sync.assert_called_once_with(guild) self.UserSyncer.sync.assert_called_once_with(guild)
async def test_sync_message_edited(self): """The message should be edited if one was sent, even if the sync has an API error.""" subtests = ( (None, None, False), (helpers.MockMessage(), None, True), (helpers.MockMessage(), ResponseCodeError(mock.MagicMock()), True), ) for message, side_effect, should_edit in subtests: with self.subTest(message=message, side_effect=side_effect, should_edit=should_edit): self.syncer._sync.side_effect = side_effect self.syncer._get_confirmation_result = mock.AsyncMock( return_value=(True, message)) guild = helpers.MockGuild() await self.syncer.sync(guild) if should_edit: message.edit.assert_called_once() self.assertIn("content", message.edit.call_args[1])
async def test_sync_diff_size(self): """The diff size should be correctly calculated.""" subtests = ( (6, _Diff({1, 2}, {3, 4}, {5, 6})), (5, _Diff({1, 2, 3}, None, {4, 5})), (0, _Diff(None, None, None)), (0, _Diff(set(), set(), set())), ) for size, diff in subtests: with self.subTest(size=size, diff=diff): self.syncer._get_diff.reset_mock() self.syncer._get_diff.return_value = diff self.syncer._get_confirmation_result = mock.AsyncMock( return_value=(False, None)) guild = helpers.MockGuild() await self.syncer.sync(guild) self.syncer._get_diff.assert_called_once_with(guild) self.syncer._get_confirmation_result.assert_called_once() self.assertEqual( self.syncer._get_confirmation_result.call_args[0][0], size)
def test_greeting(): """ Verify that the greeting message is printed correctly. This only tests the information inside the box, not the coloring. All ANSI escape sequences are removed before testing. """ bot = helpers.MockMrFreeze() bot.user.__str__ = lambda _: "BOT.USER #1234" bot.user.id = 1234567890 bot.user.name = "BOT.USER.NAME" bot.guilds = [helpers.MockGuild()] bot.guilds[0].text_channels = [i for i in range(10)] bot.users = [i for i in range(30)] captured_output = io.StringIO() sys.stdout = captured_output greeting.bot_greeting(bot) sys.stdout = sys.__stdout__ output = captured_output.getvalue().splitlines() expected = [ f"#######################################", f"# We have logged in as BOT.USER #1234 #", f"# User name: BOT.USER.NAME #", f"# User ID: 1234567890 #", f"# Number of servers: 1 #", f"# Number of channels: 10 #", f"# Number of users: 30 #", f"#######################################" ] for i in enumerate(expected): actual = colors.strip(output[i[0]]) expected = i[1] test = actual == expected assert test
async def test_server_info_command(self, time_since_patch): time_since_patch.return_value = '2 days ago' self.ctx.guild = helpers.MockGuild( features=('lemons', 'apples'), region="The Moon", roles=[self.moderator_role], channels=[ discord.TextChannel( state={}, guild=self.ctx.guild, data={'id': 42, 'name': 'lemons-offering', 'position': 22, 'type': 'text'} ), discord.CategoryChannel( state={}, guild=self.ctx.guild, data={'id': 5125, 'name': 'the-lemon-collection', 'position': 22, 'type': 'category'} ), discord.VoiceChannel( state={}, guild=self.ctx.guild, data={'id': 15290, 'name': 'listen-to-lemon', 'position': 22, 'type': 'voice'} ) ], members=[ *(helpers.MockMember(status=discord.Status.online) for _ in range(2)), *(helpers.MockMember(status=discord.Status.idle) for _ in range(1)), *(helpers.MockMember(status=discord.Status.dnd) for _ in range(4)), *(helpers.MockMember(status=discord.Status.offline) for _ in range(3)), ], member_count=1_234, icon_url='a-lemon.jpg', ) self.assertIsNone(await self.cog.server_info(self.cog, self.ctx)) time_since_patch.assert_called_once_with(self.ctx.guild.created_at, precision='days') _, kwargs = self.ctx.send.call_args embed = kwargs.pop('embed') self.assertEqual(embed.colour, discord.Colour.blurple()) self.assertEqual( embed.description, textwrap.dedent( f""" **Server information** Created: {time_since_patch.return_value} Voice region: {self.ctx.guild.region} Features: {', '.join(self.ctx.guild.features)} **Channel counts** Category channels: 1 Text channels: 1 Voice channels: 1 Staff channels: 0 **Member counts** Members: {self.ctx.guild.member_count:,} Staff members: 0 Roles: {len(self.ctx.guild.roles)} **Member statuses** {constants.Emojis.status_online} 2 {constants.Emojis.status_idle} 1 {constants.Emojis.status_dnd} 4 {constants.Emojis.status_offline} 3 """ ) ) self.assertEqual(embed.thumbnail.url, 'a-lemon.jpg')