Exemple #1
0
 def setUp(self):
     # For use within the tests we nee some stuff. Starting with a Mockbot
     self.bot = Mockbot()
     # Some generators for users and chats
     self.cg = ChatGenerator()
     # And a Messagegenerator and updater (for use with the bot.)
     self.mg = MessageGenerator(self.bot)
     self.updater = Updater(bot=self.bot)  # type: ignore
Exemple #2
0
class TestMessageGeneratorForwards(unittest.TestCase):
    def setUp(self):
        self.mg = MessageGenerator()
        self.ug = UserGenerator()
        self.cg = ChatGenerator()

    def test_forwarded_message(self):
        u1 = self.ug.get_user()
        u2 = self.ug.get_user()
        c = self.cg.get_chat(type="group")
        u = self.mg.get_message(user=u1,
                                chat=c,
                                forward_from=u2,
                                text="This is a test")
        self.assertEqual(u.message.from_user.id, u1.id)
        self.assertEqual(u.message.forward_from.id, u2.id)
        self.assertNotEqual(u.message.from_user.id, u.message.forward_from.id)
        self.assertEqual(u.message.text, "This is a test")
        self.assertIsInstance(u.message.forward_date, int)
        import datetime
        self.mg.get_message(forward_from=u2,
                            forward_date=datetime.datetime.now())

        with self.assertRaises(BadUserException):
            u3 = "This is not a User"
            u = self.mg.get_message(user=u1,
                                    chat=c,
                                    forward_from=u3,
                                    text="This is a test")

    def test_forwarded_channel_message(self):
        c = self.cg.get_chat(type="channel")
        us = self.ug.get_user()
        u = self.mg.get_message(text="This is a test",
                                forward_from=us,
                                forward_from_chat=c)
        self.assertNotEqual(u.message.chat.id, c.id)
        self.assertNotEqual(u.message.from_user.id, us.id)
        self.assertEqual(u.message.forward_from.id, us.id)
        self.assertEqual(u.message.text, "This is a test")
        self.assertIsInstance(u.message.forward_from_message_id, int)
        self.assertIsInstance(u.message.forward_date, int)

        u = self.mg.get_message(text="This is a test", forward_from_chat=c)
        self.assertNotEqual(u.message.from_user.id, u.message.forward_from.id)
        self.assertIsInstance(u.message.forward_from, User)
        self.assertIsInstance(u.message.forward_from_message_id, int)
        self.assertIsInstance(u.message.forward_date, int)

        with self.assertRaises(BadChatException):
            c = "Not a Chat"
            u = self.mg.get_message(text="This is a test", forward_from_chat=c)

        with self.assertRaises(BadChatException):
            c = self.cg.get_chat(type="group")
            u = self.mg.get_message(text="This is a test", forward_from_chat=c)
 def setUp(self):
     # For use within the tests we need some stuff. Starting with a Mockbot
     self.bot = Mockbot()
     # Some generators for users and chats
     self.ug = UserGenerator()
     self.cg = ChatGenerator()
     # And a Messagegenerator and updater (for use with the bot.)
     self.mg = MessageGenerator(self.bot)
     self.updater = Updater(bot=self.bot)
     GamesController.init()
 def __init__(self, bot=None):
     PtbGenerator.__init__(self)
     self.idgen = self._gen_id()
     self.ug = UserGenerator()
     self.cg = ChatGenerator()
     if not bot:
         self.bot = Mockbot()
     elif isinstance(bot, Mockbot):
         self.bot = bot
     else:
         raise BadBotException
Exemple #5
0
    def test_with_chat(self):
        cg = ChatGenerator()
        group = cg.get_chat(type="group")
        channel = cg.get_chat(type="channel")
        u = self.mg.get_channel_post(chat=channel)
        self.assertEqual(channel.title, u.channel_post.chat.title)

        with self.assertRaisesRegexp(BadChatException, "telegram\.Chat"):
            self.mg.get_channel_post(chat="chat")
        with self.assertRaisesRegexp(BadChatException, "chat\.type"):
            self.mg.get_channel_post(chat=group)
Exemple #6
0
class TestClass:
    bot = Mockbot()
    ug = UserGenerator()
    cg = ChatGenerator()
    mg = MessageGenerator(bot)
    pp = PicklePersistence(filename='bbqreserve_test')
    updater = Updater(bot=bot, persistence=pp, use_context=True)

    @pytest.mark.parametrize("test_input, expected, userdata, delme",
                             create_reserve_parameters)
    def test_create_reservation(self, test_input, expected, userdata, delme):
        user = self.ug.get_user(id=userdata['id'],
                                first_name=userdata['first_name'],
                                last_name=userdata['last_name'])
        chat = self.cg.get_chat(user=user)
        self.updater.dispatcher.add_handler(reserve.reserve_conv_handler)
        self.updater.start_polling()
        update = self.mg.get_message(user=user, chat=chat, text=test_input)
        self.bot.insertUpdate(update)
        sent = self.bot.sent_messages
        self.updater.stop()
        if delme:
            import os
            os.remove("bbqreserve_test")
        # check expected result with actual result
        assert sent[-1]['text'] == expected
Exemple #7
0
    def test_with_chat(self):
        cg = ChatGenerator()
        c = cg.get_chat()
        u = self.mg.get_message(chat=c)
        self.assertEqual(u.message.chat.id, u.message.from_user.id)
        self.assertEqual(u.message.chat.id, c.id)

        c = cg.get_chat(type="group")
        u = self.mg.get_message(chat=c)
        self.assertNotEqual(u.message.from_user.id, u.message.chat.id)
        self.assertEqual(u.message.chat.id, c.id)

        with self.assertRaisesRegexp(BadChatException, "get_channel_post"):
            c = cg.get_chat(type="channel")
            self.mg.get_message(chat=c)

        with self.assertRaises(BadChatException):
            c = "Not a telegram.Chat"
            self.mg.get_message(chat=c)
Exemple #8
0
    def test_with_chat_and_user(self):
        cg = ChatGenerator()
        ug = UserGenerator()
        us = ug.get_user()
        c = cg.get_chat()
        u = self.mg.get_message(user=us, chat=c)
        self.assertNotEqual(u.message.from_user.id, u.message.chat.id)
        self.assertEqual(u.message.from_user.id, us.id)
        self.assertEqual(u.message.chat.id, c.id)

        us = "not a telegram.User"
        with self.assertRaises(BadUserException):
            u = self.mg.get_message(user=us)
        with self.assertRaises(BadUserException):
            u = self.mg.get_message(chat=c, user="******")

        c = "Not a telegram.Chat"
        with self.assertRaises(BadChatException):
            self.mg.get_message(chat=c)
        with self.assertRaises(BadChatException):
            self.mg.get_message(user=u, chat="chat")
Exemple #9
0
 def setUpClass(self):
     # For use within the tests we nee some stuff. Starting with a Mockbot
     self.bot = Mockbot()
     self.bot.request = telegram.utils.request.Request()
     # Some generators for users and chats
     self.ug = UserGenerator()
     self.cg = ChatGenerator()
     # And a Messagegenerator,CallbackQueryGenerator and updater (for use with the bot.)
     self.mg = MessageGenerator(self.bot)
     self.cqg = CallbackQueryGenerator(self.bot)
     self.updater = Updater(bot=self.bot)
     init_db("test.sqlite3")
     install_commands()
     add_all_handlers(self.updater.dispatcher)
     with db_session:
         for listable_type in Listable.__subclasses__():
             for i in range(6):
                 listable_type(name=listable_type._discriminator_ + " " +
                               str(i),
                               url="https://url" + str(i) + ".com",
                               validated=True)
     self.updater.start_polling()
