summaryrefslogtreecommitdiffstatshomepage
path: root/tests/conftest.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/conftest.py')
-rw-r--r--tests/conftest.py594
1 files changed, 594 insertions, 0 deletions
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..a36be2d
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,594 @@
+import os
+import shutil
+from datetime import date, timedelta
+from datetime import datetime as dt
+from datetime import timezone as tz
+
+import hircine
+import hircine.db as database
+import hircine.db.models as models
+import hircine.plugins
+import pytest
+from hircine.app import schema
+from hircine.enums import Category, Censorship, Direction, Language, Layout, Rating
+from sqlalchemy.ext.asyncio import AsyncSession
+
+
+@pytest.fixture(scope="session")
+def anyio_backend():
+ return "asyncio"
+
+
+def pytest_addoption(parser):
+ parser.addoption(
+ "--sql-echo",
+ action="store_true",
+ help="Enable logging of SQL statements",
+ )
+
+
+@pytest.fixture
+def empty_plugins(monkeypatch):
+ monkeypatch.setattr(hircine.plugins, "scraper_registry", {})
+ monkeypatch.setattr(hircine.plugins, "transformers", [])
+
+
+@pytest.fixture
+def data(tmpdir, request):
+ file = request.module.__file__
+ data = os.path.join(os.path.dirname(file), "data")
+
+ if os.path.isdir(data):
+ shutil.copytree(data, tmpdir, dirs_exist_ok=True)
+
+ return lambda dir: os.path.join(tmpdir, dir)
+
+
+@pytest.fixture(scope="session")
+def engine(pytestconfig):
+ yield database.create_engine(":memory:", echo=pytestconfig.option.sql_echo)
+
+
+@pytest.fixture
+async def session(anyio_backend, engine):
+ async with engine.begin() as conn:
+ await conn.begin_nested()
+ yield AsyncSession(conn, expire_on_commit=False, autoflush=False)
+ await conn.rollback()
+
+
+@pytest.fixture(autouse=True)
+async def patch_session(anyio_backend, session, engine, monkeypatch):
+ monkeypatch.setattr(hircine.db, "session", lambda: session)
+
+
+@pytest.fixture(scope="session", autouse=True)
+async def metadata(engine, anyio_backend):
+ await database.initialize(engine)
+
+
+@pytest.fixture
+def schema_execute():
+ async def _execute(endpoint, variables=None):
+ return await schema.execute(endpoint, variable_values=variables)
+
+ return _execute
+
+
+@pytest.fixture
+def execute(schema_execute):
+ def wrapper(q):
+ async def _execute():
+ return await schema_execute(q)
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_add(schema_execute):
+ def wrapper(q):
+ async def _execute(input):
+ return await schema_execute(q, {"input": input})
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_update(schema_execute):
+ def wrapper(q):
+ async def _execute(ids, input):
+ return await schema_execute(q, {"ids": ids, "input": input})
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_update_single(schema_execute):
+ def wrapper(q):
+ async def _execute(id, input):
+ return await schema_execute(q, {"id": id, "input": input})
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_delete(schema_execute):
+ def wrapper(q):
+ async def _execute(ids):
+ return await schema_execute(q, {"ids": ids})
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_id(schema_execute):
+ def wrapper(q):
+ async def _execute(id):
+ return await schema_execute(q, {"id": id})
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_filter(schema_execute):
+ def wrapper(q):
+ async def _execute(filter=None):
+ return await schema_execute(q, {"filter": filter} if filter else None)
+
+ return _execute
+
+ return wrapper
+
+
+@pytest.fixture
+def execute_sort(schema_execute):
+ def wrapper(q):
+ async def _execute(sort=None):
+ return await schema_execute(q, {"sort": sort} if sort else None)
+
+ return _execute
+
+ return wrapper
+
+
+class DB:
+ @staticmethod
+ async def add(model):
+ async with database.session() as s:
+ s.add(model)
+ await s.commit()
+ return model
+
+ @staticmethod
+ async def add_all(*models):
+ async with database.session() as s:
+ s.add_all(models)
+ await s.commit()
+ return models
+
+ @staticmethod
+ async def get(modelcls, id, full=False):
+ async with database.session() as s:
+ options = modelcls.load_full() if full else []
+ model = await s.get(modelcls, id, options=options)
+ return model
+
+ @staticmethod
+ async def delete(modelcls, id):
+ async with database.session() as s:
+ model = await s.get(modelcls, id)
+ await s.delete(model)
+ await s.commit()
+ return
+
+
+class Response:
+ def __init__(self, response, key=None):
+ assert response.errors is None
+
+ if key is None:
+ assert response.data is not None
+ assert len(response.data) == 1
+ key = next(iter(response.data.keys()))
+
+ assert key in response.data
+ self.data = response.data.get(key)
+ self.errors = response.errors
+
+ def __getattr__(self, name):
+ assert name in self.data
+ return self.data.get(name)
+
+ def assert_is(self, typename):
+ assert self.data["__typename"] == typename
+
+
+@pytest.fixture
+def gen_artist():
+ def _gen():
+ yield models.Artist(id=1, name="alan smithee")
+ yield models.Artist(id=2, name="david agnew")
+ yield models.Artist(id=3, name="robin bland")
+ yield models.Artist(id=4, name="robin smith")
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_character():
+ def _gen():
+ yield models.Character(id=1, name="greta giraffe")
+ yield models.Character(id=2, name="bob bear")
+ yield models.Character(id=3, name="rico rhinoceros")
+ yield models.Character(id=4, name="ziggy zebra")
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_circle():
+ def _gen():
+ yield models.Circle(id=1, name="archimedes")
+ yield models.Circle(id=2, name="bankoff")
+ yield models.Circle(id=3, name="carlyle")
+ yield models.Circle(id=4, name="ford")
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_namespace():
+ def _gen():
+ yield models.Namespace(id=1, name="animal", sort_name="animal")
+ yield models.Namespace(id=2, name="human", sort_name="human")
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_tag():
+ def _gen():
+ yield models.Tag(
+ id=1, name="small", description="barely visible", namespaces=[]
+ )
+ yield models.Tag(
+ id=2,
+ name="medium",
+ description="mostly average",
+ namespaces=[],
+ )
+ yield models.Tag(id=3, name="big", description="impressive", namespaces=[])
+ yield models.Tag(
+ id=4, name="massive", description="what is THAT", namespaces=[]
+ )
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_world():
+ def _gen():
+ yield models.World(id=1, name="animal friends")
+ yield models.World(id=2, name="criminanimals")
+ yield models.World(id=3, name="in the nude")
+ yield models.World(id=4, name="wall street")
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_image():
+ def _gen():
+ yield models.Image(
+ id=1, hash="1bb05614b44bf177589632a51ce216a2", width=3024, height=2106
+ )
+ yield models.Image(
+ id=2, hash="77dfd96aee1bc8c36ab7095fcf18f7ff", width=3024, height=2094
+ )
+ yield models.Image(
+ id=3, hash="109aac22f29bd361fbfb19f975a1b7f0", width=3019, height=2089
+ )
+ yield models.Image(
+ id=4, hash="e18fc95f00a087ff001ecd8675eddd14", width=3024, height=2097
+ )
+ yield models.Image(
+ id=5, hash="0e2cd2f176e792a3777710978768bc90", width=1607, height=2259
+ )
+ yield models.Image(
+ id=6, hash="64e50730eb842750ebe5417a524b83e6", width=1556, height=2264
+ )
+ yield models.Image(
+ id=7, hash="d906ef54788cae72e1a511c9775e6d68", width=1525, height=2259
+ )
+ yield models.Image(
+ id=8, hash="0f8ead4a60df09a1dd071617b5d5583b", width=1545, height=2264
+ )
+ yield models.Image(
+ id=9, hash="912ccb4350fb17ea1248e26ecfb5d983", width=1607, height=2259
+ )
+ yield models.Image(
+ id=10, hash="108edee1b417f022a6d1f999bd32d16d", width=1546, height=2224
+ )
+ yield models.Image(
+ id=11, hash="97c0903cb0962741174f264aaa7015d4", width=1528, height=2257
+ )
+ yield models.Image(
+ id=12, hash="b5490ad31d2a8910087ba932073b4e52", width=1543, height=2271
+ )
+ yield models.Image(
+ id=13, hash="c9ab7febcb81974a992ed1de60c728ba", width=1611, height=2257
+ )
+ yield models.Image(
+ id=14, hash="bcfdf22ec17a09cd4f6a0af86e966e8f", width=1553, height=2265
+ )
+ yield models.Image(
+ id=15, hash="1f58f4b08bf6f4ca92bd29cbce26241e", width=1526, height=2258
+ )
+ yield models.Image(
+ id=16, hash="f87d7e55203b5e7cf9c801db48624ef0", width=1645, height=2262
+ )
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_page(gen_image):
+ def _gen():
+ yield models.Page(id=1, index=1, path="001.png", image=next(gen_image))
+ yield models.Page(id=2, index=2, path="002.png", image=next(gen_image))
+ yield models.Page(id=3, index=3, path="003.png", image=next(gen_image))
+ yield models.Page(id=4, index=4, path="004.png", image=next(gen_image))
+ yield models.Page(id=5, index=1, path="00.jpg", image=next(gen_image))
+ yield models.Page(id=6, index=2, path="01.jpg", image=next(gen_image))
+ yield models.Page(id=7, index=3, path="02.jpg", image=next(gen_image))
+ yield models.Page(id=8, index=4, path="03.jpg", image=next(gen_image))
+ yield models.Page(id=9, index=1, path="1.jpg", image=next(gen_image))
+ yield models.Page(id=10, index=2, path="2.jpg", image=next(gen_image))
+ yield models.Page(id=11, index=3, path="10.jpg", image=next(gen_image))
+ yield models.Page(id=12, index=4, path="11.jpg", image=next(gen_image))
+ yield models.Page(id=13, index=1, path="010.png", image=next(gen_image))
+ yield models.Page(id=14, index=2, path="011.png", image=next(gen_image))
+ yield models.Page(id=15, index=3, path="012.png", image=next(gen_image))
+ yield models.Page(id=16, index=4, path="013.png", image=next(gen_image))
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_jumbled_pages(gen_image):
+ def _gen():
+ yield models.Page(id=101, index=3, path="3.png", image=next(gen_image))
+ yield models.Page(id=52, index=9, path="9.png", image=next(gen_image))
+ yield models.Page(id=13, index=2, path="2.png", image=next(gen_image))
+ yield models.Page(id=258, index=10, path="10.png", image=next(gen_image))
+ yield models.Page(id=7, index=7, path="7.jpg", image=next(gen_image))
+ yield models.Page(id=25, index=5, path="5.jpg", image=next(gen_image))
+ yield models.Page(id=150, index=1, path="1.jpg", image=next(gen_image))
+ yield models.Page(id=69, index=4, path="4.jpg", image=next(gen_image))
+ yield models.Page(id=219, index=6, path="6.jpg", image=next(gen_image))
+ yield models.Page(id=34, index=8, path="8.jpg", image=next(gen_image))
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_jumbled_archive(gen_jumbled_pages):
+ def _gen():
+ pages = [next(gen_jumbled_pages) for _ in range(10)]
+ yield models.Archive(
+ id=100,
+ hash="4e1243bd22c66e76c2ba9eddc1f91394",
+ path="comics/jumbled.zip",
+ size=32559235,
+ mtime=dt(2002, 1, 23).astimezone(),
+ cover=pages[0].image,
+ pages=pages,
+ page_count=len(pages),
+ )
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_archive(gen_page):
+ def _gen():
+ pages = [next(gen_page) for _ in range(4)]
+ yield models.Archive(
+ id=1,
+ hash="1d394f66c49ccb1d3c30870904d31bd4",
+ path="comics/archive-01.zip",
+ size=7340032,
+ mtime=dt(2016, 5, 10).astimezone(),
+ cover=pages[0].image,
+ pages=pages,
+ page_count=len(pages),
+ )
+
+ pages = [next(gen_page) for _ in range(4)]
+ yield models.Archive(
+ id=2,
+ hash="d7d8929b2e606200e863d390f71b53bb",
+ path="comics/archive-02.zip",
+ size=11335106,
+ mtime=dt(2008, 10, 2, tzinfo=tz(timedelta(hours=+6))),
+ cover=pages[0].image,
+ pages=pages,
+ page_count=len(pages),
+ )
+
+ pages = [next(gen_page) for _ in range(4)]
+ yield models.Archive(
+ id=3,
+ hash="02669dbe08c4a5f4820c10b3ff2178fa",
+ path="comics/sub/archive-new.zip",
+ size=51841969,
+ mtime=dt(2005, 11, 17, tzinfo=tz(timedelta(hours=+2))),
+ cover=pages[0].image,
+ pages=pages,
+ page_count=len(pages),
+ )
+
+ pages = [next(gen_page) for _ in range(4)]
+ yield models.Archive(
+ id=4,
+ hash="6b2ecf5ceb8befd6d0c1cd353a3df709",
+ path="comics/archive-03.zip",
+ size=13568769,
+ mtime=dt(1999, 5, 8, tzinfo=tz(timedelta(hours=-2))),
+ cover=pages[0].image,
+ pages=pages,
+ page_count=len(pages),
+ )
+
+ return _gen()
+
+
+@pytest.fixture
+def gen_comic(
+ gen_archive,
+ gen_artist,
+ gen_character,
+ gen_circle,
+ gen_world,
+ gen_tag,
+ gen_namespace,
+):
+ def _gen():
+ artists = {a.id: a for a in gen_artist}
+ characters = {c.id: c for c in gen_character}
+
+ namespaces = {ns.id: ns for ns in gen_namespace}
+ tags = {t.id: t for t in gen_tag}
+
+ def tag(nid, tid):
+ return models.ComicTag(namespace=namespaces[nid], tag=tags[tid])
+
+ archive = next(gen_archive)
+ yield models.Comic(
+ id=1,
+ title="Arid Savannah Adventures",
+ url="file:///home/savannah/adventures",
+ category=Category.MANGA,
+ censorship=Censorship.NONE,
+ date=date(2010, 7, 5),
+ direction=Direction.LEFT_TO_RIGHT,
+ favourite=True,
+ language=Language.EN,
+ layout=Layout.SINGLE,
+ rating=Rating.SAFE,
+ archive=archive,
+ artists=[artists[1], artists[2]],
+ characters=list(characters.values()),
+ circles=[next(gen_circle)],
+ worlds=[next(gen_world)],
+ cover=archive.cover,
+ pages=archive.pages,
+ tags=[
+ tag(1, 1),
+ tag(1, 2),
+ tag(1, 3),
+ tag(1, 4),
+ ],
+ )
+
+ archive = next(gen_archive)
+ yield models.Comic(
+ id=2,
+ title="This Giraffe Stole My Wallet",
+ original_title="Diese Giraffe hat mein Geldbeutel geklaut",
+ url="ftp://crimes.local/giraffes.zip",
+ category=Category.MANGA,
+ censorship=Censorship.BAR,
+ date=date(2002, 2, 17),
+ direction=Direction.LEFT_TO_RIGHT,
+ favourite=False,
+ language=Language.EN,
+ layout=Layout.SINGLE,
+ rating=Rating.QUESTIONABLE,
+ archive=archive,
+ artists=[artists[3]],
+ characters=[characters[1]],
+ circles=[next(gen_circle)],
+ worlds=[next(gen_world)],
+ cover=archive.cover,
+ pages=archive.pages,
+ tags=[
+ tag(1, 3),
+ tag(2, 1),
+ ],
+ )
+
+ archive = next(gen_archive)
+ yield models.Comic(
+ id=3,
+ title="サイのスパ",
+ category=Category.ARTBOOK,
+ censorship=Censorship.MOSAIC,
+ date=date(2017, 5, 3),
+ direction=Direction.RIGHT_TO_LEFT,
+ favourite=False,
+ language=Language.JA,
+ layout=Layout.DOUBLE_OFFSET,
+ rating=Rating.EXPLICIT,
+ archive=archive,
+ artists=[artists[1], artists[4]],
+ characters=[characters[3]],
+ circles=[next(gen_circle)],
+ worlds=[next(gen_world)],
+ cover=archive.cover,
+ pages=archive.pages,
+ tags=[
+ tag(1, 4),
+ ],
+ )
+
+ archive = next(gen_archive)
+ yield models.Comic(
+ id=4,
+ title="In the Company of Vultures",
+ category=Category.DOUJINSHI,
+ date=date(2023, 3, 10),
+ direction=Direction.LEFT_TO_RIGHT,
+ favourite=False,
+ language=Language.EN,
+ layout=Layout.SINGLE,
+ rating=Rating.SAFE,
+ archive=archive,
+ artists=[artists[4]],
+ characters=[characters[4]],
+ circles=[next(gen_circle)],
+ worlds=[next(gen_world)],
+ cover=archive.cover,
+ pages=archive.pages,
+ tags=[
+ tag(2, 1),
+ tag(2, 2),
+ tag(2, 3),
+ ],
+ )
+
+ return _gen()
+
+
+@pytest.fixture
+def empty_comic(gen_archive):
+ archive = next(gen_archive)
+ yield models.Comic(
+ id=100,
+ title="Hic Sunt Dracones",
+ archive=archive,
+ cover=archive.cover,
+ pages=archive.pages,
+ )