mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 07:35:19 +00:00
432a67efdd
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
446 lines
16 KiB
Python
446 lines
16 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# A library that provides a Python interface to the Telegram Bot API
|
|
# Copyright (C) 2015-2026
|
|
# 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/].
|
|
import datetime as dtm
|
|
|
|
import pytest
|
|
|
|
from telegram import (
|
|
Chat,
|
|
Checklist,
|
|
ChecklistTask,
|
|
ChecklistTasksAdded,
|
|
ChecklistTasksDone,
|
|
Dice,
|
|
MessageEntity,
|
|
User,
|
|
)
|
|
from telegram._utils.datetime import UTC, to_timestamp
|
|
from telegram.constants import ZERO_DATE
|
|
from tests.auxil.build_messages import make_message
|
|
from tests.auxil.slots import mro_slots
|
|
|
|
|
|
class ChecklistTaskTestBase:
|
|
id = 42
|
|
text = "here is a text"
|
|
text_entities = [
|
|
MessageEntity(type="bold", offset=0, length=4),
|
|
MessageEntity(type="italic", offset=5, length=2),
|
|
]
|
|
completed_by_user = User(id=1, first_name="Test", last_name="User", is_bot=False)
|
|
completed_by_chat = Chat(id=-100, type=Chat.SUPERGROUP, title="Test Chat")
|
|
completion_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def checklist_task():
|
|
return ChecklistTask(
|
|
id=ChecklistTaskTestBase.id,
|
|
text=ChecklistTaskTestBase.text,
|
|
text_entities=ChecklistTaskTestBase.text_entities,
|
|
completed_by_user=ChecklistTaskTestBase.completed_by_user,
|
|
completed_by_chat=ChecklistTaskTestBase.completed_by_chat,
|
|
completion_date=ChecklistTaskTestBase.completion_date,
|
|
)
|
|
|
|
|
|
class TestChecklistTaskWithoutRequest(ChecklistTaskTestBase):
|
|
def test_slot_behaviour(self, checklist_task):
|
|
for attr in checklist_task.__slots__:
|
|
assert getattr(checklist_task, attr, "err") != "err", f"got extra slot '{attr}'"
|
|
assert len(mro_slots(checklist_task)) == len(set(mro_slots(checklist_task))), (
|
|
"duplicate slot"
|
|
)
|
|
|
|
def test_to_dict(self, checklist_task):
|
|
clt_dict = checklist_task.to_dict()
|
|
assert isinstance(clt_dict, dict)
|
|
assert clt_dict["id"] == self.id
|
|
assert clt_dict["text"] == self.text
|
|
assert clt_dict["text_entities"] == [entity.to_dict() for entity in self.text_entities]
|
|
assert clt_dict["completed_by_user"] == self.completed_by_user.to_dict()
|
|
assert clt_dict["completed_by_chat"] == self.completed_by_chat.to_dict()
|
|
assert clt_dict["completion_date"] == to_timestamp(self.completion_date)
|
|
|
|
def test_de_json(self, offline_bot):
|
|
json_dict = {
|
|
"id": self.id,
|
|
"text": self.text,
|
|
"text_entities": [entity.to_dict() for entity in self.text_entities],
|
|
"completed_by_user": self.completed_by_user.to_dict(),
|
|
"completed_by_chat": self.completed_by_chat.to_dict(),
|
|
"completion_date": to_timestamp(self.completion_date),
|
|
}
|
|
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
|
assert isinstance(clt, ChecklistTask)
|
|
assert clt.id == self.id
|
|
assert clt.text == self.text
|
|
assert clt.text_entities == tuple(self.text_entities)
|
|
assert clt.completed_by_user == self.completed_by_user
|
|
assert clt.completed_by_chat == self.completed_by_chat
|
|
assert clt.completion_date == self.completion_date
|
|
assert clt.api_kwargs == {}
|
|
|
|
def test_de_json_required_fields(self, offline_bot):
|
|
json_dict = {
|
|
"id": self.id,
|
|
"text": self.text,
|
|
}
|
|
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
|
assert isinstance(clt, ChecklistTask)
|
|
assert clt.id == self.id
|
|
assert clt.text == self.text
|
|
assert clt.text_entities == ()
|
|
assert clt.completed_by_user is None
|
|
assert clt.completion_date is None
|
|
assert clt.api_kwargs == {}
|
|
|
|
def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
|
|
json_dict = {
|
|
"id": self.id,
|
|
"text": self.text,
|
|
"completion_date": to_timestamp(self.completion_date),
|
|
}
|
|
clt_bot = ChecklistTask.de_json(json_dict, offline_bot)
|
|
clt_bot_raw = ChecklistTask.de_json(json_dict, raw_bot)
|
|
clt_bot_tz = ChecklistTask.de_json(json_dict, tz_bot)
|
|
|
|
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
|
completion_date_offset = clt_bot_tz.completion_date.utcoffset()
|
|
completion_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset(
|
|
clt_bot_tz.completion_date.replace(tzinfo=None)
|
|
)
|
|
|
|
assert clt_bot.completion_date.tzinfo == UTC
|
|
assert clt_bot_raw.completion_date.tzinfo == UTC
|
|
assert completion_date_offset_tz == completion_date_offset
|
|
|
|
@pytest.mark.parametrize(
|
|
("completion_date", "expected"),
|
|
[
|
|
(None, None),
|
|
(0, ZERO_DATE),
|
|
(1735689600, dtm.datetime(2025, 1, 1, tzinfo=UTC)),
|
|
],
|
|
)
|
|
def test_de_json_completion_date(self, offline_bot, completion_date, expected):
|
|
json_dict = {
|
|
"id": self.id,
|
|
"text": self.text,
|
|
"completion_date": completion_date,
|
|
}
|
|
clt = ChecklistTask.de_json(json_dict, offline_bot)
|
|
assert isinstance(clt, ChecklistTask)
|
|
assert clt.completion_date == expected
|
|
|
|
def test_parse_entity(self, checklist_task):
|
|
assert checklist_task.parse_entity(checklist_task.text_entities[0]) == "here"
|
|
|
|
def test_parse_entities(self, checklist_task):
|
|
assert checklist_task.parse_entities(MessageEntity.BOLD) == {
|
|
checklist_task.text_entities[0]: "here"
|
|
}
|
|
assert checklist_task.parse_entities() == {
|
|
checklist_task.text_entities[0]: "here",
|
|
checklist_task.text_entities[1]: "is",
|
|
}
|
|
|
|
def test_equality(self, checklist_task):
|
|
clt1 = checklist_task
|
|
clt2 = ChecklistTask(
|
|
id=self.id,
|
|
text="other text",
|
|
)
|
|
clt3 = ChecklistTask(
|
|
id=self.id + 1,
|
|
text=self.text,
|
|
)
|
|
clt4 = Dice(value=1, emoji="🎲")
|
|
|
|
assert clt1 == clt2
|
|
assert hash(clt1) == hash(clt2)
|
|
|
|
assert clt1 != clt3
|
|
assert hash(clt1) != hash(clt3)
|
|
|
|
assert clt1 != clt4
|
|
assert hash(clt1) != hash(clt4)
|
|
|
|
|
|
class ChecklistTestBase:
|
|
title = "Checklist Title"
|
|
title_entities = [
|
|
MessageEntity(type="bold", offset=0, length=9),
|
|
MessageEntity(type="italic", offset=10, length=5),
|
|
]
|
|
tasks = [
|
|
ChecklistTask(
|
|
id=1,
|
|
text="Task 1",
|
|
),
|
|
ChecklistTask(
|
|
id=2,
|
|
text="Task 2",
|
|
),
|
|
]
|
|
others_can_add_tasks = True
|
|
others_can_mark_tasks_as_done = False
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def checklist():
|
|
return Checklist(
|
|
title=ChecklistTestBase.title,
|
|
title_entities=ChecklistTestBase.title_entities,
|
|
tasks=ChecklistTestBase.tasks,
|
|
others_can_add_tasks=ChecklistTestBase.others_can_add_tasks,
|
|
others_can_mark_tasks_as_done=ChecklistTestBase.others_can_mark_tasks_as_done,
|
|
)
|
|
|
|
|
|
class TestChecklistWithoutRequest(ChecklistTestBase):
|
|
def test_slot_behaviour(self, checklist):
|
|
for attr in checklist.__slots__:
|
|
assert getattr(checklist, attr, "err") != "err", f"got extra slot '{attr}'"
|
|
assert len(mro_slots(checklist)) == len(set(mro_slots(checklist))), "duplicate slot"
|
|
|
|
def test_to_dict(self, checklist):
|
|
cl_dict = checklist.to_dict()
|
|
assert isinstance(cl_dict, dict)
|
|
assert cl_dict["title"] == self.title
|
|
assert cl_dict["title_entities"] == [entity.to_dict() for entity in self.title_entities]
|
|
assert cl_dict["tasks"] == [task.to_dict() for task in self.tasks]
|
|
assert cl_dict["others_can_add_tasks"] is self.others_can_add_tasks
|
|
assert cl_dict["others_can_mark_tasks_as_done"] is self.others_can_mark_tasks_as_done
|
|
|
|
def test_de_json(self, offline_bot):
|
|
json_dict = {
|
|
"title": self.title,
|
|
"title_entities": [entity.to_dict() for entity in self.title_entities],
|
|
"tasks": [task.to_dict() for task in self.tasks],
|
|
"others_can_add_tasks": self.others_can_add_tasks,
|
|
"others_can_mark_tasks_as_done": self.others_can_mark_tasks_as_done,
|
|
}
|
|
cl = Checklist.de_json(json_dict, offline_bot)
|
|
assert isinstance(cl, Checklist)
|
|
assert cl.title == self.title
|
|
assert cl.title_entities == tuple(self.title_entities)
|
|
assert cl.tasks == tuple(self.tasks)
|
|
assert cl.others_can_add_tasks is self.others_can_add_tasks
|
|
assert cl.others_can_mark_tasks_as_done is self.others_can_mark_tasks_as_done
|
|
assert cl.api_kwargs == {}
|
|
|
|
def test_de_json_required_fields(self, offline_bot):
|
|
json_dict = {
|
|
"title": self.title,
|
|
"tasks": [task.to_dict() for task in self.tasks],
|
|
}
|
|
cl = Checklist.de_json(json_dict, offline_bot)
|
|
assert isinstance(cl, Checklist)
|
|
assert cl.title == self.title
|
|
assert cl.title_entities == ()
|
|
assert cl.tasks == tuple(self.tasks)
|
|
assert not cl.others_can_add_tasks
|
|
assert not cl.others_can_mark_tasks_as_done
|
|
|
|
def test_parse_entity(self, checklist):
|
|
assert checklist.parse_entity(checklist.title_entities[0]) == "Checklist"
|
|
assert checklist.parse_entity(checklist.title_entities[1]) == "Title"
|
|
|
|
def test_parse_entities(self, checklist):
|
|
assert checklist.parse_entities(MessageEntity.BOLD) == {
|
|
checklist.title_entities[0]: "Checklist"
|
|
}
|
|
assert checklist.parse_entities() == {
|
|
checklist.title_entities[0]: "Checklist",
|
|
checklist.title_entities[1]: "Title",
|
|
}
|
|
|
|
def test_equality(self, checklist, checklist_task):
|
|
cl1 = checklist
|
|
cl2 = Checklist(
|
|
title=self.title + " other",
|
|
tasks=[ChecklistTask(id=1, text="something"), ChecklistTask(id=2, text="something")],
|
|
)
|
|
cl3 = Checklist(
|
|
title=self.title + " other",
|
|
tasks=[ChecklistTask(id=42, text="Task 2")],
|
|
)
|
|
cl4 = checklist_task
|
|
|
|
assert cl1 == cl2
|
|
assert hash(cl1) == hash(cl2)
|
|
|
|
assert cl1 != cl3
|
|
assert hash(cl1) != hash(cl3)
|
|
|
|
assert cl1 != cl4
|
|
assert hash(cl1) != hash(cl4)
|
|
|
|
|
|
class ChecklistTasksDoneTestBase:
|
|
checklist_message = make_message("Checklist message")
|
|
marked_as_done_task_ids = [1, 2, 3]
|
|
marked_as_not_done_task_ids = [4, 5]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def checklist_tasks_done():
|
|
return ChecklistTasksDone(
|
|
checklist_message=ChecklistTasksDoneTestBase.checklist_message,
|
|
marked_as_done_task_ids=ChecklistTasksDoneTestBase.marked_as_done_task_ids,
|
|
marked_as_not_done_task_ids=ChecklistTasksDoneTestBase.marked_as_not_done_task_ids,
|
|
)
|
|
|
|
|
|
class TestChecklistTasksDoneWithoutRequest(ChecklistTasksDoneTestBase):
|
|
def test_slot_behaviour(self, checklist_tasks_done):
|
|
for attr in checklist_tasks_done.__slots__:
|
|
assert getattr(checklist_tasks_done, attr, "err") != "err", f"got extra slot '{attr}'"
|
|
assert len(mro_slots(checklist_tasks_done)) == len(set(mro_slots(checklist_tasks_done))), (
|
|
"duplicate slot"
|
|
)
|
|
|
|
def test_to_dict(self, checklist_tasks_done):
|
|
cltd_dict = checklist_tasks_done.to_dict()
|
|
assert isinstance(cltd_dict, dict)
|
|
assert cltd_dict["checklist_message"] == self.checklist_message.to_dict()
|
|
assert cltd_dict["marked_as_done_task_ids"] == self.marked_as_done_task_ids
|
|
assert cltd_dict["marked_as_not_done_task_ids"] == self.marked_as_not_done_task_ids
|
|
|
|
def test_de_json(self, offline_bot):
|
|
json_dict = {
|
|
"checklist_message": self.checklist_message.to_dict(),
|
|
"marked_as_done_task_ids": self.marked_as_done_task_ids,
|
|
"marked_as_not_done_task_ids": self.marked_as_not_done_task_ids,
|
|
}
|
|
cltd = ChecklistTasksDone.de_json(json_dict, offline_bot)
|
|
assert isinstance(cltd, ChecklistTasksDone)
|
|
assert cltd.checklist_message == self.checklist_message
|
|
assert cltd.marked_as_done_task_ids == tuple(self.marked_as_done_task_ids)
|
|
assert cltd.marked_as_not_done_task_ids == tuple(self.marked_as_not_done_task_ids)
|
|
assert cltd.api_kwargs == {}
|
|
|
|
def test_de_json_required_fields(self, offline_bot):
|
|
cltd = ChecklistTasksDone.de_json({}, offline_bot)
|
|
assert isinstance(cltd, ChecklistTasksDone)
|
|
assert cltd.checklist_message is None
|
|
assert cltd.marked_as_done_task_ids == ()
|
|
assert cltd.marked_as_not_done_task_ids == ()
|
|
assert cltd.api_kwargs == {}
|
|
|
|
def test_equality(self, checklist_tasks_done):
|
|
cltd1 = checklist_tasks_done
|
|
cltd2 = ChecklistTasksDone(
|
|
checklist_message=None,
|
|
marked_as_done_task_ids=[1, 2, 3],
|
|
marked_as_not_done_task_ids=[4, 5],
|
|
)
|
|
cltd3 = ChecklistTasksDone(
|
|
checklist_message=make_message("Checklist message"),
|
|
marked_as_done_task_ids=[1, 2, 3],
|
|
)
|
|
cltd4 = make_message("Not a checklist tasks done")
|
|
|
|
assert cltd1 == cltd2
|
|
assert hash(cltd1) == hash(cltd2)
|
|
|
|
assert cltd1 != cltd3
|
|
assert hash(cltd1) != hash(cltd3)
|
|
|
|
assert cltd1 != cltd4
|
|
assert hash(cltd1) != hash(cltd4)
|
|
|
|
|
|
class ChecklistTasksAddedTestBase:
|
|
checklist_message = make_message("Checklist message")
|
|
tasks = [
|
|
ChecklistTask(id=1, text="Task 1"),
|
|
ChecklistTask(id=2, text="Task 2"),
|
|
ChecklistTask(id=3, text="Task 3"),
|
|
]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def checklist_tasks_added():
|
|
return ChecklistTasksAdded(
|
|
checklist_message=ChecklistTasksAddedTestBase.checklist_message,
|
|
tasks=ChecklistTasksAddedTestBase.tasks,
|
|
)
|
|
|
|
|
|
class TestChecklistTasksAddedWithoutRequest(ChecklistTasksAddedTestBase):
|
|
def test_slot_behaviour(self, checklist_tasks_added):
|
|
for attr in checklist_tasks_added.__slots__:
|
|
assert getattr(checklist_tasks_added, attr, "err") != "err", f"got extra slot '{attr}'"
|
|
assert len(mro_slots(checklist_tasks_added)) == len(
|
|
set(mro_slots(checklist_tasks_added))
|
|
), "duplicate slot"
|
|
|
|
def test_to_dict(self, checklist_tasks_added):
|
|
clta_dict = checklist_tasks_added.to_dict()
|
|
assert isinstance(clta_dict, dict)
|
|
assert clta_dict["checklist_message"] == self.checklist_message.to_dict()
|
|
assert clta_dict["tasks"] == [task.to_dict() for task in self.tasks]
|
|
|
|
def test_de_json(self, offline_bot):
|
|
json_dict = {
|
|
"checklist_message": self.checklist_message.to_dict(),
|
|
"tasks": [task.to_dict() for task in self.tasks],
|
|
}
|
|
clta = ChecklistTasksAdded.de_json(json_dict, offline_bot)
|
|
assert isinstance(clta, ChecklistTasksAdded)
|
|
assert clta.checklist_message == self.checklist_message
|
|
assert clta.tasks == tuple(self.tasks)
|
|
assert clta.api_kwargs == {}
|
|
|
|
def test_de_json_required_fields(self, offline_bot):
|
|
clta = ChecklistTasksAdded.de_json(
|
|
{"tasks": [task.to_dict() for task in self.tasks]}, offline_bot
|
|
)
|
|
assert isinstance(clta, ChecklistTasksAdded)
|
|
assert clta.checklist_message is None
|
|
assert clta.tasks == tuple(self.tasks)
|
|
assert clta.api_kwargs == {}
|
|
|
|
def test_equality(self, checklist_tasks_added):
|
|
clta1 = checklist_tasks_added
|
|
clta2 = ChecklistTasksAdded(
|
|
checklist_message=None,
|
|
tasks=[
|
|
ChecklistTask(id=1, text="Other Task 1"),
|
|
ChecklistTask(id=2, text="Other Task 2"),
|
|
ChecklistTask(id=3, text="Other Task 3"),
|
|
],
|
|
)
|
|
clta3 = ChecklistTasksAdded(
|
|
checklist_message=make_message("Checklist message"),
|
|
tasks=[ChecklistTask(id=1, text="Task 1")],
|
|
)
|
|
clta4 = make_message("Not a checklist tasks added")
|
|
|
|
assert clta1 == clta2
|
|
assert hash(clta1) == hash(clta2)
|
|
|
|
assert clta1 != clta3
|
|
assert hash(clta1) != hash(clta3)
|
|
|
|
assert clta1 != clta4
|
|
assert hash(clta1) != hash(clta4)
|