class TestClass:
    bot = Mockbot()
    ug = UserGenerator()
    cg = ChatGenerator()
    mg = MessageGenerator(bot)
    pp = PicklePersistence(filename='bbqreserve_test')
    updater = Updater(bot=bot, persistence=pp, use_context=True)

    @pytest.mark.parametrize("test_input, expected, userdata", cancel_reserve_parameters)
    def test_cancel_reservation(self, test_input, expected, userdata):
        user = self.ug.get_user(id=userdata['id'], first_name=userdata['first_name'], last_name=userdata['last_name'])
        chat = self.cg.get_chat(user=user)
        self.updater.dispatcher.add_handler(cancel.cancel_reserve_conv_handler)
        self.updater.start_polling()
        update = self.mg.get_message(user=user, chat=chat, text=test_input)
        self.bot.insertUpdate(update)
        sent = self.bot.sent_messages
        self.updater.stop()
        print(sent)
    def get_channel_post(self, chat=None, user=None, **kwargs):
        """
        Parameters:
            chat (Optional[telegram.Chat]): Chat with type='channel' to use with this update
            user (Optional[telegram.User]): User for the update. None if omitted
            **kwargs: See get_message

        Returns:
            telegram.Update: A telegram update object containing a :py:class:`telegram.Message.
        """
        if chat:
            if not isinstance(chat, Chat):
                raise BadChatException
            if not chat.type == "channel":
                raise BadChatException(
                    "Can only use chat.type='channel' for get_channel_post"
                )
        else:
            chat = ChatGenerator().get_chat(type="channel")

        return self.get_message(chat=chat, user=user, channel=True, **kwargs).message
Exemple #12
0
class TestExplore(unittest.TestCase):
    def setUp(self):
        # For use within the tests we nee some stuff. Starting with a Mockbot
        self.bot = Mockbot()
        # Some generators for users and chats
        self.ug = UserGenerator()
        self.cg = ChatGenerator()
        # And a Messagegenerator and updater (for use with the bot.)
        self.mg = MessageGenerator(self.bot)
        self.updater = Updater(bot=self.bot)

    def test_help(self):
        # Then register the handler with he updater's dispatcher and start polling
        self.updater.dispatcher.add_handler(
            CommandHandler("explore", explore.explore, pass_chat_data=True))
        self.updater.start_polling()
        # We want to simulate a message. Since we don't care wich user sends it we let the MessageGenerator
        # create random ones
        update = self.mg.get_message(text="/explore")
        # We insert the update with the bot so the updater can retrieve it.
        self.bot.insertUpdate(update)
        # sent_messages is the list with calls to the bot's outbound actions. Since we hope the message we inserted
        # only triggered one sendMessage action it's length should be 1.
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.updater.stop()

    def test_start(self):
        def start(bot, update):
            update.message.reply_text('Hi!')

        self.updater.dispatcher.add_handler(CommandHandler("start", start))
        self.updater.start_polling()
        # Here you can see how we would handle having our own user and chat
        user = self.ug.get_user(first_name="Test", last_name="The Bot")
        chat = self.cg.get_chat(user=user)
        update = self.mg.get_message(user=user, chat=chat, text="/start")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertEqual(sent['text'], "Hi!")
        self.updater.stop()

    def test_echo(self):
        def echo(bot, update):
            update.message.reply_text(update.message.text)

        self.updater.dispatcher.add_handler(MessageHandler(Filters.text, echo))
        self.updater.start_polling()
        update = self.mg.get_message(text="first message")
        update2 = self.mg.get_message(text="second message")
        self.bot.insertUpdate(update)
        self.bot.insertUpdate(update2)
        self.assertEqual(len(self.bot.sent_messages), 2)
        sent = self.bot.sent_messages
        self.assertEqual(sent[0]['method'], "sendMessage")
        self.assertEqual(sent[0]['text'], "first message")
        self.assertEqual(sent[1]['text'], "second message")
        self.updater.stop()
Exemple #13
0
 def setUp(self):
     self.mg = MessageGenerator()
     self.ug = UserGenerator()
     self.cg = ChatGenerator()
Exemple #14
0
class Testtimerbot(unittest.TestCase):
    def setUp(self):
        # For use within the tests we nee some stuff. Starting with a Mockbot
        self.bot = Mockbot()
        # Some generators for users and chats
        self.cg = ChatGenerator()
        # And a Messagegenerator and updater (for use with the bot.)
        self.mg = MessageGenerator(self.bot)
        self.updater = Updater(bot=self.bot)  # type: ignore

    def test_timer(self):
        # first declare the callback methods
        def alarm(context):
            """Function to send the alarm message"""
            context.bot.sendMessage(context.job.context["chat_id"],
                                    text='Beep!')

        def set(update, context):
            """Adds a job to the queue"""
            chat_id = update.message.chat_id
            try:
                args = context.args
                # args[0] should contain the time for the timer in seconds
                due = int(args[0])
                if due < 0:
                    update.message.reply_text(
                        'Sorry we can not go back to the past!')
                    return

                # Add job to queue
                context.user_data["job"] = context.job_queue.run_once(
                    callback=alarm, when=due, context={"chat_id": chat_id})
                update.message.reply_text('Timer successfully set!')

            except (IndexError, ValueError):
                update.message.reply_text('Usage: /set <seconds>')

        def unset(update, context):
            """Removes the job if the user changed their mind"""

            if 'job' not in context.user_data:
                update.message.reply_text('You have no active timer')
                return

            job = context.user_data['job']
            job.schedule_removal()
            del context.user_data['job']

            update.message.reply_text('Timer successfully unset!')

        # Now add those handlers to the updater and start polling
        dp = self.updater.dispatcher
        dp.add_handler(CommandHandler("set", set))
        dp.add_handler(CommandHandler("unset", unset))
        self.updater.start_polling()

        #  we want to check if the bot returns a message to the same chat after a period of time
        # so let's create a chat to use
        chat = self.cg.get_chat()

        # let's generate some updates we can use
        u1 = self.mg.get_message(chat=chat, text="/set", parse_mode="HTML")
        u2 = self.mg.get_message(chat=chat, text="/set -20", parse_mode="HTML")
        u3 = self.mg.get_message(chat=chat, text="/set 6", parse_mode="HTML")
        u4 = self.mg.get_message(chat=chat, text="/unset", parse_mode="HTML")

        # first check some errors
        self.bot.insertUpdate(u1)
        self.bot.insertUpdate(u2)
        self.bot.insertUpdate(u4)
        data = self.bot.sent_messages
        self.assertEqual(len(data), 3)
        self.assertEqual(data[0]['text'], "Usage: /set <seconds>")
        self.assertEqual(data[1]['text'],
                         'Sorry we can not go back to the past!')
        self.assertEqual(data[2]['text'], 'You have no active timer')

        # now check if setting and unsetting works (within timer limit)
        self.bot.insertUpdate(u3)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], 'Timer successfully set!')
        time.sleep(2)
        self.bot.insertUpdate(u4)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], 'Timer successfully unset!')
        # and to be certain we have to wait some more to see if it stops sending the message
        # we reset the bot so we can be sure nothing more has been sent
        self.bot.reset()
        time.sleep(5)
        data = self.bot.sent_messages
        self.assertEqual(len(data), 0)

        # lastly we will make sure an alarm message is sent after the timelimit has passed
        self.bot.insertUpdate(u3)
        time.sleep(6)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], 'Beep!')
        self.assertEqual(data['chat_id'], chat.id)

        # and stop the updater.
        self.updater.stop()
 def setUp(self):
     self.cg = ChatGenerator()
