#!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API # Copyright (C) 2015-2024 # Leandro Toledo de Souza # # 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, PaidMedia, PaidMediaInfo, PaidMediaPhoto, PaidMediaPreview, PaidMediaVideo, PhotoSize, Video, ) from telegram.constants import PaidMediaType from tests.auxil.slots import mro_slots @pytest.fixture( scope="module", params=[ PaidMedia.PREVIEW, PaidMedia.PHOTO, PaidMedia.VIDEO, ], ) def pm_scope_type(request): return request.param @pytest.fixture( scope="module", params=[ PaidMediaPreview, PaidMediaPhoto, PaidMediaVideo, ], ids=[ PaidMedia.PREVIEW, PaidMedia.PHOTO, PaidMedia.VIDEO, ], ) def pm_scope_class(request): return request.param @pytest.fixture( scope="module", params=[ ( PaidMediaPreview, PaidMedia.PREVIEW, ), ( PaidMediaPhoto, PaidMedia.PHOTO, ), ( PaidMediaVideo, PaidMedia.VIDEO, ), ], ids=[ PaidMedia.PREVIEW, PaidMedia.PHOTO, PaidMedia.VIDEO, ], ) def pm_scope_class_and_type(request): return request.param @pytest.fixture(scope="module") def paid_media(pm_scope_class_and_type): # We use de_json here so that we don't have to worry about which class gets which arguments return pm_scope_class_and_type[0].de_json( { "type": pm_scope_class_and_type[1], "width": PaidMediaTestBase.width, "height": PaidMediaTestBase.height, "duration": PaidMediaTestBase.duration, "video": PaidMediaTestBase.video.to_dict(), "photo": [p.to_dict() for p in PaidMediaTestBase.photo], }, bot=None, ) def paid_media_video(): return PaidMediaVideo(video=PaidMediaTestBase.video) def paid_media_photo(): return PaidMediaPhoto(photo=PaidMediaTestBase.photo) @pytest.fixture(scope="module") def paid_media_info(): return PaidMediaInfo( star_count=PaidMediaInfoTestBase.star_count, paid_media=[paid_media_video(), paid_media_photo()], ) class PaidMediaTestBase: width = 640 height = 480 duration = 60 video = Video( file_id="video_file_id", width=640, height=480, file_unique_id="file_unique_id", duration=60, ) photo = ( PhotoSize( file_id="photo_file_id", width=640, height=480, file_unique_id="file_unique_id", ), ) class TestPaidMediaWithoutRequest(PaidMediaTestBase): def test_slot_behaviour(self, paid_media): inst = paid_media for attr in inst.__slots__: assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" def test_de_json(self, offline_bot, pm_scope_class_and_type): cls = pm_scope_class_and_type[0] type_ = pm_scope_class_and_type[1] json_dict = { "type": type_, "width": self.width, "height": self.height, "duration": self.duration, "video": self.video.to_dict(), "photo": [p.to_dict() for p in self.photo], } pm = PaidMedia.de_json(json_dict, offline_bot) assert set(pm.api_kwargs.keys()) == { "width", "height", "duration", "video", "photo", } - set(cls.__slots__) assert isinstance(pm, PaidMedia) assert type(pm) is cls assert pm.type == type_ if "width" in cls.__slots__: assert pm.width == self.width assert pm.height == self.height assert pm.duration == self.duration if "video" in cls.__slots__: assert pm.video == self.video if "photo" in cls.__slots__: assert pm.photo == self.photo assert cls.de_json(None, offline_bot) is None assert PaidMedia.de_json({}, offline_bot) is None def test_de_json_invalid_type(self, offline_bot): json_dict = { "type": "invalid", "width": self.width, "height": self.height, "duration": self.duration, "video": self.video.to_dict(), "photo": [p.to_dict() for p in self.photo], } pm = PaidMedia.de_json(json_dict, offline_bot) assert pm.api_kwargs == { "width": self.width, "height": self.height, "duration": self.duration, "video": self.video.to_dict(), "photo": [p.to_dict() for p in self.photo], } assert type(pm) is PaidMedia assert pm.type == "invalid" def test_de_json_subclass(self, pm_scope_class, offline_bot): """This makes sure that e.g. PaidMediaPreivew(data) never returns a TransactionPartnerPhoto instance.""" json_dict = { "type": "invalid", "width": self.width, "height": self.height, "duration": self.duration, "video": self.video.to_dict(), "photo": [p.to_dict() for p in self.photo], } assert type(pm_scope_class.de_json(json_dict, offline_bot)) is pm_scope_class def test_to_dict(self, paid_media): pm_dict = paid_media.to_dict() assert isinstance(pm_dict, dict) assert pm_dict["type"] == paid_media.type if hasattr(paid_media_info, "width"): assert pm_dict["width"] == paid_media.width assert pm_dict["height"] == paid_media.height assert pm_dict["duration"] == paid_media.duration if hasattr(paid_media_info, "video"): assert pm_dict["video"] == paid_media.video.to_dict() if hasattr(paid_media_info, "photo"): assert pm_dict["photo"] == [p.to_dict() for p in paid_media.photo] def test_type_enum_conversion(self): assert type(PaidMedia("video").type) is PaidMediaType assert PaidMedia("unknown").type == "unknown" def test_equality(self, paid_media, offline_bot): a = PaidMedia("base_type") b = PaidMedia("base_type") c = paid_media d = deepcopy(paid_media) 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, "video"): json_dict = c.to_dict() json_dict["video"] = Video("different", "d2", 1, 1, 1).to_dict() f = c.__class__.de_json(json_dict, offline_bot) assert c != f assert hash(c) != hash(f) if hasattr(c, "photo"): json_dict = c.to_dict() json_dict["photo"] = [PhotoSize("different", "d2", 1, 1, 1).to_dict()] f = c.__class__.de_json(json_dict, offline_bot) assert c != f assert hash(c) != hash(f) class PaidMediaInfoTestBase: star_count = 200 paid_media = [paid_media_video(), paid_media_photo()] class TestPaidMediaInfoWithoutRequest(PaidMediaInfoTestBase): def test_slot_behaviour(self, paid_media_info): inst = paid_media_info for attr in inst.__slots__: assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" def test_de_json(self, offline_bot): json_dict = { "star_count": self.star_count, "paid_media": [t.to_dict() for t in self.paid_media], } pmi = PaidMediaInfo.de_json(json_dict, offline_bot) pmi_none = PaidMediaInfo.de_json(None, offline_bot) assert pmi.paid_media == tuple(self.paid_media) assert pmi.star_count == self.star_count assert pmi_none is None def test_to_dict(self, paid_media_info): assert paid_media_info.to_dict() == { "star_count": self.star_count, "paid_media": [t.to_dict() for t in self.paid_media], } def test_equality(self): pmi1 = PaidMediaInfo( star_count=self.star_count, paid_media=[paid_media_video(), paid_media_photo()] ) pmi2 = PaidMediaInfo( star_count=self.star_count, paid_media=[paid_media_video(), paid_media_photo()] ) pmi3 = PaidMediaInfo(star_count=100, paid_media=[paid_media_photo()]) assert pmi1 == pmi2 assert hash(pmi1) == hash(pmi2) assert pmi1 != pmi3 assert hash(pmi1) != hash(pmi3)