def test_webhook_no_ssl(self): self._setup_updater('', messages=0) d = self.updater.dispatcher d.addTelegramMessageHandler(self.telegramHandlerTest) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port for travis self.updater.start_webhook(ip, port) sleep(0.5) # Now, we send an update to the server via urlopen message = Message(1, User(1, "Tester 2"), datetime.now(), Chat(1, 'group', title="Test Group 2")) message.text = "Webhook Test 2" update = Update(1) update.message = message self._send_webhook_msg(ip, port, update.to_json()) sleep(1) self.assertEqual(self.received_message, 'Webhook Test 2')
def test_drop_callback_data_exception(self, bot, app): non_ext_bot = Bot(bot.token) update = Update(0, message=Message(0, None, Chat(1, "chat"), from_user=User(1, "user", False))) callback_context = CallbackContext.from_update(update, app) with pytest.raises(RuntimeError, match="This telegram.ext.ExtBot instance does not"): callback_context.drop_callback_data(None) try: app.bot = non_ext_bot with pytest.raises(RuntimeError, match="telegram.Bot does not allow for"): callback_context.drop_callback_data(None) finally: app.bot = bot
def test_webhook(self, monkeypatch, updater): q = Queue() monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u)) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port updater.start_webhook(ip, port, url_path='TOKEN') sleep(0.2) try: # Now, we send an update to the server via urlopen update = Update( 1, message=Message( 1, None, Chat(1, ''), from_user=User(1, '', False), text='Webhook' ), ) self._send_webhook_msg(ip, port, update.to_json(), 'TOKEN') sleep(0.2) assert q.get(False) == update # Returns 404 if path is incorrect with pytest.raises(HTTPError) as excinfo: self._send_webhook_msg(ip, port, None, 'webookhandler.py') assert excinfo.value.code == 404 with pytest.raises(HTTPError) as excinfo: self._send_webhook_msg( ip, port, None, 'webookhandler.py', get_method=lambda: 'HEAD' ) assert excinfo.value.code == 404 # Test multiple shutdown() calls updater.httpd.shutdown() finally: updater.httpd.shutdown() sleep(0.2) assert not updater.httpd.is_running updater.stop()
def test_deepcopy_telegram_obj(self, bot): chat = Chat(2, Chat.PRIVATE) user = User(3, "first_name", False) date = datetime.datetime.now() photo = PhotoSize("file_id", "unique", 21, 21, bot=bot) msg = Message(1, date, chat, from_user=user, text="foobar", bot=bot, photo=[photo]) new_msg = deepcopy(msg) # The same bot should be present when deepcopying. assert new_msg.get_bot() == bot and new_msg.get_bot() is bot assert new_msg.date == date and new_msg.date is not date assert new_msg.chat == chat and new_msg.chat is not chat assert new_msg.from_user == user and new_msg.from_user is not user assert new_msg.photo[0] == photo and new_msg.photo[0] is not photo
def test_addRemoveTelegramCommandHandler(self): self._setup_updater('', messages=0) d = self.updater.dispatcher handler = CommandHandler('test', self.telegramHandlerTest) self.updater.dispatcher.add_handler(handler) user = User(first_name="singelton", id=404) bot = self.updater.bot queue = self.updater.start_polling(0.01) # regular use message = Message(0, user, None, None, text="/test", bot=bot) queue.put(Update(update_id=0, message=message)) sleep(.1) self.assertEqual(self.received_message, '/test') # assigned use message = Message(0, user, None, None, text="/test@MockBot", bot=bot) queue.put(Update(update_id=0, message=message)) sleep(.1) self.assertEqual(self.received_message, '/test@MockBot') # directed at other bot self.reset() message = Message(0, user, None, None, text="/test@OtherBot", bot=bot) queue.put(Update(update_id=0, message=message)) sleep(.1) self.assertTrue(None is self.received_message) # Remove handler d.removeHandler(handler) handler = CommandHandler('test', self.telegramHandlerEditedTest, allow_edited=False) d.addHandler(handler) self.reset() self.updater.bot.send_messages = 1 sleep(.1) self.assertTrue(None is self.received_message)
class CMDefaults: user = User(1, "First name", False) custom_title: str = "PTB" is_anonymous: bool = True until_date: datetime.datetime = to_timestamp(datetime.datetime.utcnow()) can_be_edited: bool = False can_change_info: bool = True can_post_messages: bool = True can_edit_messages: bool = True can_delete_messages: bool = True can_invite_users: bool = True can_restrict_members: bool = True can_pin_messages: bool = True can_promote_members: bool = True can_send_messages: bool = True can_send_media_messages: bool = True can_send_polls: bool = True can_send_other_messages: bool = True can_add_web_page_previews: bool = True is_member: bool = True can_manage_chat: bool = True can_manage_video_chats: bool = True
def test_endOnFirstMessage(self): self._setup_updater('', messages=0) d = self.updater.dispatcher user = User(first_name="Misses Test", id=123) handler = ConversationHandler( entry_points=[CommandHandler('start', self.start_end)], states={}, fallbacks=[]) d.add_handler(handler) queue = self.updater.start_polling(0.01) # User starts the state machine and immediately ends it. message = Message(0, user, None, self.group, text="/start", bot=self.bot) queue.put(Update(update_id=0, message=message)) sleep(.1) self.assertEquals(len(handler.conversations), 0)
class TestGameHighScore: position = 12 user = User(2, 'test user', False) score = 42 def test_de_json(self, bot): json_dict = {'position': self.position, 'user': self.user.to_dict(), 'score': self.score} highscore = GameHighScore.de_json(json_dict, bot) assert highscore.position == self.position assert highscore.user == self.user assert highscore.score == self.score def test_to_dict(self, game_highscore): game_highscore_dict = game_highscore.to_dict() assert isinstance(game_highscore_dict, dict) assert game_highscore_dict['position'] == game_highscore.position assert game_highscore_dict['user'] == game_highscore.user.to_dict() assert game_highscore_dict['score'] == game_highscore.score
def test_drop_callback_data(self, cdp, monkeypatch, chat_id): monkeypatch.setattr(cdp.bot, 'arbitrary_callback_data', True) update = Update(0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))) callback_context = CallbackContext.from_update(update, cdp) cdp.bot.send_message( chat_id=chat_id, text='test', reply_markup=InlineKeyboardMarkup.from_button( InlineKeyboardButton('test', callback_data='callback_data')), ) keyboard_uuid = cdp.bot.callback_data_cache.persistence_data[0][0][0] button_uuid = list( cdp.bot.callback_data_cache.persistence_data[0][0][2])[0] callback_data = keyboard_uuid + button_uuid callback_query = CallbackQuery( id='1', from_user=None, chat_instance=None, data=callback_data, ) cdp.bot.callback_data_cache.process_callback_query(callback_query) try: assert len(cdp.bot.callback_data_cache.persistence_data[0]) == 1 assert list( cdp.bot.callback_data_cache.persistence_data[1]) == ['1'] callback_context.drop_callback_data(callback_query) assert cdp.bot.callback_data_cache.persistence_data == ([], {}) finally: cdp.bot.callback_data_cache.clear_callback_data() cdp.bot.callback_data_cache.clear_callback_queries()
def test_endOnFirstMessageAsync(self): self._setup_updater('', messages=0) d = self.updater.dispatcher user = User(first_name="Misses Test", id=123) start_end_async = ( lambda bot, update: d.run_async(self.start_end, bot, update)) handler = ConversationHandler( entry_points=[CommandHandler('start', start_end_async)], states={}, fallbacks=[]) d.add_handler(handler) queue = self.updater.start_polling(0.01) # User starts the state machine with an async function that immediately ends the # conversation. Async results are resolved when the users state is queried next time. message = Message(0, user, None, self.group, text="/start", bot=self.bot) queue.put(Update(update_id=0, message=message)) sleep(.1) # Assert that the Promise has been accepted as the new state self.assertEquals(len(handler.conversations), 1) message = Message(0, user, None, self.group, text="resolve promise pls", bot=self.bot) queue.put(Update(update_id=0, message=message)) sleep(.1) # Assert that the Promise has been resolved and the conversation ended. self.assertEquals(len(handler.conversations), 0)
def test_webhook_default_quote(self, monkeypatch, updater): updater._default_quote = True q = Queue() monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u)) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port updater.start_webhook( ip, port, url_path='TOKEN') sleep(.2) # Now, we send an update to the server via urlopen update = Update(1, message=Message(1, User(1, '', False), None, Chat(1, ''), text='Webhook')) self._send_webhook_msg(ip, port, update.to_json(), 'TOKEN') sleep(.2) # assert q.get(False) == update assert q.get(False).message.default_quote is True updater.stop()
def test_process_message_wrong_sender(self, pass_from_user, pass_via_bot, callback_data_cache): reply_markup = InlineKeyboardMarkup.from_button( InlineKeyboardButton('test', callback_data='callback_data')) user = User(1, 'first', False) message = Message( 1, None, None, from_user=user if pass_from_user else None, via_bot=user if pass_via_bot else None, reply_markup=reply_markup, ) callback_data_cache.process_message(message) if pass_from_user or pass_via_bot: # Here we can determine that the message is not from our bot, so no replacing assert message.reply_markup.inline_keyboard[0][ 0].callback_data == 'callback_data' else: # Here we have no chance to know, so InvalidCallbackData assert isinstance( message.reply_markup.inline_keyboard[0][0].callback_data, InvalidCallbackData)
def test_init(self, bot, populated_orchestra, empty_member): orchestra = populated_orchestra orchestra.register_member(empty_member) questioner = Questioner( user_id=empty_member.user_id, orchestra=orchestra, hint_attributes=[], question_attributes=[], number_of_questions=42, bot=bot, multiple_choice=True, ) assert questioner.member == empty_member assert questioner.orchestra is orchestra assert questioner.bot is bot assert questioner.multiple_choice is True assert questioner.score.answers == 0 assert not questioner.current_question assert not questioner.check_update(Update(123)) assert not questioner.check_update( Update(123, poll_answer=PollAnswer(123, User(123, '', False), [1])) )
def test_webhook_no_ssl(self): print('Testing Webhook without SSL') bot = MockBot('', messages=0) self.updater.bot = bot d = self.updater.dispatcher d.addTelegramMessageHandler(self.telegramHandlerTest) # Select random port for travis port = randrange(1024, 49152) self.updater.start_webhook('127.0.0.1', port) sleep(0.5) # Now, we send an update to the server via urlopen message = Message(1, User(1, "Tester 2"), datetime.now(), Chat(1, 'group', title="Test Group 2")) message.text = "Webhook Test 2" update = Update(1) update.message = message try: payload = bytes(update.to_json(), encoding='utf-8') except TypeError: payload = bytes(update.to_json()) header = { 'content-type': 'application/json', 'content-length': str(len(payload)) } r = Request('http://127.0.0.1:%d/' % port, data=payload, headers=header) urlopen(r) sleep(1) self.assertEqual(self.received_message, 'Webhook Test 2')
def test_deprecation_warnings_start_webhook(self, recwarn, updater, monkeypatch): monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True) # prevent api calls from @info decorator when updater.bot.id is used in thread names monkeypatch.setattr(updater.bot, '_bot', User(id=123, first_name='bot', is_bot=True)) monkeypatch.setattr(updater.bot, '_commands', []) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port updater.start_webhook(ip, port, clean=True, force_event_loop=False) updater.stop() for warning in recwarn.list: print(warning.message) assert len(recwarn) == 3 assert str(recwarn[0].message).startswith('Old Handler API') assert str(recwarn[1].message).startswith('The argument `clean` of') assert str(recwarn[2].message).startswith( 'The argument `force_event_loop` of')
def _fetch_updates(self, bot): chat = Chat(id=626525644, type='private', first_name='Wallace', last_name='Reis') user = User(id=626525644, first_name='Wallace', last_name='Reis', is_bot=False, language_code='pt-br') return [ Update(update_id=704571537, message=Message( message_id=22, date=None, chat=chat, text='/hello', delete_chat_photo=False, group_chat_created=False, supergroup_chat_created=False, channel_chat_created=False, from_user=user, bot=bot, )), Update( update_id=704571545, message=Message( message_id=7, date=None, chat=chat, new_chat_members=[user], from_user=user, bot=bot, ), ), ]
class TestPollAnswer(object): poll_id = 'id' user = User(1, '', False) option_ids = [2] def test_de_json(self): json_dict = { 'poll_id': self.poll_id, 'user': self.user.to_dict(), 'option_ids': self.option_ids } poll_answer = PollAnswer.de_json(json_dict, None) assert poll_answer.poll_id == self.poll_id assert poll_answer.user == self.user assert poll_answer.option_ids == self.option_ids def test_to_dict(self, poll_answer): poll_answer_dict = poll_answer.to_dict() assert isinstance(poll_answer_dict, dict) assert poll_answer_dict['poll_id'] == poll_answer.poll_id assert poll_answer_dict['user'] == poll_answer.user.to_dict() assert poll_answer_dict['option_ids'] == poll_answer.option_ids
def test_webhook_no_ssl(self, monkeypatch, updater): q = Queue() monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u)) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port for travis updater.start_webhook(ip, port, webhook_url=None) sleep(.2) # Now, we send an update to the server via urlopen update = Update(1, message=Message(1, User(1, '', False), None, Chat(1, ''), text='Webhook 2')) self._send_webhook_msg(ip, port, update.to_json()) sleep(.2) assert q.get(False) == update
def get_false_update_fixture_decorator_params(): message = Message(1, DATE, Chat(1, ''), from_user=User(1, '', False), text='test') params = [ { 'callback_query': CallbackQuery(1, User(1, '', False), 'chat', message=message) }, { 'channel_post': message }, { 'edited_channel_post': message }, { 'inline_query': InlineQuery(1, User(1, '', False), '', '') }, { 'chosen_inline_result': ChosenInlineResult('id', User(1, '', False), '') }, { 'shipping_query': ShippingQuery('id', User(1, '', False), '', None) }, { 'pre_checkout_query': PreCheckoutQuery('id', User(1, '', False), '', 0, '') }, { 'callback_query': CallbackQuery(1, User(1, '', False), 'chat') }, ] ids = tuple(key for kwargs in params for key in kwargs) return {'params': params, 'ids': ids}
def get_false_update_fixture_decorator_params(): message = Message(1, DATE, Chat(1, ""), from_user=User(1, "", False), text="test") params = [ { "callback_query": CallbackQuery(1, User(1, "", False), "chat", message=message) }, { "channel_post": message }, { "edited_channel_post": message }, { "inline_query": InlineQuery(1, User(1, "", False), "", "") }, { "chosen_inline_result": ChosenInlineResult("id", User(1, "", False), "") }, { "shipping_query": ShippingQuery("id", User(1, "", False), "", None) }, { "pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "") }, { "callback_query": CallbackQuery(1, User(1, "", False), "chat") }, ] ids = tuple(key for kwargs in params for key in kwargs) return {"params": params, "ids": ids}
def test_equality(self): a = ChatInviteLink("link", User(1, '', False), True, True) b = ChatInviteLink("link", User(1, '', False), True, True) d = ChatInviteLink("link", User(2, '', False), False, True) d2 = ChatInviteLink("notalink", User(1, '', False), False, True) d3 = ChatInviteLink("notalink", User(1, '', False), True, True) e = User(1, '', False) assert a == b assert hash(a) == hash(b) assert a is not b assert a != d assert hash(a) != hash(d) assert a != d2 assert hash(a) != hash(d2) assert d2 != d3 assert hash(d2) != hash(d3) assert a != e assert hash(a) != hash(e)
def test_persisting_no_user_no_chat(self, cdp): class OwnPersistence(BasePersistence): def __init__(self): super(OwnPersistence, self).__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True self.test_flag_bot_data = False self.test_flag_chat_data = False self.test_flag_user_data = False def update_bot_data(self, data): self.test_flag_bot_data = True def update_chat_data(self, chat_id, data): self.test_flag_chat_data = True def update_user_data(self, user_id, data): self.test_flag_user_data = True def update_conversation(self, name, key, new_state): pass def get_conversations(self, name): pass def get_user_data(self): pass def get_bot_data(self): pass def get_chat_data(self): pass def callback(update, context): pass handler = MessageHandler(Filters.all, callback) cdp.add_handler(handler) cdp.persistence = OwnPersistence() update = Update(1, message=Message(1, None, None, from_user=User(1, '', False), text='Text')) cdp.process_update(update) assert cdp.persistence.test_flag_bot_data assert cdp.persistence.test_flag_user_data assert not cdp.persistence.test_flag_chat_data cdp.persistence.test_flag_bot_data = False cdp.persistence.test_flag_user_data = False cdp.persistence.test_flag_chat_data = False update = Update(1, message=Message(1, None, Chat(1, ''), from_user=None, text='Text')) cdp.process_update(update) assert cdp.persistence.test_flag_bot_data assert not cdp.persistence.test_flag_user_data assert cdp.persistence.test_flag_chat_data
def test_error_while_persisting(self, cdp, monkeypatch): class OwnPersistence(BasePersistence): def __init__(self): super(OwnPersistence, self).__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True def update(self, data): raise Exception('PersistenceError') def update_bot_data(self, data): self.update(data) def update_chat_data(self, chat_id, data): self.update(data) def update_user_data(self, user_id, data): self.update(data) def get_chat_data(self): pass def get_bot_data(self): pass def get_user_data(self): pass def get_conversations(self, name): pass def update_conversation(self, name, key, new_state): pass def callback(update, context): pass test_flag = False def error(update, context): nonlocal test_flag test_flag = str(context.error) == 'PersistenceError' raise Exception('ErrorHandlingError') def logger(message): assert 'uncaught error was raised while handling' in message update = Update(1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')) handler = MessageHandler(Filters.all, callback) cdp.add_handler(handler) cdp.add_error_handler(error) monkeypatch.setattr(cdp.logger, 'exception', logger) cdp.persistence = OwnPersistence() cdp.process_update(update) assert test_flag
def test_error_while_saving_chat_data(self, bot): increment = [] class OwnPersistence(BasePersistence): def __init__(self): super().__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True def get_bot_data(self): return dict() def update_bot_data(self, data): raise Exception def get_chat_data(self): return defaultdict(dict) def update_chat_data(self, chat_id, data): raise Exception def get_user_data(self): return defaultdict(dict) def update_user_data(self, user_id, data): raise Exception def get_conversations(self, name): pass def update_conversation(self, name, key, new_state): pass def start1(b, u): pass def error(b, u, e): increment.append("error") # If updating a user_data or chat_data from a persistence object throws an error, # the error handler should catch it update = Update( 1, message=Message( 1, None, Chat(1, "lala"), from_user=User(1, "Test", False), text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) my_persistence = OwnPersistence() dp = Dispatcher(bot, None, persistence=my_persistence, use_context=False) dp.add_handler(CommandHandler('start', start1)) dp.add_error_handler(error) dp.process_update(update) assert increment == ["error", "error", "error"]
class TestDispatcher: message_update = Update(1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')) received = None count = 0 @pytest.fixture(autouse=True, name='reset') def reset_fixture(self): self.reset() def reset(self): self.received = None self.count = 0 def error_handler(self, bot, update, error): self.received = error.message def error_handler_context(self, update, context): self.received = context.error.message def error_handler_raise_error(self, bot, update, error): raise Exception('Failing bigly') def callback_increase_count(self, bot, update): self.count += 1 def callback_set_count(self, count): def callback(bot, update): self.count = count return callback def callback_raise_error(self, bot, update): if isinstance(bot, Bot): raise TelegramError(update.message.text) raise TelegramError(bot.message.text) def callback_if_not_update_queue(self, bot, update, update_queue=None): if update_queue is not None: self.received = update.message def callback_context(self, update, context): if (isinstance(context, CallbackContext) and isinstance(context.bot, Bot) and isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and isinstance(context.error, TelegramError)): self.received = context.error.message def test_one_context_per_update(self, cdp): def one(update, context): if update.message.text == 'test': context.my_flag = True def two(update, context): if update.message.text == 'test': if not hasattr(context, 'my_flag'): pytest.fail() else: if hasattr(context, 'my_flag'): pytest.fail() cdp.add_handler(MessageHandler(Filters.regex('test'), one), group=1) cdp.add_handler(MessageHandler(None, two), group=2) u = Update(1, Message(1, None, None, None, text='test')) cdp.process_update(u) u.message.text = 'something' cdp.process_update(u) def test_error_handler(self, dp): dp.add_error_handler(self.error_handler) error = TelegramError('Unauthorized.') dp.update_queue.put(error) sleep(0.1) assert self.received == 'Unauthorized.' # Remove handler dp.remove_error_handler(self.error_handler) self.reset() dp.update_queue.put(error) sleep(0.1) assert self.received is None def test_double_add_error_handler(self, dp, caplog): dp.add_error_handler(self.error_handler) with caplog.at_level(logging.DEBUG): dp.add_error_handler(self.error_handler) assert len(caplog.records) == 1 assert caplog.records[-1].getMessage().startswith( 'The callback is already registered') def test_construction_with_bad_persistence(self, caplog, bot): class my_per: def __init__(self): self.store_user_data = False self.store_chat_data = False self.store_bot_data = False with pytest.raises( TypeError, match= 'persistence must be based on telegram.ext.BasePersistence'): Dispatcher(bot, None, persistence=my_per()) def test_error_handler_that_raises_errors(self, dp): """ Make sure that errors raised in error handlers don't break the main loop of the dispatcher """ handler_raise_error = MessageHandler(Filters.all, self.callback_raise_error) handler_increase_count = MessageHandler(Filters.all, self.callback_increase_count) error = TelegramError('Unauthorized.') dp.add_error_handler(self.error_handler_raise_error) # From errors caused by handlers dp.add_handler(handler_raise_error) dp.update_queue.put(self.message_update) sleep(0.1) # From errors in the update_queue dp.remove_handler(handler_raise_error) dp.add_handler(handler_increase_count) dp.update_queue.put(error) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 1 @pytest.mark.parametrize(['run_async', 'expected_output'], [(True, 5), (False, 0)]) def test_default_run_async_error_handler(self, dp, monkeypatch, run_async, expected_output): def mock_async_err_handler(*args, **kwargs): self.count = 5 # set defaults value to dp.bot dp.bot.defaults = Defaults(run_async=run_async) try: dp.add_handler( MessageHandler(Filters.all, self.callback_raise_error)) dp.add_error_handler(self.error_handler) monkeypatch.setattr(dp, 'run_async', mock_async_err_handler) dp.process_update(self.message_update) assert self.count == expected_output finally: # reset dp.bot.defaults values dp.bot.defaults = None @pytest.mark.parametrize(['run_async', 'expected_output'], [(True, 'running async'), (False, None)]) def test_default_run_async(self, monkeypatch, dp, run_async, expected_output): def mock_run_async(*args, **kwargs): self.received = 'running async' # set defaults value to dp.bot dp.bot.defaults = Defaults(run_async=run_async) try: dp.add_handler(MessageHandler(Filters.all, lambda u, c: None)) monkeypatch.setattr(dp, 'run_async', mock_run_async) dp.process_update(self.message_update) assert self.received == expected_output finally: # reset defaults value dp.bot.defaults = None def test_run_async_multiple(self, bot, dp, dp2): def get_dispatcher_name(q): q.put(current_thread().name) q1 = Queue() q2 = Queue() dp.run_async(get_dispatcher_name, q1) dp2.run_async(get_dispatcher_name, q2) sleep(0.1) name1 = q1.get() name2 = q2.get() assert name1 != name2 def test_multiple_run_async_decorator(self, dp, dp2): # Make sure we got two dispatchers and that they are not the same assert isinstance(dp, Dispatcher) assert isinstance(dp2, Dispatcher) assert dp is not dp2 @run_async def must_raise_runtime_error(): pass with pytest.raises(RuntimeError): must_raise_runtime_error() def test_run_async_with_args(self, dp): dp.add_handler( MessageHandler(Filters.all, run_async(self.callback_if_not_update_queue), pass_update_queue=True)) dp.update_queue.put(self.message_update) sleep(0.1) assert self.received == self.message_update.message def test_multiple_run_async_deprecation(self, dp): assert isinstance(dp, Dispatcher) @run_async def callback(update, context): pass dp.add_handler(MessageHandler(Filters.all, callback)) with pytest.warns(TelegramDeprecationWarning, match='@run_async decorator'): dp.process_update(self.message_update) def test_async_raises_dispatcher_handler_stop(self, dp, caplog): @run_async def callback(update, context): raise DispatcherHandlerStop() dp.add_handler(MessageHandler(Filters.all, callback)) with caplog.at_level(logging.WARNING): dp.update_queue.put(self.message_update) sleep(0.1) assert len(caplog.records) == 1 assert (caplog.records[-1].getMessage().startswith( 'DispatcherHandlerStop is not supported ' 'with async functions')) def test_async_raises_exception(self, dp, caplog): @run_async def callback(update, context): raise RuntimeError('async raising exception') dp.add_handler(MessageHandler(Filters.all, callback)) with caplog.at_level(logging.WARNING): dp.update_queue.put(self.message_update) sleep(0.1) assert len(caplog.records) == 1 assert (caplog.records[-1].getMessage().startswith( 'A promise with deactivated error handling')) def test_add_async_handler(self, dp): dp.add_handler( MessageHandler( Filters.all, self.callback_if_not_update_queue, pass_update_queue=True, run_async=True, )) dp.update_queue.put(self.message_update) sleep(0.1) assert self.received == self.message_update.message def test_run_async_no_error_handler(self, dp, caplog): def func(): raise RuntimeError('Async Error') with caplog.at_level(logging.ERROR): dp.run_async(func) sleep(0.1) assert len(caplog.records) == 1 assert caplog.records[-1].getMessage().startswith( 'No error handlers are registered') def test_async_handler_error_handler(self, dp): dp.add_handler( MessageHandler(Filters.all, self.callback_raise_error, run_async=True)) dp.add_error_handler(self.error_handler) dp.update_queue.put(self.message_update) sleep(0.1) assert self.received == self.message_update.message.text def test_async_handler_async_error_handler_context(self, cdp): cdp.add_handler( MessageHandler(Filters.all, self.callback_raise_error, run_async=True)) cdp.add_error_handler(self.error_handler_context, run_async=True) cdp.update_queue.put(self.message_update) sleep(2) assert self.received == self.message_update.message.text def test_async_handler_error_handler_that_raises_error(self, dp, caplog): handler = MessageHandler(Filters.all, self.callback_raise_error, run_async=True) dp.add_handler(handler) dp.add_error_handler(self.error_handler_raise_error, run_async=False) with caplog.at_level(logging.ERROR): dp.update_queue.put(self.message_update) sleep(0.1) assert len(caplog.records) == 1 assert caplog.records[-1].getMessage().startswith( 'An uncaught error was raised') # Make sure that the main loop still runs dp.remove_handler(handler) dp.add_handler( MessageHandler(Filters.all, self.callback_increase_count, run_async=True)) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 1 def test_async_handler_async_error_handler_that_raises_error( self, dp, caplog): handler = MessageHandler(Filters.all, self.callback_raise_error, run_async=True) dp.add_handler(handler) dp.add_error_handler(self.error_handler_raise_error, run_async=True) with caplog.at_level(logging.ERROR): dp.update_queue.put(self.message_update) sleep(0.1) assert len(caplog.records) == 1 assert caplog.records[-1].getMessage().startswith( 'An uncaught error was raised') # Make sure that the main loop still runs dp.remove_handler(handler) dp.add_handler( MessageHandler(Filters.all, self.callback_increase_count, run_async=True)) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 1 def test_error_in_handler(self, dp): dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error)) dp.add_error_handler(self.error_handler) dp.update_queue.put(self.message_update) sleep(0.1) assert self.received == self.message_update.message.text def test_add_remove_handler(self, dp): handler = MessageHandler(Filters.all, self.callback_increase_count) dp.add_handler(handler) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 1 dp.remove_handler(handler) dp.update_queue.put(self.message_update) assert self.count == 1 def test_add_remove_handler_non_default_group(self, dp): handler = MessageHandler(Filters.all, self.callback_increase_count) dp.add_handler(handler, group=2) with pytest.raises(KeyError): dp.remove_handler(handler) dp.remove_handler(handler, group=2) def test_error_start_twice(self, dp): assert dp.running dp.start() def test_handler_order_in_group(self, dp): dp.add_handler( MessageHandler(Filters.photo, self.callback_set_count(1))) dp.add_handler(MessageHandler(Filters.all, self.callback_set_count(2))) dp.add_handler(MessageHandler(Filters.text, self.callback_set_count(3))) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 2 def test_groups(self, dp): dp.add_handler( MessageHandler(Filters.all, self.callback_increase_count)) dp.add_handler(MessageHandler(Filters.all, self.callback_increase_count), group=2) dp.add_handler(MessageHandler(Filters.all, self.callback_increase_count), group=-1) dp.update_queue.put(self.message_update) sleep(0.1) assert self.count == 3 def test_add_handler_errors(self, dp): handler = 'not a handler' with pytest.raises(TypeError, match='handler is not an instance of'): dp.add_handler(handler) handler = MessageHandler(Filters.photo, self.callback_set_count(1)) with pytest.raises(TypeError, match='group is not int'): dp.add_handler(handler, 'one') def test_flow_stop(self, dp, bot): passed = [] def start1(b, u): passed.append('start1') raise DispatcherHandlerStop def start2(b, u): passed.append('start2') def start3(b, u): passed.append('start3') def error(b, u, e): passed.append('error') passed.append(e) update = Update( 1, message=Message( 1, None, None, None, text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) # If Stop raised handlers in other groups should not be called. passed = [] dp.add_handler(CommandHandler('start', start1), 1) dp.add_handler(CommandHandler('start', start3), 1) dp.add_handler(CommandHandler('start', start2), 2) dp.process_update(update) assert passed == ['start1'] def test_exception_in_handler(self, dp, bot): passed = [] err = Exception('General exception') def start1(b, u): passed.append('start1') raise err def start2(b, u): passed.append('start2') def start3(b, u): passed.append('start3') def error(b, u, e): passed.append('error') passed.append(e) update = Update( 1, message=Message( 1, None, None, None, text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) # If an unhandled exception was caught, no further handlers from the same group should be # called. Also, the error handler should be called and receive the exception passed = [] dp.add_handler(CommandHandler('start', start1), 1) dp.add_handler(CommandHandler('start', start2), 1) dp.add_handler(CommandHandler('start', start3), 2) dp.add_error_handler(error) dp.process_update(update) assert passed == ['start1', 'error', err, 'start3'] def test_telegram_error_in_handler(self, dp, bot): passed = [] err = TelegramError('Telegram error') def start1(b, u): passed.append('start1') raise err def start2(b, u): passed.append('start2') def start3(b, u): passed.append('start3') def error(b, u, e): passed.append('error') passed.append(e) update = Update( 1, message=Message( 1, None, None, None, text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) # If a TelegramException was caught, an error handler should be called and no further # handlers from the same group should be called. dp.add_handler(CommandHandler('start', start1), 1) dp.add_handler(CommandHandler('start', start2), 1) dp.add_handler(CommandHandler('start', start3), 2) dp.add_error_handler(error) dp.process_update(update) assert passed == ['start1', 'error', err, 'start3'] assert passed[2] is err def test_error_while_saving_chat_data(self, bot): increment = [] class OwnPersistence(BasePersistence): def __init__(self): super().__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True def get_bot_data(self): return dict() def update_bot_data(self, data): raise Exception def get_chat_data(self): return defaultdict(dict) def update_chat_data(self, chat_id, data): raise Exception def get_user_data(self): return defaultdict(dict) def update_user_data(self, user_id, data): raise Exception def get_conversations(self, name): pass def update_conversation(self, name, key, new_state): pass def start1(b, u): pass def error(b, u, e): increment.append("error") # If updating a user_data or chat_data from a persistence object throws an error, # the error handler should catch it update = Update( 1, message=Message( 1, None, Chat(1, "lala"), from_user=User(1, "Test", False), text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) my_persistence = OwnPersistence() dp = Dispatcher(bot, None, persistence=my_persistence, use_context=False) dp.add_handler(CommandHandler('start', start1)) dp.add_error_handler(error) dp.process_update(update) assert increment == ["error", "error", "error"] def test_flow_stop_in_error_handler(self, dp, bot): passed = [] err = TelegramError('Telegram error') def start1(b, u): passed.append('start1') raise err def start2(b, u): passed.append('start2') def start3(b, u): passed.append('start3') def error(b, u, e): passed.append('error') passed.append(e) raise DispatcherHandlerStop update = Update( 1, message=Message( 1, None, None, None, text='/start', entities=[ MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0, length=len('/start')) ], bot=bot, ), ) # If a TelegramException was caught, an error handler should be called and no further # handlers from the same group should be called. dp.add_handler(CommandHandler('start', start1), 1) dp.add_handler(CommandHandler('start', start2), 1) dp.add_handler(CommandHandler('start', start3), 2) dp.add_error_handler(error) dp.process_update(update) assert passed == ['start1', 'error', err] assert passed[2] is err def test_error_handler_context(self, cdp): cdp.add_error_handler(self.callback_context) error = TelegramError('Unauthorized.') cdp.update_queue.put(error) sleep(0.1) assert self.received == 'Unauthorized.' def test_sensible_worker_thread_names(self, dp2): thread_names = [ thread.name for thread in getattr(dp2, '_Dispatcher__async_threads') ] print(thread_names) for thread_name in thread_names: assert thread_name.startswith("Bot:{}:worker:".format(dp2.bot.id)) def test_non_context_deprecation(self, dp): with pytest.warns(TelegramDeprecationWarning): Dispatcher(dp.bot, dp.update_queue, job_queue=dp.job_queue, workers=0, use_context=False) def test_error_while_persisting(self, cdp, monkeypatch): class OwnPersistence(BasePersistence): def __init__(self): super(OwnPersistence, self).__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True def update(self, data): raise Exception('PersistenceError') def update_bot_data(self, data): self.update(data) def update_chat_data(self, chat_id, data): self.update(data) def update_user_data(self, user_id, data): self.update(data) def get_chat_data(self): pass def get_bot_data(self): pass def get_user_data(self): pass def get_conversations(self, name): pass def update_conversation(self, name, key, new_state): pass def callback(update, context): pass test_flag = False def error(update, context): nonlocal test_flag test_flag = str(context.error) == 'PersistenceError' raise Exception('ErrorHandlingError') def logger(message): assert 'uncaught error was raised while handling' in message update = Update(1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')) handler = MessageHandler(Filters.all, callback) cdp.add_handler(handler) cdp.add_error_handler(error) monkeypatch.setattr(cdp.logger, 'exception', logger) cdp.persistence = OwnPersistence() cdp.process_update(update) assert test_flag def test_persisting_no_user_no_chat(self, cdp): class OwnPersistence(BasePersistence): def __init__(self): super(OwnPersistence, self).__init__() self.store_user_data = True self.store_chat_data = True self.store_bot_data = True self.test_flag_bot_data = False self.test_flag_chat_data = False self.test_flag_user_data = False def update_bot_data(self, data): self.test_flag_bot_data = True def update_chat_data(self, chat_id, data): self.test_flag_chat_data = True def update_user_data(self, user_id, data): self.test_flag_user_data = True def update_conversation(self, name, key, new_state): pass def get_conversations(self, name): pass def get_user_data(self): pass def get_bot_data(self): pass def get_chat_data(self): pass def callback(update, context): pass handler = MessageHandler(Filters.all, callback) cdp.add_handler(handler) cdp.persistence = OwnPersistence() update = Update(1, message=Message(1, None, None, from_user=User(1, '', False), text='Text')) cdp.process_update(update) assert cdp.persistence.test_flag_bot_data assert cdp.persistence.test_flag_user_data assert not cdp.persistence.test_flag_chat_data cdp.persistence.test_flag_bot_data = False cdp.persistence.test_flag_user_data = False cdp.persistence.test_flag_chat_data = False update = Update(1, message=Message(1, None, Chat(1, ''), from_user=None, text='Text')) cdp.process_update(update) assert cdp.persistence.test_flag_bot_data assert not cdp.persistence.test_flag_user_data assert cdp.persistence.test_flag_chat_data
def user2(): return User(first_name='Mister Test', id=124)
def user1(): return User(first_name='Misses Test', id=123)
class TestMessage: id_ = 1 from_user = User(2, 'testuser', False) date = datetime.utcnow() chat = Chat(3, 'private') test_entities = [ { 'length': 4, 'offset': 10, 'type': 'bold' }, { 'length': 3, 'offset': 16, 'type': 'italic' }, { 'length': 3, 'offset': 20, 'type': 'italic' }, { 'length': 4, 'offset': 25, 'type': 'code' }, { 'length': 5, 'offset': 31, 'type': 'text_link', 'url': 'http://github.com/ab_' }, { 'length': 12, 'offset': 38, 'type': 'text_mention', 'user': User(123456789, 'mentioned user', False), }, { 'length': 3, 'offset': 55, 'type': 'pre', 'language': 'python' }, { 'length': 21, 'offset': 60, 'type': 'url' }, ] test_text = 'Test for <bold, ita_lic, code, links, text-mention and pre. http://google.com/ab_' test_entities_v2 = [ { 'length': 4, 'offset': 0, 'type': 'underline' }, { 'length': 4, 'offset': 10, 'type': 'bold' }, { 'length': 7, 'offset': 16, 'type': 'italic' }, { 'length': 6, 'offset': 25, 'type': 'code' }, { 'length': 5, 'offset': 33, 'type': 'text_link', 'url': r'http://github.com/abc\)def' }, { 'length': 12, 'offset': 40, 'type': 'text_mention', 'user': User(123456789, 'mentioned user', False), }, { 'length': 5, 'offset': 57, 'type': 'pre' }, { 'length': 17, 'offset': 64, 'type': 'url' }, { 'length': 36, 'offset': 86, 'type': 'italic' }, { 'length': 24, 'offset': 91, 'type': 'bold' }, { 'length': 4, 'offset': 101, 'type': 'strikethrough' }, { 'length': 10, 'offset': 124, 'type': 'pre', 'language': 'python' }, ] test_text_v2 = ( r'Test for <bold, ita_lic, \`code, links, text-mention and `\pre. ' 'http://google.com and bold nested in strk nested in italic. Python pre.' ) test_message = Message( message_id=1, from_user=None, date=None, chat=None, text=test_text, entities=[MessageEntity(**e) for e in test_entities], caption=test_text, caption_entities=[MessageEntity(**e) for e in test_entities], ) test_message_v2 = Message( message_id=1, from_user=None, date=None, chat=None, text=test_text_v2, entities=[MessageEntity(**e) for e in test_entities_v2], caption=test_text_v2, caption_entities=[MessageEntity(**e) for e in test_entities_v2], ) def test_all_possibilities_de_json_and_to_dict(self, bot, message_params): new = Message.de_json(message_params.to_dict(), bot) assert new.to_dict() == message_params.to_dict() def test_dict_approach(self, message): assert message['text'] == message.text assert message['chat_id'] == message.chat_id assert message['no_key'] is None def test_parse_entity(self): text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467' b'\\u200d\\U0001f467\\U0001f431http://google.com' ).decode('unicode-escape') entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17) message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[entity]) assert message.parse_entity(entity) == 'http://google.com' def test_parse_caption_entity(self): caption = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467' b'\\u200d\\U0001f467\\U0001f431http://google.com' ).decode('unicode-escape') entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17) message = Message(1, self.from_user, self.date, self.chat, caption=caption, caption_entities=[entity]) assert message.parse_caption_entity(entity) == 'http://google.com' def test_parse_entities(self): text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467' b'\\u200d\\U0001f467\\U0001f431http://google.com' ).decode('unicode-escape') entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17) entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1) message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[entity_2, entity]) assert message.parse_entities(MessageEntity.URL) == { entity: 'http://google.com' } assert message.parse_entities() == { entity: 'http://google.com', entity_2: 'h' } def test_parse_caption_entities(self): text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467' b'\\u200d\\U0001f467\\U0001f431http://google.com' ).decode('unicode-escape') entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17) entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1) message = Message( 1, self.from_user, self.date, self.chat, caption=text, caption_entities=[entity_2, entity], ) assert message.parse_caption_entities(MessageEntity.URL) == { entity: 'http://google.com' } assert message.parse_caption_entities() == { entity: 'http://google.com', entity_2: 'h' } def test_text_html_simple(self): test_html_string = ( '<u>Test</u> for <<b>bold</b>, <i>ita_lic</i>, ' r'<code>\`code</code>, ' r'<a href="http://github.com/abc\)def">links</a>, ' '<a href="tg://user?id=123456789">text-mention</a> and ' r'<pre>`\pre</pre>. http://google.com ' 'and <i>bold <b>nested in <s>strk</s> nested in</b> italic</i>. ' '<pre><code class="python">Python pre</code></pre>.') text_html = self.test_message_v2.text_html assert text_html == test_html_string def test_text_html_empty(self, message): message.text = None message.caption = "test" assert message.text_html is None def test_text_html_urled(self): test_html_string = ( '<u>Test</u> for <<b>bold</b>, <i>ita_lic</i>, ' r'<code>\`code</code>, ' r'<a href="http://github.com/abc\)def">links</a>, ' '<a href="tg://user?id=123456789">text-mention</a> and ' r'<pre>`\pre</pre>. <a href="http://google.com">http://google.com</a> ' 'and <i>bold <b>nested in <s>strk</s> nested in</b> italic</i>. ' '<pre><code class="python">Python pre</code></pre>.') text_html = self.test_message_v2.text_html_urled assert text_html == test_html_string def test_text_markdown_simple(self): test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' '[text-mention](tg://user?id=123456789) and ```python\npre```. ' r'http://google.com/ab\_') text_markdown = self.test_message.text_markdown assert text_markdown == test_md_string def test_text_markdown_v2_simple(self): test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' '[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. ' r'http://google\.com and _bold *nested in ~strk~ nested in* italic_\. ' '```python\nPython pre```\\.') text_markdown = self.test_message_v2.text_markdown_v2 assert text_markdown == test_md_string def test_text_markdown_new_in_v2(self, message): message.text = 'test' message.entities = [ MessageEntity(MessageEntity.BOLD, offset=0, length=4), MessageEntity(MessageEntity.ITALIC, offset=0, length=4), ] with pytest.raises(ValueError): assert message.text_markdown message.entities = [ MessageEntity(MessageEntity.UNDERLINE, offset=0, length=4) ] with pytest.raises(ValueError): message.text_markdown message.entities = [ MessageEntity(MessageEntity.STRIKETHROUGH, offset=0, length=4) ] with pytest.raises(ValueError): message.text_markdown message.entities = [] def test_text_markdown_empty(self, message): message.text = None message.caption = "test" assert message.text_markdown is None assert message.text_markdown_v2 is None def test_text_markdown_urled(self): test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' '[text-mention](tg://user?id=123456789) and ```python\npre```. ' '[http://google.com/ab_](http://google.com/ab_)') text_markdown = self.test_message.text_markdown_urled assert text_markdown == test_md_string def test_text_markdown_v2_urled(self): test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' '[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. ' r'[http://google\.com](http://google.com) and _bold *nested in ~strk~ ' 'nested in* italic_\\. ```python\nPython pre```\\.') text_markdown = self.test_message_v2.text_markdown_v2_urled assert text_markdown == test_md_string def test_text_html_emoji(self): text = b'\\U0001f469\\u200d\\U0001f469\\u200d ABC'.decode( 'unicode-escape') expected = b'\\U0001f469\\u200d\\U0001f469\\u200d <b>ABC</b>'.decode( 'unicode-escape') bold_entity = MessageEntity(type=MessageEntity.BOLD, offset=7, length=3) message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[bold_entity]) assert expected == message.text_html def test_text_markdown_emoji(self): text = b'\\U0001f469\\u200d\\U0001f469\\u200d ABC'.decode( 'unicode-escape') expected = b'\\U0001f469\\u200d\\U0001f469\\u200d *ABC*'.decode( 'unicode-escape') bold_entity = MessageEntity(type=MessageEntity.BOLD, offset=7, length=3) message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[bold_entity]) assert expected == message.text_markdown def test_caption_html_simple(self): test_html_string = ( '<u>Test</u> for <<b>bold</b>, <i>ita_lic</i>, ' r'<code>\`code</code>, ' r'<a href="http://github.com/abc\)def">links</a>, ' '<a href="tg://user?id=123456789">text-mention</a> and ' r'<pre>`\pre</pre>. http://google.com ' 'and <i>bold <b>nested in <s>strk</s> nested in</b> italic</i>. ' '<pre><code class="python">Python pre</code></pre>.') caption_html = self.test_message_v2.caption_html assert caption_html == test_html_string def test_caption_html_empty(self, message): message.text = "test" message.caption = None assert message.caption_html is None def test_caption_html_urled(self): test_html_string = ( '<u>Test</u> for <<b>bold</b>, <i>ita_lic</i>, ' r'<code>\`code</code>, ' r'<a href="http://github.com/abc\)def">links</a>, ' '<a href="tg://user?id=123456789">text-mention</a> and ' r'<pre>`\pre</pre>. <a href="http://google.com">http://google.com</a> ' 'and <i>bold <b>nested in <s>strk</s> nested in</b> italic</i>. ' '<pre><code class="python">Python pre</code></pre>.') caption_html = self.test_message_v2.caption_html_urled assert caption_html == test_html_string def test_caption_markdown_simple(self): test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' '[text-mention](tg://user?id=123456789) and ```python\npre```. ' r'http://google.com/ab\_') caption_markdown = self.test_message.caption_markdown assert caption_markdown == test_md_string def test_caption_markdown_v2_simple(self): test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' '[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. ' r'http://google\.com and _bold *nested in ~strk~ nested in* italic_\. ' '```python\nPython pre```\\.') caption_markdown = self.test_message_v2.caption_markdown_v2 assert caption_markdown == test_md_string def test_caption_markdown_empty(self, message): message.text = "test" message.caption = None assert message.caption_markdown is None assert message.caption_markdown_v2 is None def test_caption_markdown_urled(self): test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' '[text-mention](tg://user?id=123456789) and ```python\npre```. ' '[http://google.com/ab_](http://google.com/ab_)') caption_markdown = self.test_message.caption_markdown_urled assert caption_markdown == test_md_string def test_caption_markdown_v2_urled(self): test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' '[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. ' r'[http://google\.com](http://google.com) and _bold *nested in ~strk~ ' 'nested in* italic_\\. ```python\nPython pre```\\.') caption_markdown = self.test_message_v2.caption_markdown_v2_urled assert caption_markdown == test_md_string def test_caption_html_emoji(self): caption = b'\\U0001f469\\u200d\\U0001f469\\u200d ABC'.decode( 'unicode-escape') expected = b'\\U0001f469\\u200d\\U0001f469\\u200d <b>ABC</b>'.decode( 'unicode-escape') bold_entity = MessageEntity(type=MessageEntity.BOLD, offset=7, length=3) message = Message( 1, self.from_user, self.date, self.chat, caption=caption, caption_entities=[bold_entity], ) assert expected == message.caption_html def test_caption_markdown_emoji(self): caption = b'\\U0001f469\\u200d\\U0001f469\\u200d ABC'.decode( 'unicode-escape') expected = b'\\U0001f469\\u200d\\U0001f469\\u200d *ABC*'.decode( 'unicode-escape') bold_entity = MessageEntity(type=MessageEntity.BOLD, offset=7, length=3) message = Message( 1, self.from_user, self.date, self.chat, caption=caption, caption_entities=[bold_entity], ) assert expected == message.caption_markdown def test_parse_entities_url_emoji(self): url = b'http://github.com/?unicode=\\u2713\\U0001f469'.decode( 'unicode-escape') text = 'some url' link_entity = MessageEntity(type=MessageEntity.URL, offset=0, length=8, url=url) message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[link_entity]) assert message.parse_entities() == {link_entity: text} assert next(iter(message.parse_entities())).url == url def test_chat_id(self, message): assert message.chat_id == message.chat.id @pytest.mark.parametrize('type', argvalues=[Chat.SUPERGROUP, Chat.CHANNEL]) def test_link_with_username(self, message, type): message.chat.username = '******' message.chat.type = type assert message.link == f'https://t.me/{message.chat.username}/{message.message_id}' @pytest.mark.parametrize('type, id', argvalues=[(Chat.CHANNEL, -1003), (Chat.SUPERGROUP, -1003)]) def test_link_with_id(self, message, type, id): message.chat.username = None message.chat.id = id message.chat.type = type # The leading - for group ids/ -100 for supergroup ids isn't supposed to be in the link assert message.link == f'https://t.me/c/{3}/{message.message_id}' @pytest.mark.parametrize('id, username', argvalues=[(None, 'username'), (-3, None)]) def test_link_private_chats(self, message, id, username): message.chat.type = Chat.PRIVATE message.chat.id = id message.chat.username = username assert message.link is None message.chat.type = Chat.GROUP assert message.link is None def test_effective_attachment(self, message_params): for i in ( 'audio', 'game', 'document', 'animation', 'photo', 'sticker', 'video', 'voice', 'video_note', 'contact', 'location', 'venue', 'invoice', 'invoice', 'successful_payment', ): item = getattr(message_params, i, None) if item: break else: item = None assert message_params.effective_attachment == item def test_reply_text(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id text = args[1] == 'test' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and text and reply monkeypatch.setattr(message.bot, 'send_message', test) assert message.reply_text('test') assert message.reply_text('test', quote=True) assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True) def test_reply_markdown(self, monkeypatch, message): test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' '[text-mention](tg://user?id=123456789) and ```python\npre```. ' r'http://google.com/ab\_') def test(*args, **kwargs): cid = args[0] == message.chat_id markdown_text = args[1] == test_md_string markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return all([cid, markdown_text, reply, markdown_enabled]) text_markdown = self.test_message.text_markdown assert text_markdown == test_md_string monkeypatch.setattr(message.bot, 'send_message', test) assert message.reply_markdown(self.test_message.text_markdown) assert message.reply_markdown(self.test_message.text_markdown, quote=True) assert message.reply_markdown(self.test_message.text_markdown, reply_to_message_id=message.message_id, quote=True) def test_reply_markdown_v2(self, monkeypatch, message): test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' '[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. ' r'http://google\.com and _bold *nested in ~strk~ nested in* italic_\. ' '```python\nPython pre```\\.') def test(*args, **kwargs): cid = args[0] == message.chat_id markdown_text = args[1] == test_md_string markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN_V2 if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return all([cid, markdown_text, reply, markdown_enabled]) text_markdown = self.test_message_v2.text_markdown_v2 assert text_markdown == test_md_string monkeypatch.setattr(message.bot, 'send_message', test) assert message.reply_markdown_v2(self.test_message_v2.text_markdown_v2) assert message.reply_markdown_v2(self.test_message_v2.text_markdown_v2, quote=True) assert message.reply_markdown_v2( self.test_message_v2.text_markdown_v2, reply_to_message_id=message.message_id, quote=True, ) def test_reply_html(self, monkeypatch, message): test_html_string = ( '<u>Test</u> for <<b>bold</b>, <i>ita_lic</i>, ' r'<code>\`code</code>, ' r'<a href="http://github.com/abc\)def">links</a>, ' '<a href="tg://user?id=123456789">text-mention</a> and ' r'<pre>`\pre</pre>. http://google.com ' 'and <i>bold <b>nested in <s>strk</s> nested in</b> italic</i>. ' '<pre><code class="python">Python pre</code></pre>.') def test(*args, **kwargs): cid = args[0] == message.chat_id html_text = args[1] == test_html_string html_enabled = kwargs['parse_mode'] == ParseMode.HTML if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return all([cid, html_text, reply, html_enabled]) text_html = self.test_message_v2.text_html assert text_html == test_html_string monkeypatch.setattr(message.bot, 'send_message', test) assert message.reply_html(self.test_message_v2.text_html) assert message.reply_html(self.test_message_v2.text_html, quote=True) assert message.reply_html(self.test_message_v2.text_html, reply_to_message_id=message.message_id, quote=True) def test_reply_media_group(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id media = kwargs['media'] == 'reply_media_group' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and media and reply monkeypatch.setattr(message.bot, 'send_media_group', test) assert message.reply_media_group(media='reply_media_group') assert message.reply_media_group(media='reply_media_group', quote=True) def test_reply_photo(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id photo = kwargs['photo'] == 'test_photo' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and photo and reply monkeypatch.setattr(message.bot, 'send_photo', test) assert message.reply_photo(photo='test_photo') assert message.reply_photo(photo='test_photo', quote=True) def test_reply_audio(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id audio = kwargs['audio'] == 'test_audio' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and audio and reply monkeypatch.setattr(message.bot, 'send_audio', test) assert message.reply_audio(audio='test_audio') assert message.reply_audio(audio='test_audio', quote=True) def test_reply_document(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id document = kwargs['document'] == 'test_document' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and document and reply monkeypatch.setattr(message.bot, 'send_document', test) assert message.reply_document(document='test_document') assert message.reply_document(document='test_document', quote=True) def test_reply_animation(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id animation = kwargs['animation'] == 'test_animation' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and animation and reply monkeypatch.setattr(message.bot, 'send_animation', test) assert message.reply_animation(animation='test_animation') assert message.reply_animation(animation='test_animation', quote=True) def test_reply_sticker(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id sticker = kwargs['sticker'] == 'test_sticker' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and sticker and reply monkeypatch.setattr(message.bot, 'send_sticker', test) assert message.reply_sticker(sticker='test_sticker') assert message.reply_sticker(sticker='test_sticker', quote=True) def test_reply_video(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id video = kwargs['video'] == 'test_video' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and video and reply monkeypatch.setattr(message.bot, 'send_video', test) assert message.reply_video(video='test_video') assert message.reply_video(video='test_video', quote=True) def test_reply_video_note(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id video_note = kwargs['video_note'] == 'test_video_note' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and video_note and reply monkeypatch.setattr(message.bot, 'send_video_note', test) assert message.reply_video_note(video_note='test_video_note') assert message.reply_video_note(video_note='test_video_note', quote=True) def test_reply_voice(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id voice = kwargs['voice'] == 'test_voice' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and voice and reply monkeypatch.setattr(message.bot, 'send_voice', test) assert message.reply_voice(voice='test_voice') assert message.reply_voice(voice='test_voice', quote=True) def test_reply_location(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id location = kwargs['location'] == 'test_location' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and location and reply monkeypatch.setattr(message.bot, 'send_location', test) assert message.reply_location(location='test_location') assert message.reply_location(location='test_location', quote=True) def test_reply_venue(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id venue = kwargs['venue'] == 'test_venue' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and venue and reply monkeypatch.setattr(message.bot, 'send_venue', test) assert message.reply_venue(venue='test_venue') assert message.reply_venue(venue='test_venue', quote=True) def test_reply_contact(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id contact = kwargs['contact'] == 'test_contact' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and contact and reply monkeypatch.setattr(message.bot, 'send_contact', test) assert message.reply_contact(contact='test_contact') assert message.reply_contact(contact='test_contact', quote=True) def test_reply_poll(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id contact = kwargs['question'] == 'test_poll' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and contact and reply monkeypatch.setattr(message.bot, 'send_poll', test) assert message.reply_poll(question='test_poll') assert message.reply_poll(question='test_poll', quote=True) def test_reply_dice(self, monkeypatch, message): def test(*args, **kwargs): id_ = args[0] == message.chat_id contact = kwargs['disable_notification'] is True if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True return id_ and contact and reply monkeypatch.setattr(message.bot, 'send_dice', test) assert message.reply_dice(disable_notification=True) assert message.reply_dice(disable_notification=True, quote=True) def test_forward(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == 123456 from_chat = kwargs['from_chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id if kwargs.get('disable_notification'): notification = kwargs['disable_notification'] is True else: notification = True return chat_id and from_chat and message_id and notification monkeypatch.setattr(message.bot, 'forward_message', test) assert message.forward(123456) assert message.forward(123456, disable_notification=True) assert not message.forward(635241) def test_copy(self, monkeypatch, message): keyboard = [[1, 2]] def test(*args, **kwargs): chat_id = kwargs['chat_id'] == 123456 from_chat = kwargs['from_chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id if kwargs.get('disable_notification'): notification = kwargs['disable_notification'] is True else: notification = True if kwargs.get('reply_markup'): reply_markup = kwargs['reply_markup'] is keyboard else: reply_markup = True return chat_id and from_chat and message_id and notification and reply_markup monkeypatch.setattr(message.bot, 'copy_message', test) assert message.copy(123456) assert message.copy(123456, disable_notification=True) assert message.copy(123456, reply_markup=keyboard) assert not message.copy(635241) @pytest.mark.pfff def test_reply_copy(self, monkeypatch, message): keyboard = [[1, 2]] def test(*args, **kwargs): chat_id = kwargs['from_chat_id'] == 123456 from_chat = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == 456789 if kwargs.get('disable_notification'): notification = kwargs['disable_notification'] is True else: notification = True if kwargs.get('reply_markup'): reply_markup = kwargs['reply_markup'] is keyboard else: reply_markup = True return chat_id and from_chat and message_id and notification and reply_markup monkeypatch.setattr(message.bot, 'copy_message', test) assert message.reply_copy(123456, 456789) assert message.reply_copy(123456, 456789, disable_notification=True) assert message.reply_copy(123456, 456789, reply_markup=keyboard) def test_edit_text(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id text = kwargs['text'] == 'test' return chat_id and message_id and text monkeypatch.setattr(message.bot, 'edit_message_text', test) assert message.edit_text(text='test') def test_edit_caption(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id caption = kwargs['caption'] == 'new caption' return chat_id and message_id and caption monkeypatch.setattr(message.bot, 'edit_message_caption', test) assert message.edit_caption(caption='new caption') def test_edit_media(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id media = kwargs['media'] == 'my_media' return chat_id and message_id and media monkeypatch.setattr(message.bot, 'edit_message_media', test) assert message.edit_media('my_media') def test_edit_reply_markup(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id reply_markup = kwargs['reply_markup'] == [['1', '2']] return chat_id and message_id and reply_markup monkeypatch.setattr(message.bot, 'edit_message_reply_markup', test) assert message.edit_reply_markup(reply_markup=[['1', '2']]) def test_edit_live_location(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id latitude = kwargs['latitude'] == 1 longitude = kwargs['longitude'] == 2 return chat_id and message_id and longitude and latitude monkeypatch.setattr(message.bot, 'edit_message_live_location', test) assert message.edit_live_location(latitude=1, longitude=2) def test_stop_live_location(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id return chat_id and message_id monkeypatch.setattr(message.bot, 'stop_message_live_location', test) assert message.stop_live_location() def test_set_game_score(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 score = kwargs['score'] == 2 return chat_id and message_id and user_id and score monkeypatch.setattr(message.bot, 'set_game_score', test) assert message.set_game_score(user_id=1, score=2) def test_get_game_high_scores(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 return chat_id and message_id and user_id monkeypatch.setattr(message.bot, 'get_game_high_scores', test) assert message.get_game_high_scores(user_id=1, score=2) def test_delete(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id return chat_id and message_id monkeypatch.setattr(message.bot, 'delete_message', test) assert message.delete() def test_stop_poll(self, monkeypatch, message): def test(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id return chat_id and message_id monkeypatch.setattr(message.bot, 'stop_poll', test) assert message.stop_poll() def test_pin(self, monkeypatch, message): def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id return chat_id and message_id monkeypatch.setattr(message.bot, 'pin_chat_message', make_assertion) assert message.pin() def test_unpin(self, monkeypatch, message): def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id return chat_id and message_id monkeypatch.setattr(message.bot, 'unpin_chat_message', make_assertion) assert message.unpin() def test_default_quote(self, message): message.bot.defaults = Defaults() kwargs = {} message.bot.defaults._quote = False message._quote(kwargs) assert 'reply_to_message_id' not in kwargs message.bot.defaults._quote = True message._quote(kwargs) assert 'reply_to_message_id' in kwargs kwargs = {} message.bot.defaults._quote = None message.chat.type = Chat.PRIVATE message._quote(kwargs) assert 'reply_to_message_id' not in kwargs message.chat.type = Chat.GROUP message._quote(kwargs) assert 'reply_to_message_id' in kwargs def test_equality(self): id_ = 1 a = Message( id_, self.date, self.chat, from_user=self.from_user, ) b = Message( id_, self.date, self.chat, from_user=self.from_user, ) c = Message(id_, self.date, Chat(123, Chat.GROUP), from_user=User(0, '', False)) d = Message(0, self.date, self.chat, from_user=self.from_user) e = Update(id_) assert a == b assert hash(a) == hash(b) assert a is not 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)
@pytest.fixture(scope='class') def message(bot): return Message( TestMessage.id_, TestMessage.date, TestMessage.chat, from_user=TestMessage.from_user, bot=bot, ) @pytest.fixture( scope='function', params=[ { 'forward_from': User(99, 'forward_user', False), 'forward_date': datetime.utcnow() }, { 'forward_from_chat': Chat(-23, 'channel'), 'forward_from_message_id': 101, 'forward_date': datetime.utcnow(), }, { 'reply_to_message': Message(50, None, None, None) }, { 'edit_date': datetime.utcnow() }, { 'text':
def inline_query(bot): return Update(0, inline_query=InlineQuery('id', User(2, 'test user', False), 'test query', offset='22', location=Location(latitude=-23.691288, longitude=-46.788279)))