class TestChatGenerator(unittest.TestCase):
    def setUp(self):
        self.cg = ChatGenerator()

    def test_without_parameter(self):
        c = self.cg.get_chat()

        self.assertIsInstance(c.id, int)
        self.assertTrue(c.id > 0)
        self.assertEqual(c.username, c.first_name + c.last_name)
        self.assertEqual(c.type, "private")

    def test_group_chat(self):
        c = self.cg.get_chat(type="group")

        self.assertTrue(c.id < 0)
        self.assertEqual(c.type, "group")
        self.assertFalse(c.all_members_are_administrators)
        self.assertIsInstance(c.title, str)

    def test_group_all_members_are_administrators(self):
        c = self.cg.get_chat(type="group", all_members_are_administrators=True)
        self.assertEqual(c.type, "group")
        self.assertTrue(c.all_members_are_administrators)

    def test_group_chat_with_group_name(self):
        c = self.cg.get_chat(type="group", title="My Group")

        self.assertEqual(c.title, "My Group")

    def test_private_from_user(self):
        u = UserGenerator().get_user()
        c = self.cg.get_chat(user=u)

        self.assertEqual(u.id, c.id)
        self.assertEqual(c.username, c.first_name + c.last_name)
        self.assertEqual(u.username, c.username)
        self.assertEqual(c.type, "private")

    def test_supergroup(self):
        c = self.cg.get_chat(type="supergroup")

        self.assertTrue(c.id < 0)
        self.assertEqual(c.type, "supergroup")
        self.assertIsInstance(c.title, str)
        self.assertTrue(c.username, "".join(c.title.split()))

    def test_supergroup_with_title(self):
        c = self.cg.get_chat(type="supergroup", title="Awesome Group")

        self.assertEqual(c.title, "Awesome Group")
        self.assertEqual(c.username, "AwesomeGroup")

    def test_supergroup_with_username(self):
        c = self.cg.get_chat(type="supergroup", username="******")

        self.assertEqual(c.username, "mygroup")

    def test_supergroup_with_username_title(self):
        c = self.cg.get_chat(type="supergroup",
                             username="******",
                             title="Awesome Group")

        self.assertEqual(c.title, "Awesome Group")
        self.assertEqual(c.username, "mygroup")

    def test_channel(self):
        c = self.cg.get_chat(type="channel")

        self.assertIsInstance(c.title, str)
        self.assertEqual(c.type, "channel")
        self.assertTrue(c.username, "".join(c.title.split()))

    def test_channel_with_title(self):
        c = self.cg.get_chat(type="channel", title="Awesome Group")
        self.assertEqual(c.title, "Awesome Group")
        self.assertEqual(c.username, "AwesomeGroup")

    def test_supergroup_with_username(self):
        c = self.cg.get_chat(type="channel", username="******")

        self.assertEqual(c.username, "mygroup")

    def test_supergroup_with_username_title(self):
        c = self.cg.get_chat(type="channel",
                             username="******",
                             title="Awesome Group")

        self.assertEqual(c.title, "Awesome Group")
        self.assertEqual(c.username, "mygroup")
Exemple #17
0
class TestCommands(unittest.TestCase):
    def setUp(self):
        # For use within the tests we nee some stuff. Starting with a Mockbot
        self.bot = Mockbot()
        # Some generators for users and chats
        self.ug = UserGenerator()
        self.cg = ChatGenerator()
        # And a Messagegenerator and updater (for use with the bot.)
        self.mg = MessageGenerator(self.bot)
        self.updater = Updater(bot=self.bot)
        GamesController.init()

    def test_ping(self):
        # Then register the handler with he updater's dispatcher and start polling
        self.updater.dispatcher.add_handler(
            CommandHandler("ping", command_ping))
        self.updater.start_polling()
        # create with random user
        update = self.mg.get_message(text="/ping")
        # We insert the update with the bot so the updater can retrieve it.
        self.bot.insertUpdate(update)
        # sent_messages is the list with calls to the bot's outbound actions. Since we hope the message we inserted
        # only triggered one sendMessage action it's length should be 1.
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertEqual(sent['text'], "pong - v0.4")
        # Always stop the updater at the end of a testcase so it won't hang.
        self.updater.stop()

    def test_start(self):
        self.updater.dispatcher.add_handler(
            CommandHandler("start", command_start))
        self.updater.start_polling()
        update = self.mg.get_message(text="/start")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 2)
        start = self.bot.sent_messages[0]
        self.assertEqual(start['method'], "sendMessage")
        self.assertIn("Secret Blue is a social deduction game", start['text'])
        help = self.bot.sent_messages[1]
        self.assertEqual(help['method'], "sendMessage")
        self.assertIn("The following commands are available", help['text'])
        self.updater.stop()

    def test_symbols(self):
        self.updater.dispatcher.add_handler(
            CommandHandler("symbols", command_symbols))
        self.updater.start_polling()
        update = self.mg.get_message(text="/symbols")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertIn("The following symbols can appear on the board:",
                      sent['text'])
        self.updater.stop()

    def test_board_when_there_is_no_game(self):
        self.updater.dispatcher.add_handler(
            CommandHandler("board", command_board))
        self.updater.start_polling()
        update = self.mg.get_message(text="/board")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertIn(
            "There is no game in this chat. Create a new game with /newgame",
            sent['text'])
        self.updater.stop()

    def test_board_when_game_is_not_running(self):
        game = Game(-999, 12345)
        GamesController.games[-999] = game
        self.updater.dispatcher.add_handler(
            CommandHandler("board", command_board))
        self.updater.start_polling()
        chat = self.cg.get_chat(cid=-999)
        update = self.mg.get_message(chat=chat, text="/board")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertIn(
            "There is no running game in this chat. Please start the game with /startgame",
            sent['text'])
        self.updater.stop()

    def test_board_when_game_is_running(self):
        game = Game(-999, 12345)
        game.board = Board(5, game)
        GamesController.games[-999] = game
        self.updater.dispatcher.add_handler(
            CommandHandler("board", command_board))
        self.updater.start_polling()
        chat = self.cg.get_chat(cid=-999)
        update = self.mg.get_message(chat=chat, text="/board")
        self.bot.insertUpdate(update)
        self.assertEqual(len(self.bot.sent_messages), 1)
        sent = self.bot.sent_messages[0]
        self.assertEqual(sent['method'], "sendMessage")
        self.assertIn("--- Liberal acts ---", sent['text'])
        self.updater.stop()
Exemple #18
0
 def setUp(self):
     self.bot = Mockbot()
     self.ug = UserGenerator()
     self.cg = ChatGenerator()
     self.mg = MessageGenerator(self.bot)
     self.updater = Updater(bot=self.bot)
Exemple #19
0
class TestMessageGeneratorStatusMessages(unittest.TestCase):
    def setUp(self):
        self.mg = MessageGenerator()
        self.ug = UserGenerator()
        self.cg = ChatGenerator()

    def test_new_chat_member(self):
        user = self.ug.get_user()
        chat = self.cg.get_chat(type="group")
        u = self.mg.get_message(chat=chat, new_chat_member=user)
        self.assertEqual(u.message.new_chat_member.id, user.id)

        with self.assertRaises(BadChatException):
            self.mg.get_message(new_chat_member=user)
        with self.assertRaises(BadUserException):
            self.mg.get_message(chat=chat, new_chat_member="user")

    def test_left_chat_member(self):
        user = self.ug.get_user()
        chat = self.cg.get_chat(type='group')
        u = self.mg.get_message(chat=chat, left_chat_member=user)
        self.assertEqual(u.message.left_chat_member.id, user.id)

        with self.assertRaises(BadChatException):
            self.mg.get_message(left_chat_member=user)
        with self.assertRaises(BadUserException):
            self.mg.get_message(chat=chat, left_chat_member="user")

    def test_new_chat_title(self):
        chat = self.cg.get_chat(type="group")
        u = self.mg.get_message(chat=chat, new_chat_title="New title")
        self.assertEqual(u.message.chat.title, "New title")
        self.assertEqual(u.message.chat.title, chat.title)

        with self.assertRaises(BadChatException):
            self.mg.get_message(new_chat_title="New title")

    def test_new_chat_photo(self):
        chat = self.cg.get_chat(type="group")
        u = self.mg.get_message(chat=chat, new_chat_photo=True)
        self.assertIsInstance(u.message.new_chat_photo, list)
        self.assertIsInstance(u.message.new_chat_photo[0], PhotoSize)
        photo = [PhotoSize("2", 1, 1, file_size=3)]
        u = self.mg.get_message(chat=chat, new_chat_photo=photo)
        self.assertEqual(len(u.message.new_chat_photo), 1)

        with self.assertRaises(BadChatException):
            self.mg.get_message(new_chat_photo=True)

        photo = "foto's!"
        with self.assertRaises(BadMessageException):
            self.mg.get_message(chat=chat, new_chat_photo=photo)
        with self.assertRaises(BadMessageException):
            self.mg.get_message(chat=chat, new_chat_photo=[1, 2, 3])

    def test_pinned_message(self):
        chat = self.cg.get_chat(type="supergroup")
        message = self.mg.get_message(
            chat=chat, text="this will be pinned").message
        u = self.mg.get_message(chat=chat, pinned_message=message)
        self.assertEqual(u.message.pinned_message.text, "this will be pinned")

        with self.assertRaises(BadChatException):
            self.mg.get_message(pinned_message=message)
        with self.assertRaises(BadMessageException):
            self.mg.get_message(chat=chat, pinned_message="message")

    def test_multiple_statusmessages(self):
        with self.assertRaises(BadMessageException):
            self.mg.get_message(
                private=False,
                new_chat_member=self.ug.get_user(),
                new_chat_title="New title")
