1
# SPDX-License-Identifier: MIT
4
from unittest import mock
9
from disnake.abc import GuildChannel
10
from disnake.utils import MISSING
14
class TestGuildChannelEdit:
15
# TODO: use proper mock models once we have state/guild mocks
18
ch = mock.Mock(GuildChannel, id=123, category_id=456)
19
ch._state = mock.Mock(http=mock.AsyncMock())
20
ch.guild = mock.Mock()
23
parent._overwrites = [mock.Mock() for _ in range(3)]
24
ch.guild.get_channel.return_value = parent
28
async def test_none(self, channel) -> None:
29
res = await GuildChannel._edit(channel, reason="h")
32
channel._move.assert_not_called()
33
channel._state.http.edit_channel.assert_not_called()
35
async def test_all(self, channel) -> None:
36
mock_role = mock.Mock(disnake.Role)
37
mock_member = mock.Mock(disnake.Member)
39
res = await GuildChannel._edit(
42
topic="talk about things here",
45
sync_permissions=False,
46
category=disnake.Object(321),
48
default_thread_slowmode_delay=42,
49
default_auto_archive_duration=disnake.ThreadArchiveDuration.hour,
50
type=disnake.ChannelType.news,
52
mock_role: disnake.PermissionOverwrite(kick_members=False, send_messages=True),
53
mock_member: disnake.PermissionOverwrite(ban_members=False),
58
video_quality_mode=disnake.VideoQualityMode.full,
59
flags=disnake.ChannelFlags(pinned=False, require_tag=True),
60
available_tags=[disnake.ForumTag(name="tag", emoji="woo")],
61
default_reaction=disnake.PartialEmoji(name="woo", id=9876),
62
default_sort_order=disnake.ThreadSortOrder.creation_date,
63
default_layout=disnake.ThreadLayout.gallery_view,
66
assert res is channel._state.http.edit_channel.return_value
68
channel._move.assert_awaited_once_with(
69
10, parent_id=321, lock_permissions=False, reason="stuff"
71
channel._state.http.edit_channel.assert_awaited_once_with(
74
topic="talk about things here",
76
rate_limit_per_user=8,
77
default_thread_rate_limit_per_user=42,
78
default_auto_archive_duration=60,
80
permission_overwrites=[
81
{"allow": "2048", "deny": "2", "id": mock_role.id, "type": 0},
82
{"allow": "0", "deny": "4", "id": mock_member.id, "type": 1},
90
{"name": "tag", "moderated": False, "emoji_name": "woo", "emoji_id": None}
92
default_reaction_emoji={"emoji_name": None, "emoji_id": 9876},
94
default_forum_layout=2,
98
async def test_move_only(self, channel) -> None:
99
# test position and related parameters, shouldn't call `edit_channel`
100
res = await GuildChannel._edit(
101
channel, position=42, category=disnake.Object(999), sync_permissions=True, reason="h"
105
channel._move.assert_awaited_once_with(42, parent_id=999, lock_permissions=True, reason="h")
106
channel._state.http.edit_channel.assert_not_called()
108
async def test_sync_permissions(self, channel) -> None:
109
# test common behavior
110
res = await GuildChannel._edit(channel, sync_permissions=True, reason="yes")
111
assert res is not None
113
channel.guild.get_channel.assert_called_once_with(channel.category_id)
114
channel._move.assert_not_called()
115
channel._state.http.edit_channel.assert_awaited_once_with(
117
permission_overwrites=[
118
o._asdict() for o in channel.guild.get_channel.return_value._overwrites
123
async def test_sync_permissions__no_parent(self, channel) -> None:
124
# moving channel out of category, `sync_permissions` should do nothing
125
res = await GuildChannel._edit(channel, category=None, sync_permissions=True)
126
assert res is not None
128
channel._move.assert_not_called()
129
channel._state.http.edit_channel.assert_awaited_once_with(
135
async def test_sync_permissions__no_parent_cache(self, channel) -> None:
136
# assume parent category doesn't exist in cache
137
channel.guild.get_channel.return_value = None
139
res = await GuildChannel._edit(channel, sync_permissions=True)
142
channel._move.assert_not_called()
143
channel._state.http.edit_channel.assert_not_called()
145
@pytest.mark.parametrize("sync_permissions", [MISSING, True])
146
async def test_overwrites(self, channel, sync_permissions) -> None:
147
# overwrites should override `sync_permissions` parameter
148
res = await GuildChannel._edit(channel, sync_permissions=sync_permissions, overwrites={})
149
assert res is not None
151
channel._move.assert_not_called()
152
channel._state.http.edit_channel.assert_awaited_once_with(
153
channel.id, permission_overwrites=[], reason=None
157
class TestUserProtocol:
158
def _test_typing_assignable(self) -> None:
159
def handle_abc_user(user: disnake.abc.User) -> None:
162
# All of these should match the abc.User protocol and thus type-check correctly
163
# (they could just inherit from the protocol to ensure correct implementation,
164
# but we really only want structural (i.e. implicit) subtyping)
165
handle_abc_user(cast(disnake.User, ...))
166
handle_abc_user(cast(disnake.ClientUser, ...))
167
handle_abc_user(cast(disnake.Member, ...))