diff options
Diffstat (limited to 'tests/test_helpers.py')
| -rw-r--r-- | tests/test_helpers.py | 163 | 
1 files changed, 101 insertions, 62 deletions
| diff --git a/tests/test_helpers.py b/tests/test_helpers.py index f08239981..7894e104a 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -19,7 +19,6 @@ class DiscordMocksTests(unittest.TestCase):          self.assertIsInstance(role, discord.Role)          self.assertEqual(role.name, "role") -        self.assertEqual(role.id, 1)          self.assertEqual(role.position, 1)          self.assertEqual(role.mention, "&role") @@ -27,7 +26,7 @@ class DiscordMocksTests(unittest.TestCase):          """Test if MockRole initializes with the arguments provided."""          role = helpers.MockRole(              name="Admins", -            role_id=90210, +            id=90210,              position=10,          ) @@ -67,22 +66,21 @@ class DiscordMocksTests(unittest.TestCase):          self.assertIsInstance(member, discord.Member)          self.assertEqual(member.name, "member") -        self.assertEqual(member.id, 1) -        self.assertListEqual(member.roles, [helpers.MockRole("@everyone", 1)]) +        self.assertListEqual(member.roles, [helpers.MockRole(name="@everyone", position=1, id=0)])          self.assertEqual(member.mention, "@member")      def test_mock_member_alternative_arguments(self):          """Test if MockMember initializes with the arguments provided.""" -        core_developer = helpers.MockRole("Core Developer", 2) +        core_developer = helpers.MockRole(name="Core Developer", position=2)          member = helpers.MockMember(              name="Mark", -            user_id=12345, +            id=12345,              roles=[core_developer]          )          self.assertEqual(member.name, "Mark")          self.assertEqual(member.id, 12345) -        self.assertListEqual(member.roles, [helpers.MockRole("@everyone", 1), core_developer]) +        self.assertListEqual(member.roles, [helpers.MockRole(name="@everyone", position=1, id=0), core_developer])          self.assertEqual(member.mention, "@Mark")      def test_mock_member_accepts_dynamic_arguments(self): @@ -102,19 +100,19 @@ class DiscordMocksTests(unittest.TestCase):          # 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.roles, [helpers.MockRole(name="@everyone", position=1, id=0)])          self.assertListEqual(guild.members, [])      def test_mock_guild_alternative_arguments(self):          """Test if MockGuild initializes with the arguments provided.""" -        core_developer = helpers.MockRole("Core Developer", 2) +        core_developer = helpers.MockRole(name="Core Developer", position=2)          guild = helpers.MockGuild(              roles=[core_developer], -            members=[helpers.MockMember(user_id=54321)], +            members=[helpers.MockMember(id=54321)],          ) -        self.assertListEqual(guild.roles, [helpers.MockRole("@everyone", 1), core_developer]) -        self.assertListEqual(guild.members, [helpers.MockMember(user_id=54321)]) +        self.assertListEqual(guild.roles, [helpers.MockRole(name="@everyone", position=1, id=0), core_developer]) +        self.assertListEqual(guild.members, [helpers.MockMember(id=54321)])      def test_mock_guild_accepts_dynamic_arguments(self):          """Test if MockGuild accepts and sets abitrary keyword arguments.""" @@ -191,51 +189,30 @@ class DiscordMocksTests(unittest.TestCase):                  with self.assertRaises(AttributeError):                      mock.the_cake_is_a_lie -    def test_custom_mock_methods_are_valid_discord_object_methods(self): -        """The `AsyncMock` attributes of the mocks should be valid for the class they're mocking.""" -        mocks = ( -            (helpers.MockGuild, helpers.guild_instance), -            (helpers.MockRole, helpers.role_instance), -            (helpers.MockMember, helpers.member_instance), -            (helpers.MockBot, helpers.bot_instance), -            (helpers.MockContext, helpers.context_instance), -            (helpers.MockTextChannel, helpers.channel_instance), -            (helpers.MockMessage, helpers.message_instance), +    def test_mocks_use_mention_when_provided_as_kwarg(self): +        """The mock should use the passed `mention` instead of the default one if present.""" +        test_cases = ( +            (helpers.MockRole, "role mention"), +            (helpers.MockMember, "member mention"), +            (helpers.MockTextChannel, "channel mention"),          ) -        for mock_class, instance in mocks: -            mock = mock_class() -            async_methods = ( -                attr for attr in dir(mock) if isinstance(getattr(mock, attr), helpers.AsyncMock) -            ) - -            # spec_mock = unittest.mock.MagicMock(spec=instance) -            for method in async_methods: -                with self.subTest(mock_class=mock_class, method=method): -                    try: -                        getattr(instance, method) -                    except AttributeError: -                        msg = f"method {method} is not a method attribute of {instance.__class__}" -                        self.fail(msg) - -    @unittest.mock.patch(f'{__name__}.DiscordMocksTests.subTest') -    def test_the_custom_mock_methods_test(self, subtest_mock): -        """The custom method test should raise AssertionError for invalid methods.""" -        class FakeMockBot(helpers.AttributeMock, unittest.mock.MagicMock): -            """Fake MockBot class with invalid attribute/method `release_the_walrus`.""" - -            attribute_mocktype = unittest.mock.MagicMock +        for mock_type, mention in test_cases: +            with self.subTest(mock_type=mock_type, mention=mention): +                mock = mock_type(mention=mention) +                self.assertEqual(mock.mention, mention) -            def __init__(self, **kwargs): -                super().__init__(spec=helpers.bot_instance, **kwargs) +    def test_create_test_on_mock_bot_closes_passed_coroutine(self): +        """`bot.loop.create_task` should close the passed coroutine object to prevent warnings.""" +        async def dementati(): +            """Dummy coroutine for testing purposes.""" -                # Fake attribute -                self.release_the_walrus = helpers.AsyncMock() +        coroutine_object = dementati() -        with unittest.mock.patch("tests.helpers.MockBot", new=FakeMockBot): -            msg = "method release_the_walrus is not a valid method of <class 'discord.ext.commands.bot.Bot'>" -            with self.assertRaises(AssertionError, msg=msg): -                self.test_custom_mock_methods_are_valid_discord_object_methods() +        bot = helpers.MockBot() +        bot.loop.create_task(coroutine_object) +        with self.assertRaises(RuntimeError, msg="cannot reuse already awaited coroutine"): +            asyncio.run(coroutine_object)  class MockObjectTests(unittest.TestCase): @@ -266,14 +243,14 @@ class MockObjectTests(unittest.TestCase):      def test_hashable_mixin_uses_id_for_equality_comparison(self):          """Test if the HashableMixing uses the id attribute for hashing.""" -        class MockScragly(unittest.mock.Mock, helpers.HashableMixin): +        class MockScragly(helpers.HashableMixin):              pass -        scragly = MockScragly(spec=object) +        scragly = MockScragly()          scragly.id = 10 -        eevee = MockScragly(spec=object) +        eevee = MockScragly()          eevee.id = 10 -        python = MockScragly(spec=object) +        python = MockScragly()          python.id = 20          self.assertTrue(scragly == eevee) @@ -281,14 +258,14 @@ class MockObjectTests(unittest.TestCase):      def test_hashable_mixin_uses_id_for_nonequality_comparison(self):          """Test if the HashableMixing uses the id attribute for hashing.""" -        class MockScragly(unittest.mock.Mock, helpers.HashableMixin): +        class MockScragly(helpers.HashableMixin):              pass -        scragly = MockScragly(spec=object) +        scragly = MockScragly()          scragly.id = 10 -        eevee = MockScragly(spec=object) +        eevee = MockScragly()          eevee.id = 10 -        python = MockScragly(spec=object) +        python = MockScragly()          python.id = 20          self.assertTrue(scragly != python) @@ -298,7 +275,7 @@ class MockObjectTests(unittest.TestCase):          """Test if the MagicMock subclasses that implement the HashableMixin use id for hash."""          for mock in self.hashable_mocks:              with self.subTest(mock_class=mock): -                instance = helpers.MockRole(role_id=100) +                instance = helpers.MockRole(id=100)                  self.assertEqual(hash(instance), instance.id)      def test_mock_class_with_hashable_mixin_uses_id_for_equality(self): @@ -331,6 +308,18 @@ class MockObjectTests(unittest.TestCase):                  self.assertFalse(instance_one != instance_two)                  self.assertTrue(instance_one != instance_three) +    def test_custom_mock_mixin_accepts_mock_seal(self): +        """The `CustomMockMixin` should support `unittest.mock.seal`.""" +        class MyMock(helpers.CustomMockMixin, unittest.mock.MagicMock): + +            child_mock_type = unittest.mock.MagicMock +            pass + +        mock = MyMock() +        unittest.mock.seal(mock) +        with self.assertRaises(AttributeError, msg="MyMock.shirayuki"): +            mock.shirayuki = "hello!" +      def test_spec_propagation_of_mock_subclasses(self):          """Test if the `spec` does not propagate to attributes of the mock object."""          test_values = ( @@ -339,6 +328,10 @@ class MockObjectTests(unittest.TestCase):              (helpers.MockMember, "display_name"),              (helpers.MockBot, "owner_id"),              (helpers.MockContext, "command_failed"), +            (helpers.MockMessage, "mention_everyone"), +            (helpers.MockEmoji, 'managed'), +            (helpers.MockPartialEmoji, 'url'), +            (helpers.MockReaction, 'me'),          )          for mock_type, valid_attribute in test_values: @@ -346,7 +339,53 @@ class MockObjectTests(unittest.TestCase):                  mock = mock_type()                  self.assertTrue(isinstance(mock, mock_type))                  attribute = getattr(mock, valid_attribute) -                self.assertTrue(isinstance(attribute, mock_type.attribute_mocktype)) +                self.assertTrue(isinstance(attribute, mock_type.child_mock_type)) + +    def test_extract_coroutine_methods_from_spec_instance_should_extract_all_and_only_coroutines(self): +        """Test if all coroutine functions are extracted, but not regular methods or attributes.""" +        class CoroutineDonor: +            def __init__(self): +                self.some_attribute = 'alpha' + +            async def first_coroutine(): +                """This coroutine function should be extracted.""" + +            async def second_coroutine(): +                """This coroutine function should be extracted.""" + +            def regular_method(): +                """This regular function should not be extracted.""" + +        class Receiver: +            pass + +        donor = CoroutineDonor() +        receiver = Receiver() + +        helpers.CustomMockMixin._extract_coroutine_methods_from_spec_instance(receiver, donor) + +        self.assertIsInstance(receiver.first_coroutine, helpers.AsyncMock) +        self.assertIsInstance(receiver.second_coroutine, helpers.AsyncMock) +        self.assertFalse(hasattr(receiver, 'regular_method')) +        self.assertFalse(hasattr(receiver, 'some_attribute')) + +    @unittest.mock.patch("builtins.super", new=unittest.mock.MagicMock()) +    @unittest.mock.patch("tests.helpers.CustomMockMixin._extract_coroutine_methods_from_spec_instance") +    def test_custom_mock_mixin_init_with_spec(self, extract_method_mock): +        """Test if CustomMockMixin correctly passes on spec/kwargs and calls the extraction method.""" +        spec_set = "pydis" + +        helpers.CustomMockMixin(spec_set=spec_set) + +        extract_method_mock.assert_called_once_with(spec_set) + +    @unittest.mock.patch("builtins.super", new=unittest.mock.MagicMock()) +    @unittest.mock.patch("tests.helpers.CustomMockMixin._extract_coroutine_methods_from_spec_instance") +    def test_custom_mock_mixin_init_without_spec(self, extract_method_mock): +        """Test if CustomMockMixin correctly passes on spec/kwargs and calls the extraction method.""" +        helpers.CustomMockMixin() + +        extract_method_mock.assert_not_called()      def test_async_mock_provides_coroutine_for_dunder_call(self):          """Test if AsyncMock objects have a coroutine for their __call__ method.""" | 