Exemple #20
0
class TestDCUBABot(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        # For use within the tests we nee some stuff. Starting with a Mockbot
        self.bot = Mockbot()
        self.bot.request = telegram.utils.request.Request()
        # Some generators for users and chats
        self.ug = UserGenerator()
        self.cg = ChatGenerator()
        # And a Messagegenerator,CallbackQueryGenerator and updater (for use with the bot.)
        self.mg = MessageGenerator(self.bot)
        self.cqg = CallbackQueryGenerator(self.bot)
        self.updater = Updater(bot=self.bot)
        init_db("test.sqlite3")
        install_commands()
        add_all_handlers(self.updater.dispatcher)
        with db_session:
            for listable_type in Listable.__subclasses__():
                for i in range(6):
                    listable_type(name=listable_type._discriminator_ + " " +
                                  str(i),
                                  url="https://url" + str(i) + ".com",
                                  validated=True)
        self.updater.start_polling()

    @classmethod
    def tearDownClass(self):
        self.updater.stop()
        os.remove("test.sqlite3")

    @classmethod
    def sendCommand(self, command, chat_id=None):
        user = self.ug.get_user(first_name="Test", last_name="The Bot")
        if chat_id:
            chat = self.cg.get_chat(chat_id)
        else:
            chat = self.cg.get_chat(user=user)
        update = self.mg.get_message(user=user, chat=chat, text=command)
        self.bot.insertUpdate(update)
        return user, chat

    # TODO: Cleanup this
    def assert_bot_response(self,
                            message_text,
                            response_text,
                            chat_id=None,
                            random=False):
        if isinstance(response_text, str):
            response_text = [response_text]

        sent_messages = self.bot.sent_messages
        sent_messages_before = len(sent_messages)
        self.sendCommand(message_text, chat_id=chat_id)
        response_sent_messages = len(sent_messages) - sent_messages_before
        expected_sent_messages = 0 if not response_text else\
            (1 if random else len(response_text))
        self.assertEqual(response_sent_messages, expected_sent_messages)

        for i in range(response_sent_messages):
            sent = sent_messages[sent_messages_before + i]
            self.assertEqual(sent['method'], "sendMessage")
            if not random:
                self.assertEqual(sent['text'], response_text[i])
            else:
                self.assertIn(sent['text'], response_text)

    def get_keyboard(self, message):
        return json.loads(message['reply_markup'])['inline_keyboard']

    def button_in_list(self, name, url, list_command):
        self.sendCommand("/" + list_command)
        inline_keyboard = self.get_keyboard(self.bot.sent_messages[-1])
        for row in inline_keyboard:
            for button in row:
                if button["text"] == name and button["url"] == url:
                    return True
        return False

    def test_help(self):
        with db_session:
            for c in Command.select():
                c.description = ""
            Command(name="comandoSinDescripcion1")
            Command(name="comandoConDescripcion1", description="Descripción 1")
            Command(name="comandoSinDescripcion2")
            Command(name="comandoConDescripcion2", description="Descripción 2")
            Command(name="comandoSinDescripcion3")
            Command(name="comandoConDescripcion3", description="Descripción 3")

        self.assert_bot_response("/help",
                                 ("/comandoConDescripcion1 - Descripción 1\n"
                                  "/comandoConDescripcion2 - Descripción 2\n"
                                  "/comandoConDescripcion3 - Descripción 3\n"))

    def test_start(self):
        self.assert_bot_response(
            "/start",
            "Hola, ¿qué tal? ¡Mandame /help si no sabés qué puedo hacer!")

    def test_estasvivo(self):
        self.assert_bot_response("/estasvivo", "Sí, estoy vivo.")

    def test_rozendioanalisis(self):
        self.assert_bot_response("/rozendioanalisis",
                                 "¡Sí, Rozen ya dio el final de análisis!")

    # TODO: Rename
    def list_test(self, command, listable_type):
        self.assert_bot_response(command, "Grupos: ")

        # Assertions on keyboard
        inline_keyboard = self.get_keyboard(self.bot.sent_messages[-1])
        self.assertEqual(len(inline_keyboard), 2)  # Number of rows
        for i in range(2):
            row = inline_keyboard[i]
            self.assertEqual((len(row)), 3)  # Number of columns
            for j in range(3):
                button = row[j]
                button_number = i * 3 + j
                self.assertEqual(
                    button['text'],
                    listable_type._discriminator_ + " " + str(button_number))
                self.assertEqual(button['url'],
                                 "https://url" + str(button_number) + ".com")
                self.assertEqual(button['callback_data'], button['url'])

    def test_listar(self):
        self.list_test("/listar", Obligatoria)

    def test_listaroptativa(self):
        self.list_test("/listaroptativa", Optativa)

    def test_listarotro(self):
        self.list_test("/listarotro", Otro)

    def suggestion_test(self, command, list_command, listable_type):
        name = "Sugerido"
        url = "sugerido.com"
        error_message = "Hiciste algo mal, la idea es que pongas:\n" +\
                        command + " <nombre>|<link>"

        # Invalid command usages
        self.assert_bot_response(command, error_message)
        self.assert_bot_response(command + " " + name, error_message)
        self.assert_bot_response(command + " " + name + "|", error_message)
        self.assert_bot_response(command + " |" + url, error_message)
        self.assert_bot_response(command + " |", error_message)
        self.assert_bot_response(command + " " + name + "|" + url + "|sobra",
                                 error_message)

        # Make a group suggestion to accept
        self.assert_bot_response(command + " " + name + "|" + url, [
            listable_type.__name__ + ": " + name + "\n" + url,
            "OK, se lo mando a Rozen."
        ])

        # Assertions on keyboard
        inline_keyboard = self.get_keyboard(self.bot.sent_messages[-2])
        self.assertEqual(len(inline_keyboard), 1)  # Number of rows
        row = inline_keyboard[0]
        self.assertEqual(len(row), 2)  # Number of columns
        self.assertEqual(row[0]["text"], "Aceptar")
        self.assertEqual(row[1]["text"], "Rechazar")

        # The suggested group shouldn't be listed
        self.assertFalse(self.button_in_list(name, url, list_command))

        # Pressing the "Aceptar" button makes the group listable
        u = self.cqg.get_callback_query(message=self.mg.get_message().message,
                                        data=row[0]["callback_data"])
        self.bot.insertUpdate(u)
        self.assertTrue(self.button_in_list(name, url, list_command))
        with db_session:
            delete(l for l in Listable if l.name == name)

        # Make a group suggestion to reject
        self.sendCommand(command + " " + name + "|" + url)
        inline_keyboard = self.get_keyboard(self.bot.sent_messages[-2])
        row = inline_keyboard[0]

        # Pressing the "Rechazar" button doesn't make the group listable
        u = self.cqg.get_callback_query(message=self.mg.get_message().message,
                                        data=row[1]["callback_data"])
        self.bot.insertUpdate(u)
        self.assertFalse(self.button_in_list(name, url, list_command))

        # The database is clean of rejected suggestions
        with db_session:
            self.assertEqual(count(l for l in Listable if l.name == name), 0)

    def test_sugerirgrupo(self):
        self.suggestion_test("/sugerirgrupo", "listar", Obligatoria)

    def test_sugeriroptativa(self):
        self.suggestion_test("/sugeriroptativa", "listaroptativa", Optativa)

    def test_sugerirotro(self):
        self.suggestion_test("/sugerirotro", "listarotro", Otro)

    def test_logger(self):
        with self.assertLogs("DCUBABOT", level='INFO') as cm:
            user, _ = self.sendCommand("/listar")
            first_message = 'INFO:DCUBABOT:' + str(user.id) + ': /listar'
            user, _ = self.sendCommand("/estasvivo")
            second_message = 'INFO:DCUBABOT:' + str(user.id) + ': /estasvivo'
            self.assertEqual(cm.output, [first_message, second_message])

    def test_cubawiki(self):
        cubawiki_url = "https://www.cubawiki.com.ar/index.php/Segundo_Parcial_del_10/12/18"
        positive_chat_id = -123456
        negative_chat_id_no_cubawiki = -654321
        negative_chat_id_no_entry = -123321
        with db_session:
            Obligatoria(name="Cubawiki",
                        url="test.com",
                        chat_id=positive_chat_id,
                        cubawiki_url=cubawiki_url)
            Obligatoria(name="Cubawiki",
                        url="test.com",
                        chat_id=negative_chat_id_no_cubawiki)

        # Positive test case
        self.assert_bot_response("/cubawiki",
                                 cubawiki_url,
                                 chat_id=positive_chat_id)

        # Negative test cases
        self.assert_bot_response("/cubawiki",
                                 None,
                                 chat_id=negative_chat_id_no_cubawiki)
        self.assert_bot_response("/cubawiki",
                                 None,
                                 chat_id=negative_chat_id_no_entry)

        with db_session:
            delete(o for o in Obligatoria if o.name == "Cubawiki")

    def test_felizdia(self):
        today = datetime.datetime(2019, 1, 1)
        self.assertEqual(felizdia_text(today), "Feliz 1 de Enero")
        today = datetime.datetime(2019, 2, 1)
        self.assertEqual(felizdia_text(today), "Feliz 1 de Febrero")
        today = datetime.datetime(2019, 3, 1)
        self.assertEqual(felizdia_text(today), "Feliz 1 de Marzo")
        today = datetime.datetime(2019, 4, 4)
        self.assertEqual(felizdia_text(today), "Feliz 4 de Abril")
        today = datetime.datetime(2019, 5, 21)
        self.assertEqual(felizdia_text(today), "Feliz 21 de Mayo")

    # TODO: Test randomness?
    def test_noitip(self):
        noitips = ["me siento boludeadisimo", "Not this shit again", "noitip"]
        with db_session:
            for phrase in noitips:
                Noitip(text=phrase)

        self.assert_bot_response("/noitip", noitips, random=True)

    def test_asm(self):
        with db_session:
            AsmInstruction(mnemonic="AAD",
                           summary="ASCII Adjust AX Before Division",
                           url="https://www.felixcloutier.com/x86/aad")
            AsmInstruction(mnemonic="ADD",
                           summary="Add",
                           url="https://www.felixcloutier.com/x86/add")
            AsmInstruction(
                mnemonic="ADDPD",
                summary="Add Packed Double-Precision Floating-Point Values",
                url="https://www.felixcloutier.com/x86/addpd")
            AsmInstruction(mnemonic="MOV",
                           summary="Move to/from Control Registers",
                           url="http://www.felixcloutier.com/x86/MOV-1.html")
            AsmInstruction(mnemonic="MOV",
                           summary="Move to/from Debug Registers",
                           url="http://www.felixcloutier.com/x86/MOV-2.html")
            AsmInstruction(
                mnemonic="INT n",
                summary="Call to Interrupt Procedure",
                url="http://www.felixcloutier.com/x86/INT%20n:INTO:INT%203.html"
            )

        not_found = "No pude encontrar esa instrucción."
        possibles = not_found + "\nQuizás quisiste decir:"
        add_info = ("[ADD] Descripción: Add.\n"
                    "Más info: https://www.felixcloutier.com/x86/add")
        addpd_info = (
            "[ADDPD] Descripción: Add Packed Double-Precision Floating-Point Values.\n"
            "Más info: https://www.felixcloutier.com/x86/addpd")
        mov1_info = ("[MOV] Descripción: Move to/from Control Registers.\n"
                     "Más info: http://www.felixcloutier.com/x86/MOV-1.html")
        mov2_info = ("[MOV] Descripción: Move to/from Debug Registers.\n"
                     "Más info: http://www.felixcloutier.com/x86/MOV-2.html")
        intn_info = (
            "[INT n] Descripción: Call to Interrupt Procedure.\n"
            "Más info: http://www.felixcloutier.com/x86/INT%20n:INTO:INT%203.html"
        )

        self.assert_bot_response("/asm", "No me pasaste ninguna instrucción.")
        self.assert_bot_response("/asm add", add_info)
        self.assert_bot_response("/asm ADDPD", addpd_info)
        self.assert_bot_response("/asm a", not_found)
        self.assert_bot_response("/asm Adp", possibles + "\n" + add_info)
        self.assert_bot_response("/asm ADDPS", possibles + "\n" + addpd_info)
        self.assert_bot_response(
            "/asm addP", possibles + "\n" + add_info + "\n" + addpd_info)
        self.assert_bot_response("/asm MOV", mov1_info + "\n" + mov2_info)
        self.assert_bot_response("/asm INT n", intn_info)
class MessageGenerator(PtbGenerator):
    """
    Message generator class.

    Attributes:
        bot (ptbtest.Mockbot): Bot to encode with the messages

    Args:
        bot (Optional[ptbtest.Mockbot]): supply your own for a custom botname
    """

    def __init__(self, bot=None):
        PtbGenerator.__init__(self)
        self.idgen = self._gen_id()
        self.ug = UserGenerator()
        self.cg = ChatGenerator()
        if not bot:
            self.bot = Mockbot()
        elif isinstance(bot, Mockbot):
            self.bot = bot
        else:
            raise BadBotException

    def _gen_id(self):
        x = 1
        while True:
            yield x
            x += 1

    @update("edited_channel_post")
    def get_edited_channel_post(self, channel_post=None, **kwargs):
        """
        Parameters:
            channel_post (Optional(telegram.Message)): The edited_channel_post will the same user, chat and message_id
            **kwargs: See get_message for the full list

        Returns:
            telegram.Update: A telegram update object containing a :py:class:`telegram.Message`.
        """

        id, user, chat = None, None, None
        if channel_post:
            if not isinstance(channel_post, Message):
                raise BadMessageException
            id = channel_post.message_id
            user = channel_post.from_user
            chat = channel_post.chat

        return self.get_channel_post(id=id, user=user, chat=chat, **kwargs).channel_post

    @update("channel_post")
    def get_channel_post(self, chat=None, user=None, **kwargs):
        """
        Parameters:
            chat (Optional[telegram.Chat]): Chat with type='channel' to use with this update
            user (Optional[telegram.User]): User for the update. None if omitted
            **kwargs: See get_message

        Returns:
            telegram.Update: A telegram update object containing a :py:class:`telegram.Message.
        """
        if chat:
            if not isinstance(chat, Chat):
                raise BadChatException
            if not chat.type == "channel":
                raise BadChatException(
                    "Can only use chat.type='channel' for get_channel_post"
                )
        else:
            chat = ChatGenerator().get_chat(type="channel")

        return self.get_message(chat=chat, user=user, channel=True, **kwargs).message

    @update("edited_message")
    def get_edited_message(self, message=None, **kwargs):
        """
        Parameters:
            message (Optional(telegram.Message)): The edited_message will have the same user, chat and message_id
            **kwargs: See get_message for the full list

        Returns:
            telegram.Update: A telegram update object containing a :py:class:`telegram.Message`.

        """
        id, user, chat = None, None, None
        if message:
            if not isinstance(message, Message):
                raise BadMessageException
            id = message.message_id
            user = message.from_user
            chat = message.chat

        return self.get_message(id=id, user=user, chat=chat, **kwargs).message

    @update("message")
    def get_message(
            self,
            id=None,
            user=None,
            chat=None,
            private=True,
            forward_from=None,
            forward_from_chat=None,
            forward_date=None,
            reply_to_message=None,
            text=None,
            entities=None,
            audio=None,
            document=None,
            photo=None,
            sticker=None,
            video=None,
            voice=None,
            caption=None,
            contact=None,
            location=None,
            venue=None,
            new_chat_members=None,
            left_chat_member=None,
            new_chat_title=None,
            new_chat_photo=None,
            delete_chat_photo=False,
            group_chat_created=False,
            supergroup_chat_created=False,
            migrate_to_chat_id=None,
            migrate_from_chat_id=None,
            channel_chat_created=False,
            pinned_message=None,
            forward_from_message_id=None,
            parse_mode=None,
            channel=False,
            bot=None,
            media_group_id=None,
            poll=None,
            **kwargs
    ):
        """
        When called without arguments will return an update object for a message from a private chat with a
        random user. for modifiers see args.

        Notes:
            whenever a list of telegram.PhotoSize objects is expected but not supplied it will always be a
            list with two random sizes between 40-400 pixels. These will not be valid file id's

        Parameters:
            user (Optional[telegram.User]): User the message is from (m.from_user)
            chat (Optional[telegram.Chat]): Chat the message is from (m.chat).
            private (Optional[bool]): If the message is private (optionally with the supplied user) default=True
            text (str): The text for the message, can make use of markdown or html, make sure to specify with parse_mode
            parse_mode (Optional[str]): "HTML" or "Markdown" parses the text and fills entities
            entities (Optional[lst(telegram.MessageEntity)]): when text and parsemode are set this will be filled with the entities in the text.  # noqa: E501
            reply_to_message (Optional[telegram.Message): Messages this one is a reply to
            forward_from (Optional[telegram.User): User this message is forwarded from
            forward_from_chat (Optional[telegram.Chat]): channel this message is forwarded from
            forward_date (Optional[int]): Original sent date
            forward_from_message_id (Optional[int]): message id from forwarded channel post.
            new_chat_members (List[telegram.User]): Optional. Information about new members to the chat. (the bot itself may be one of these members).
            left_chat_member (Optional[telegram.User]): Member left this chat
            new_chat_title (Optional[str]): New title for the chat
            new_chat_photo (Optional[lst(telegram.Photosize)] or True): New picture for the group
            pinned_message (Optional[telegram.Message]): Pinned message for supergroups
            channel_chat_created (Optional[True]): Not integrated
            migrate_from_chat_id (Optional[int]): Not integrated
            migrate_to_chat_id (Optional[int]): Not integrated
            supergroup_chat_created (Optional[True]): Not integrated
            group_chat_created (Optional[True]): Not integrated
            delete_chat_photo (Optional[True]): Not integrated
            venue (Optional[telegram.Venue or True]): Either the right object or True to generate one
            location (optional[telegram.Location or True]): Either the right object or True to generate one
            contact (optional[telegram.Contact or True]): Either the right object or True to generate one
            caption (Optional[str or True]: Either the right object or True to generate one
            voice (Optional[telegram.Voice or True]): Either the right object or True to generate one
            video (Optional[telegram.Video or True]): Either the right object or True to generate one
            sticker (Optional[telegram.Sticker] or True): Either the right object or True to generate one
            photo (Optional[lst(telegram.PhotoSize) or True]): Either the right object or True to generate one
            document (Optional[telegram.Document or True]): Either the right object or True to generate one
            audio (Optional[telegram.Audio] or True): Either the right object or True to generate one

        Returns:
            telegram.Update: A telegram update object containing a :py:class:`telegram.Message`.
        """
        if not channel:
            user, chat = self._get_user_and_chat(user, chat, private)

        if reply_to_message and not isinstance(reply_to_message, Message):
            raise BadMessageException

        forward_date, forward_from, forward_from_message_id = self._handle_forward(
            forward_date, forward_from, forward_from_chat, forward_from_message_id
        )

        text, entities = self._handle_text(text, parse_mode)

        new_chat_photo = self._handle_status(
            channel_chat_created,
            chat,
            delete_chat_photo,
            group_chat_created,
            left_chat_member,
            migrate_from_chat_id,
            migrate_to_chat_id,
            new_chat_members,
            new_chat_photo,
            new_chat_title,
            pinned_message,
            supergroup_chat_created,
        )

        (
            audio,
            contact,
            document,
            location,
            photo,
            sticker,
            venue,
            video,
            voice,
        ) = self._handle_attachments(
            audio,
            contact,
            document,
            location,
            photo,
            sticker,
            user,
            venue,
            video,
            voice,
            caption,
        )
        if poll:
            if poll in {POLL_QUIZ, POLL_REGULAR}:
                poll = self._get_poll(poll)
            else:
                raise BadMessageException("Poll can be either regular or quiz")

        return Message(
            message_id=id or next(self.idgen),
            from_user=user,
            date=datetime.datetime.now(),
            chat=chat,
            text=text,
            forward_from=forward_from,
            forward_from_chat=forward_from_chat,
            reply_to_message=reply_to_message,
            entities=entities,
            audio=audio,
            document=document,
            photo=photo,
            sticker=sticker,
            video=video,
            voice=voice,
            caption=caption,
            contact=contact,
            location=location,
            venue=venue,
            new_chat_members=new_chat_members,
            left_chat_member=left_chat_member,
            new_chat_title=new_chat_title,
            new_chat_photo=new_chat_photo,
            delete_chat_photo=delete_chat_photo,
            group_chat_created=group_chat_created,
            supergroup_chat_created=supergroup_chat_created,
            migrate_to_chat_id=migrate_to_chat_id,
            migrate_from_chat_id=migrate_from_chat_id,
            channel_chat_created=channel_chat_created,
            pinned_message=pinned_message,
            forward_from_message_id=forward_from_message_id,
            forward_date=forward_date,
            bot=bot or self.bot,
            media_group_id=media_group_id,
            poll=poll,
        )

    def _handle_attachments(
            self,
            audio,
            contact,
            document,
            location,
            photo,
            sticker,
            user,
            venue,
            video,
            voice,
            caption,
    ):
        attachments = [
            x
            for x in [
                photo,
                venue,
                location,
                contact,
                voice,
                video,
                sticker,
                document,
                audio,
            ]
            if x
        ]
        if caption and not attachments:
            raise BadMessageException("Can't have a caption without attachment")
        if len(attachments) > 1:
            raise BadMessageException("can't add more than one attachment")
        if photo:
            if isinstance(photo, list):
                if all([isinstance(x, PhotoSize) for x in photo]):
                    pass
                else:
                    raise BadMessageException(
                        "photo must either be True or list(telegram.PhotoSize)"
                    )
            elif isinstance(photo, bool):
                photo = self._get_photosize()
            else:
                raise BadMessageException(
                    "photo must either be True or list(telegram.PhotoSize)"
                )
        if location:
            if isinstance(location, Location):
                pass
            elif isinstance(location, dict):
                location = Location(**location)
            elif isinstance(location, bool):
                location = self._get_location()
            else:
                raise BadMessageException(
                    "location must either be True or telegram.Location"
                )
        if venue:
            if isinstance(venue, Venue):
                pass
            elif isinstance(venue, bool):
                venue = self._get_venue()
            elif isinstance(venue, dict):
                venue["location"] = Location(**venue)
                venue = Venue(**venue)
            else:
                raise BadMessageException("venue must either be True or telegram.Venue")
        if contact:
            if isinstance(contact, Contact):
                pass
            elif isinstance(contact, dict):
                contact = Contact(**contact)
            elif isinstance(contact, bool):
                contact = self._get_contact(user)
            else:
                raise BadMessageException(
                    "contact must either be True or telegram.Contact"
                )
        if voice:
            if isinstance(voice, Voice):
                pass
            elif isinstance(voice, bool):
                voice = self._get_voice()
            elif isinstance(voice, dict):
                voice = Voice(**voice)
            else:
                raise BadMessageException("voice must either be True or telegram.Voice")
        if video:
            if isinstance(video, Video):
                pass
            elif isinstance(video, bool):
                video = self._get_video()
            elif isinstance(video, dict):
                video = self._get_video(data=video)
            else:
                raise BadMessageException("video must either be True or telegram.Video")
        if sticker:
            if isinstance(sticker, Sticker):
                pass
            elif isinstance(sticker, bool):
                sticker = self._get_sticker()
            elif isinstance(sticker, dict):
                sticker = self._get_sticker(sticker)
            else:
                raise BadMessageException(
                    "sticker must either be True or telegram.Sticker"
                )
        if document:
            if isinstance(document, Document):
                pass
            elif isinstance(document, dict):
                document = Document(**document)
            elif isinstance(document, bool):
                document = self._get_document()
            else:
                raise BadMessageException(
                    "document must either be True or telegram.Document"
                )
        if audio:
            if isinstance(audio, Audio):
                pass
            elif isinstance(audio, bool):
                audio = self._get_audio()
            elif isinstance(audio, dict):
                audio = Audio(**audio)
            else:
                raise BadMessageException("audio must either be True or telegram.Audio")
        return audio, contact, document, location, photo, sticker, venue, video, voice

    def _handle_forward(
            self, forward_date, forward_from, forward_from_chat, forward_from_message_id
    ):
        if forward_from and not isinstance(forward_from, User):
            raise BadUserException()
        if forward_from_chat:
            if not isinstance(forward_from_chat, Chat):
                raise BadChatException
            if forward_from_chat.type != "channel":
                raise BadChatException('forward_from_chat must be of type "channel"')
            if not forward_from:
                forward_from = UserGenerator().get_user()
        if forward_from:
            if not isinstance(forward_date, datetime.datetime):
                now = datetime.datetime.now()
            else:
                now = forward_date
            try:
                # Python 3.3+
                forward_date = datetime.datetime.now()
            except AttributeError:
                # Python 3 (< 3.3) and Python 2
                forward_date = datetime.datetime.now()
        if (
                forward_from_message_id and not isinstance(forward_from_message_id, int)
        ) or (forward_from_chat and not forward_from_message_id):
            forward_from_message_id = next(self.idgen)
        return forward_date, forward_from, forward_from_message_id

    def _handle_status(
            self,
            channel_chat_created,
            chat,
            delete_chat_photo,
            group_chat_created,
            left_chat_member,
            migrate_from_chat_id,
            migrate_to_chat_id,
            new_chat_members,
            new_chat_photo,
            new_chat_title,
            pinned_message,
            supergroup_chat_created,
    ):
        status_messages = [
            new_chat_members,
            left_chat_member,
            new_chat_title,
            new_chat_photo,
            delete_chat_photo,
            group_chat_created,
            supergroup_chat_created,
            channel_chat_created,
            migrate_to_chat_id,
            migrate_from_chat_id,
            pinned_message,
        ]
        if len([x for x in status_messages if x]) > 1:
            raise BadMessageException("Limit to only one status message per message")
        if new_chat_members:
            for new_chat_member in new_chat_members:
                if not isinstance(new_chat_member, User):
                    raise BadUserException
                if chat.type == "private":
                    raise BadChatException("Can not add members to private chat")
        if left_chat_member:
            if not isinstance(left_chat_member, User):
                raise BadUserException
            if chat.type == "private":
                raise BadChatException("People can not leave a private chat")
        if new_chat_title:
            if chat.type == "private":
                raise BadChatException("Can not change title of private chat")
            chat.title = new_chat_title
        if new_chat_photo:
            if chat.type == "private":
                raise BadChatException(
                    "Can't change the photo for a private chat a private chat"
                )
            if isinstance(new_chat_photo, list):
                if all([isinstance(x, PhotoSize) for x in new_chat_photo]):
                    pass
                else:
                    raise BadMessageException(
                        "new_chat_photo must either be True or list(telegram.PhotoSize)"
                    )
            elif isinstance(new_chat_photo, bool) and new_chat_photo:
                new_chat_photo = self._get_photosize()
            else:
                raise BadMessageException(
                    "new_chat_photo must either be True or list(telegram.PhotoSize)"
                )
        if pinned_message:
            if not isinstance(pinned_message, Message):
                raise BadMessageException
            elif chat.type != "supergroup":
                raise BadChatException("Messages can only be pinned in supergroups")
            else:
                pinned_message.reply_to_message = None
        return new_chat_photo

    def _get_user_and_chat(self, user, chat, private):
        if chat:
            if not isinstance(chat, Chat):
                raise BadChatException
            if chat.type == "channel":
                raise BadChatException("Use get_channel_post to get channel updates.")
        if user:
            if not isinstance(user, User):
                raise BadUserException
        if chat:
            if not user:
                if chat.type == "private":
                    user = self.ug.get_user(
                        first_name=chat.first_name,
                        last_name=chat.last_name,
                        username=chat.username,
                        id=chat.id,
                    )
                else:
                    user = self.ug.get_user()
        elif user and private:
            chat = self.cg.get_chat(user=user)
        elif user:
            chat = self.cg.get_chat(type="group")
        elif private:
            user = self.ug.get_user()
            chat = self.cg.get_chat(user=user)
        else:
            user = self.ug.get_user()
            chat = self.cg.get_chat(type="group")
        return user, chat

    def _handle_text(self, text, parse_mode):
        if text and parse_mode:
            if parse_mode not in [
                "HTML",
                "Markdown",
            ]:  # , "MarkdownV2"]:  # write parser before enabling V2
                raise BadMarkupException(
                    "Markdown mode must be HTML or Markdown"
                )  # or MarkdownV2')
            elif parse_mode == "HTML":
                text, entities = EntityParser.parse_html(text)
            else:
                text, entities = EntityParser.parse_markdown(text)
        else:
            entities = []
        return text, entities

    def _get_photosize(self):
        tmp = []
        import uuid
        from random import randint

        for _ in range(2):
            w, h = randint(40, 400), randint(40, 400)
            s = w * h * 2
            tmp.append(
                PhotoSize(
                    file_id=str(uuid.uuid4()),
                    file_unique_id=str(uuid.uuid4()),
                    width=w,
                    height=h,
                    file_size=s,
                )
            )
        return tmp

    def _get_location(self):
        from random import uniform

        return Location(uniform(-180.0, 180.0), uniform(-90.0, 90.0))

    def _get_venue(self):
        loc = self._get_location()
        address = "somewherestreet 23"
        name = "Awesome place"
        return Venue(loc, name, address)

    def _get_contact(self, user):
        return Contact("06123456789", user.first_name)

    def _get_voice(self):
        import uuid
        from random import randint

        return Voice(
            file_id=str(uuid.uuid4()),
            file_unique_id=str(uuid.uuid4()),
            duration=randint(2, 300),
        )

    def _get_video(self, data=None):
        import uuid
        from random import randint

        if data:
            data["width"] = randint(40, 400)
            data["height"] = randint(40, 400)
            return Video(**data)
        return Video(
            file_id=str(uuid.uuid4()),
            file_unique_id=str(uuid.uuid4()),
            width=randint(40, 400),
            height=randint(40, 400),
            duration=randint(2, 300),
        )

    def _get_sticker(self, data=None):
        import uuid
        from random import randint

        if data is None:
            data = {}
        data["file_unique_id"] = data["file_id"] = str(uuid.uuid4())
        if "width" not in data:
            data["width"] = randint(20, 200)
            data["height"] = randint(20, 200)
        if "is_animated" not in data:
            data["is_animated"] = False
        return Sticker(**data)

    def _get_document(self):
        import uuid

        return Document(
            file_id=str(uuid.uuid4()),
            file_unique_id=str(uuid.uuid4()),
            file_name="somedoc.pdf",
        )

    def _get_audio(self):
        import uuid
        from random import randint

        return Audio(
            file_id=str(uuid.uuid4()),
            file_unique_id=str(uuid.uuid4()),
            duration=randint(1, 120),
            title="Some song",
        )

    def _get_poll(self, poll_type):
        import uuid
        from random import randint
        if poll_type == POLL_QUIZ:
            return Poll(
                id=str(uuid.uuid4()),
                question="Are you human?",
                options=[PollOption("Yes", 2),
                         PollOption("No", 5)],
                total_voter_count=7,
                is_closed=False,
                is_anonymous=True,
                type=POLL_QUIZ,
                correct_option_id=0,
                allows_multiple_answers=False,
            )
        else:
            return Poll(
                id=str(uuid.uuid4()),
                question="Are you human?",
                options=[PollOption("Yes", 2),
                         PollOption("No", 5)],
                total_voter_count=7,
                is_closed=False,
                is_anonymous=True,
                type=POLL_REGULAR,
                allows_multiple_answers=False,
            )
Exemple #22
0
class TestInlineKeyboard(unittest.TestCase):
    def setUp(self):
        # For use within the tests we nee some stuff. Starting with a Mockbot
        self.bot = Mockbot()
        # Some generators for users and chats
        self.cg = ChatGenerator()
        # And a Messagegenerator, CallbackQueryGenerator and updater (for use with the bot.)
        self.mg = MessageGenerator(self.bot)
        self.cqg = CallbackQueryGenerator(self.bot)
        self.updater = Updater(bot=self.bot)

    def test_callback(self):
        # first insert the callbackhandler, register it and start polling
        def button(bot, update):
            query = update.callback_query

            bot.editMessageText(text="Selected option: %s" % query.data,
                                chat_id=query.message.chat_id,
                                message_id=query.message.message_id)

        dp = self.updater.dispatcher
        dp.add_handler(CallbackQueryHandler(button))
        self.updater.start_polling()

        # the start callback in this example generates a message that will be edited, so let's mimick that message
        # for future reference
        keyboard = [[
            InlineKeyboardButton("Option 1", callback_data='1'),
            InlineKeyboardButton("Option 2", callback_data='2')
        ], [InlineKeyboardButton("Option 3", callback_data='3')]]

        reply_markup = InlineKeyboardMarkup(keyboard)
        chat = self.cg.get_chat()
        start_message = self.bot.sendMessage(chat_id=chat.id,
                                             text='Please choose:',
                                             reply_markup=reply_markup)

        # now let's create some callback query's to send
        u1 = self.cqg.get_callback_query(message=start_message, data="1")
        u2 = self.cqg.get_callback_query(message=start_message, data="2")
        u3 = self.cqg.get_callback_query(message=start_message, data="3")

        # And test them one by one
        self.bot.insertUpdate(u1)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], "Selected option: 1")
        self.assertEqual(data['chat_id'], start_message.chat.id)
        self.assertEqual(data['message_id'], start_message.message_id)
        self.bot.insertUpdate(u2)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], "Selected option: 2")
        self.assertEqual(data['chat_id'], start_message.chat.id)
        self.assertEqual(data['message_id'], start_message.message_id)
        self.bot.insertUpdate(u3)
        data = self.bot.sent_messages[-1]
        self.assertEqual(data['text'], "Selected option: 3")
        self.assertEqual(data['chat_id'], start_message.chat.id)
        self.assertEqual(data['message_id'], start_message.message_id)

        # stop polling
        self.updater.stop()
