import base64 import uuid from random import randint from unittest.mock import MagicMock import peewee as pw import pytest from faker import Faker faker = Faker() def factory(class_name: str = None, **kwargs): """Simple factory to create a class with attributes from kwargs""" class FactoryGeneratedClass: pass rewrite = { '__randint': lambda *args: randint(100_000_000, 999_999_999), } for key, value in kwargs.items(): if value in rewrite: value = rewrite[value](value) setattr(FactoryGeneratedClass, key, value) if class_name is not None: FactoryGeneratedClass.__qualname__ = class_name FactoryGeneratedClass.__name__ = class_name return FactoryGeneratedClass @pytest.fixture def db(): return pw.SqliteDatabase(':memory:') @pytest.fixture(autouse=True) def models(db): """Emulate the transaction -- create a new db before each test and flush it after. Also, return the app.models module""" from src import models app_models = [models.User] db.bind(app_models, bind_refs=False, bind_backrefs=False) db.connect() db.create_tables(app_models) yield models db.drop_tables(app_models) db.close() @pytest.fixture def bot_app(bot): """Our bot app, adds the magic curring `call` method to call it with fake bot""" from src import app app.call = lambda method, *args, **kwargs: getattr(app, method)(bot, *args, **kwargs) return app @pytest.fixture def bot(message): """Mocked instance of the bot""" class Bot: send_message = MagicMock() return Bot() @pytest.fixture def app(bot, mocker): mocker.patch('src.web.get_bot', return_value=bot) from src.web import app app.testing = True return app @pytest.fixture def tg_user(): """telegram.User""" class User(factory( 'User', id='__randint', is_bot=False, first_name=faker.first_name(), last_name=faker.last_name(), username=faker.user_name(), )): @property def full_name(self): return f'{self.first_name} {self.last_name}' return User() @pytest.fixture def db_user(models): return lambda **kwargs: models.User.create(**{**dict( pk=randint(100_000_000, 999_999_999), is_confirmed=False, email='user@e.mail', full_name='Petrovich', confirmation=str(uuid.uuid4()), chat_id=randint(100_000_000, 999_999_999), ), **kwargs}) @pytest.fixture def message(): """telegram.Message""" return lambda **kwargs: factory( 'Message', chat_id='__randint', reply_text=MagicMock(return_value=factory(message_id=100800)()), # always 100800 as the replied message id **kwargs, )() @pytest.fixture def update(message, tg_user): """telegram.Update""" return factory( 'Update', update_id='__randint', message=message(from_user=tg_user), )() @pytest.fixture def photo(): # 1x1 png pixel, base64 png_b64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABHNCSVQICAgIfAhkiAAAAA1JREFUCJlj+P///38ACfsD/QjR6B4AAAAASUVORK5CYII=' return base64.b64decode(png_b64) @pytest.fixture def tg_photo_file(photo): """telegram.File""" def _mock_download(custom_path=None, out=None, timeout=None): if out: out.write(photo) return out return lambda **kwargs: factory( 'File', file_id='__randint', file_size=None, file_path='/tmp/path/to/file.png', download=MagicMock(side_effect=_mock_download), **kwargs, )() @pytest.fixture def tg_photo_size(tg_photo_file): """telegram.PhotoSize""" return lambda **kwargs: factory( 'PhotoSize', file_id='__randint', width=1, height=1, download=MagicMock(return_value=tg_photo_file()), get_file=MagicMock(return_value=tg_photo_file()), **kwargs, )()