2022-05-03 18:21:50 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# A library that provides a Python interface to the Telegram Bot API
|
2024-02-19 20:06:25 +01:00
|
|
|
# Copyright (C) 2015-2024
|
2022-05-03 18:21:50 +02:00
|
|
|
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Lesser Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Lesser Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser Public License
|
|
|
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
|
|
from copy import deepcopy
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
from telegram import (
|
|
|
|
Dice,
|
|
|
|
MenuButton,
|
|
|
|
MenuButtonCommands,
|
2022-05-05 09:27:54 +02:00
|
|
|
MenuButtonDefault,
|
2022-05-03 18:21:50 +02:00
|
|
|
MenuButtonWebApp,
|
|
|
|
WebAppInfo,
|
|
|
|
)
|
2024-01-17 21:32:37 +01:00
|
|
|
from telegram.constants import MenuButtonType
|
2023-02-22 20:19:46 +01:00
|
|
|
from tests.auxil.slots import mro_slots
|
2022-05-03 18:21:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(
|
2023-02-11 10:45:17 +01:00
|
|
|
scope="module",
|
2022-05-03 18:21:50 +02:00
|
|
|
params=[
|
|
|
|
MenuButton.DEFAULT,
|
|
|
|
MenuButton.WEB_APP,
|
|
|
|
MenuButton.COMMANDS,
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def scope_type(request):
|
|
|
|
return request.param
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(
|
2023-02-11 10:45:17 +01:00
|
|
|
scope="module",
|
2022-05-03 18:21:50 +02:00
|
|
|
params=[
|
|
|
|
MenuButtonDefault,
|
|
|
|
MenuButtonCommands,
|
|
|
|
MenuButtonWebApp,
|
|
|
|
],
|
|
|
|
ids=[
|
|
|
|
MenuButton.DEFAULT,
|
|
|
|
MenuButton.COMMANDS,
|
|
|
|
MenuButton.WEB_APP,
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def scope_class(request):
|
|
|
|
return request.param
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(
|
2023-02-11 10:45:17 +01:00
|
|
|
scope="module",
|
2022-05-03 18:21:50 +02:00
|
|
|
params=[
|
|
|
|
(MenuButtonDefault, MenuButton.DEFAULT),
|
|
|
|
(MenuButtonCommands, MenuButton.COMMANDS),
|
|
|
|
(MenuButtonWebApp, MenuButton.WEB_APP),
|
|
|
|
],
|
|
|
|
ids=[
|
|
|
|
MenuButton.DEFAULT,
|
|
|
|
MenuButton.COMMANDS,
|
|
|
|
MenuButton.WEB_APP,
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def scope_class_and_type(request):
|
|
|
|
return request.param
|
|
|
|
|
|
|
|
|
2023-02-11 10:45:17 +01:00
|
|
|
@pytest.fixture(scope="module")
|
2022-05-03 18:21:50 +02:00
|
|
|
def menu_button(scope_class_and_type):
|
2022-10-07 11:51:53 +02:00
|
|
|
# We use de_json here so that we don't have to worry about which class gets which arguments
|
|
|
|
return scope_class_and_type[0].de_json(
|
2023-03-25 19:18:04 +01:00
|
|
|
{
|
|
|
|
"type": scope_class_and_type[1],
|
|
|
|
"text": TestMenuButtonselfBase.text,
|
|
|
|
"web_app": TestMenuButtonselfBase.web_app.to_dict(),
|
|
|
|
},
|
2022-10-07 11:51:53 +02:00
|
|
|
bot=None,
|
2022-05-03 18:21:50 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-02-11 10:45:17 +01:00
|
|
|
class TestMenuButtonselfBase:
|
2022-05-03 18:21:50 +02:00
|
|
|
text = "button_text"
|
|
|
|
web_app = WebAppInfo(url="https://python-telegram-bot.org/web_app")
|
|
|
|
|
2023-02-11 10:45:17 +01:00
|
|
|
|
|
|
|
# All the scope types are very similar, so we test everything via parametrization
|
|
|
|
class TestMenuButtonWithoutRequest(TestMenuButtonselfBase):
|
2023-02-22 20:19:46 +01:00
|
|
|
def test_slot_behaviour(self, menu_button):
|
2022-05-03 18:21:50 +02:00
|
|
|
for attr in menu_button.__slots__:
|
|
|
|
assert getattr(menu_button, attr, "err") != "err", f"got extra slot '{attr}'"
|
|
|
|
assert len(mro_slots(menu_button)) == len(set(mro_slots(menu_button))), "duplicate slot"
|
|
|
|
|
|
|
|
def test_de_json(self, bot, scope_class_and_type):
|
|
|
|
cls = scope_class_and_type[0]
|
|
|
|
type_ = scope_class_and_type[1]
|
|
|
|
|
|
|
|
json_dict = {"type": type_, "text": self.text, "web_app": self.web_app.to_dict()}
|
|
|
|
menu_button = MenuButton.de_json(json_dict, bot)
|
2022-10-07 11:51:53 +02:00
|
|
|
assert set(menu_button.api_kwargs.keys()) == {"text", "web_app"} - set(cls.__slots__)
|
2022-05-03 18:21:50 +02:00
|
|
|
|
|
|
|
assert isinstance(menu_button, MenuButton)
|
|
|
|
assert type(menu_button) is cls
|
|
|
|
assert menu_button.type == type_
|
|
|
|
if "web_app" in cls.__slots__:
|
|
|
|
assert menu_button.web_app == self.web_app
|
|
|
|
if "text" in cls.__slots__:
|
|
|
|
assert menu_button.text == self.text
|
|
|
|
|
2022-10-07 11:51:53 +02:00
|
|
|
assert cls.de_json(None, bot) is None
|
|
|
|
assert MenuButton.de_json({}, bot) is None
|
|
|
|
|
2022-05-03 18:21:50 +02:00
|
|
|
def test_de_json_invalid_type(self, bot):
|
|
|
|
json_dict = {"type": "invalid", "text": self.text, "web_app": self.web_app.to_dict()}
|
|
|
|
menu_button = MenuButton.de_json(json_dict, bot)
|
2022-10-07 11:51:53 +02:00
|
|
|
assert menu_button.api_kwargs == {"text": self.text, "web_app": self.web_app.to_dict()}
|
2022-05-03 18:21:50 +02:00
|
|
|
|
|
|
|
assert type(menu_button) is MenuButton
|
|
|
|
assert menu_button.type == "invalid"
|
|
|
|
|
|
|
|
def test_de_json_subclass(self, scope_class, bot):
|
|
|
|
"""This makes sure that e.g. MenuButtonDefault(data) never returns a
|
|
|
|
MenuButtonChat instance."""
|
|
|
|
json_dict = {"type": "invalid", "text": self.text, "web_app": self.web_app.to_dict()}
|
|
|
|
assert type(scope_class.de_json(json_dict, bot)) is scope_class
|
|
|
|
|
2024-07-10 17:10:33 +02:00
|
|
|
def test_de_json_empty_data(self, scope_class):
|
|
|
|
if scope_class in (MenuButtonWebApp,):
|
|
|
|
pytest.skip(
|
|
|
|
"This test is not relevant for subclasses that have more attributes than just type"
|
|
|
|
)
|
|
|
|
assert isinstance(scope_class.de_json({}, None), scope_class)
|
|
|
|
|
2022-05-03 18:21:50 +02:00
|
|
|
def test_to_dict(self, menu_button):
|
|
|
|
menu_button_dict = menu_button.to_dict()
|
|
|
|
|
|
|
|
assert isinstance(menu_button_dict, dict)
|
|
|
|
assert menu_button_dict["type"] == menu_button.type
|
|
|
|
if hasattr(menu_button, "web_app"):
|
|
|
|
assert menu_button_dict["web_app"] == menu_button.web_app.to_dict()
|
|
|
|
if hasattr(menu_button, "text"):
|
|
|
|
assert menu_button_dict["text"] == menu_button.text
|
|
|
|
|
2024-01-17 21:32:37 +01:00
|
|
|
def test_type_enum_conversion(self):
|
|
|
|
assert type(MenuButton("commands").type) is MenuButtonType
|
|
|
|
assert MenuButton("unknown").type == "unknown"
|
|
|
|
|
2022-05-03 18:21:50 +02:00
|
|
|
def test_equality(self, menu_button, bot):
|
|
|
|
a = MenuButton("base_type")
|
|
|
|
b = MenuButton("base_type")
|
|
|
|
c = menu_button
|
|
|
|
d = deepcopy(menu_button)
|
|
|
|
e = Dice(4, "emoji")
|
|
|
|
|
|
|
|
assert a == b
|
|
|
|
assert hash(a) == hash(b)
|
|
|
|
|
|
|
|
assert a != c
|
|
|
|
assert hash(a) != hash(c)
|
|
|
|
|
|
|
|
assert a != d
|
|
|
|
assert hash(a) != hash(d)
|
|
|
|
|
|
|
|
assert a != e
|
|
|
|
assert hash(a) != hash(e)
|
|
|
|
|
|
|
|
assert c == d
|
|
|
|
assert hash(c) == hash(d)
|
|
|
|
|
|
|
|
assert c != e
|
|
|
|
assert hash(c) != hash(e)
|
|
|
|
|
|
|
|
if hasattr(c, "web_app"):
|
|
|
|
json_dict = c.to_dict()
|
|
|
|
json_dict["web_app"] = WebAppInfo("https://foo.bar/web_app").to_dict()
|
|
|
|
f = c.__class__.de_json(json_dict, bot)
|
|
|
|
|
|
|
|
assert c != f
|
|
|
|
assert hash(c) != hash(f)
|
|
|
|
|
|
|
|
if hasattr(c, "text"):
|
|
|
|
json_dict = c.to_dict()
|
|
|
|
json_dict["text"] = "other text"
|
|
|
|
g = c.__class__.de_json(json_dict, bot)
|
|
|
|
|
|
|
|
assert c != g
|
|
|
|
assert hash(c) != hash(g)
|