Exemple #23
0
    def get_callback_query(self,
                           user=None,
                           chat_instance=None,
                           message=None,
                           data=None,
                           inline_message_id=None,
                           game_short_name=None):
        """

        Returns a telegram.Update object containing a callback_query.

        Notes:
            One of message and inline_message_id must be present
            One of data and game_short_name must be present

        Parameters:
            user (Optional[telegram.User]): User that initiated the callback_query
            chat_instance (Optional[str]): unique identifier, not used
            message (Optional[telegram.Message]): Message the callback_query button belongs to
            inline_message_id (Optional[str]): Message the callback_query button belongs to
            data (Optional[string]): Data attached to the button
            game_short_name (Optional[str]): game identifier with this button

        Returns:
            telegram.Update: containing a :py:class:`telegram.CallbackQuery`

        """
        # Required
        if user:
            if not isinstance(user, User):
                raise BadUserException
        else:
            user = self.ug.get_user()
        if not chat_instance:
            chat_instance = self._gen_id()

        if message:
            if isinstance(message, Message):
                pass
            elif isinstance(message, bool):
                chat = ChatGenerator().get_chat(user=user)
                message = MessageGenerator().get_message(
                    user=self.bot.getMe(), chat=chat,
                    bot=self.bot.getMe()).message
            else:
                raise BadMessageException
        if inline_message_id:
            if isinstance(inline_message_id, str):
                pass
            elif isinstance(inline_message_id, bool):
                inline_message_id = self._gen_id()
            else:
                raise BadCallbackQueryException(
                    "inline_message_id should be string or True")

        if not len([x for x in [message, inline_message_id] if x]) == 1:
            raise BadCallbackQueryException(
                "exactly 1 of message and inline_message_id is needed")

        if not len([x for x in [data, game_short_name] if x]) == 1:
            raise BadCallbackQueryException(
                "exactly 1 of data and game_short_name is needed")

        return CallbackQuery(self._gen_id(), user, chat_instance, message,
                             data, inline_message_id, game_short_name,
                             self.bot)
class TestConversationbot2(unittest.TestCase):
    def setUp(self):
        self.bot = Mockbot()
        self.cg = ChatGenerator()
        self.ug = UserGenerator()
        self.mg = MessageGenerator(self.bot)
        self.updater = Updater(bot=self.bot)

    def test_conversation(self):
        CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)

        reply_keyboard = [['Age', 'Favourite colour'], ['Number of siblings', 'Something else...'], ['Done']]
        markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)

        def facts_to_str(user_data):
            facts = list()
            for key, value in user_data.items():
                facts.append('%s - %s' % (key, value))

            return "\n".join(facts).join(['\n', '\n'])

        def start(bot, update):
            update.message.reply_text(
                "Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
                "Why don't you tell me something about yourself?", reply_markup=markup)

            return CHOOSING

        def regular_choice(bot, update, user_data):
            text = update.message.text
            user_data['choice'] = text
            update.message.reply_text('Your %s? Yes, I would love to hear about that!' % text.lower())

            return TYPING_REPLY

        def custom_choice(bot, update):
            update.message.reply_text('Alright, please send me the category first, '
                                      'for example "Most impressive skill"')

            return TYPING_CHOICE

        def received_information(bot, update, user_data):
            text = update.message.text
            category = user_data['choice']
            user_data[category] = text
            del user_data['choice']

            update.message.reply_text("Neat! Just so you know, this is what you already told me:"
                                      "%s"
                                      "You can tell me more, or change your opinion on something."
                                      % facts_to_str(user_data), reply_markup=markup)

            return CHOOSING

        def done(bot, update, user_data):
            if 'choice' in user_data:
                del user_data['choice']

            update.message.reply_text("I learned these facts about you:"
                                      "%s"
                                      "Until next time!" % facts_to_str(user_data))

            user_data.clear()
            return ConversationHandler.END

        conv_handler = ConversationHandler(
            entry_points=[CommandHandler('start', start)],
            states={
                CHOOSING: [RegexHandler('^(Age|Favourite colour|Number of siblings)$',
                                        regular_choice,
                                        pass_user_data=True),
                           RegexHandler('^Something else...$',
                                        custom_choice),
                           ],
                TYPING_CHOICE: [MessageHandler(Filters.text,
                                               regular_choice,
                                               pass_user_data=True),
                                ],
                TYPING_REPLY: [MessageHandler(Filters.text,
                                              received_information,
                                              pass_user_data=True),
                               ],
            },
            fallbacks=[RegexHandler('^Done$', done, pass_user_data=True)]
        )
        dp = self.updater.dispatcher
        dp.add_handler(conv_handler)
        self.updater.start_polling()

        # We are going to test a conversationhandler. Since this is tied in with user and chat we need to
        # create both for consistancy
        user = self.ug.get_user()
        chat = self.cg.get_chat(type="group")
        user2 = self.ug.get_user()
        chat2 = self.cg.get_chat(user=user)

        # let's start the conversation
        u = self.mg.get_message(user=user, chat=chat, text="/start")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Doctor Botter\. I will")
        u = self.mg.get_message(user=user, chat=chat, text="Age")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Your age\? Yes")

        # now let's see what happens when another user in another chat starts conversating with the bot
        u = self.mg.get_message(user=user2, chat=chat2, text="/start")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Doctor Botter\. I will")
        self.assertEqual(data['chat_id'], chat2.id)
        self.assertNotEqual(data['chat_id'], chat.id)
        # and cancels his conv.
        u = self.mg.get_message(user=user2, chat=chat2, text="Done")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Until next time!")

        # cary on with first user
        u = self.mg.get_message(user=user, chat=chat, text="23")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Age - 23")
        u = self.mg.get_message(user=user, chat=chat, text="Something else...")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Most impressive skill")
        u = self.mg.get_message(user=user, chat=chat, text="programming skill")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"Your programming skill\? Yes")
        u = self.mg.get_message(user=user, chat=chat, text="High")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"programming skill - High")
        u = self.mg.get_message(user=user, chat=chat, text="Done")
        self.bot.insertUpdate(u)
        data = self.bot.sent_messages[-1]
        self.assertRegexpMatches(data['text'], r"programming skill - High")
        self.assertRegexpMatches(data['text'], r"Age - 23")

        self.updater.stop()