big upgrade UwU
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
"""Test doubles for the Telegram bot and the CDN fetcher."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from telegram.error import BadRequest
|
||||
|
||||
from sticker_downloader.config import DownloadConfig
|
||||
|
||||
|
||||
@dataclass
|
||||
class FakeFile:
|
||||
file_path: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class FakeThumbnail:
|
||||
file_id: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class FakeSticker:
|
||||
file_id: str
|
||||
file_unique_id: str = "uniq"
|
||||
emoji: str | None = "😀"
|
||||
is_animated: bool = False
|
||||
is_video: bool = False
|
||||
thumbnail: FakeThumbnail | None = None
|
||||
width: int = 512
|
||||
height: int = 512
|
||||
type: str = "regular"
|
||||
|
||||
|
||||
@dataclass
|
||||
class FakeStickerSet:
|
||||
name: str
|
||||
title: str = "A Pack"
|
||||
sticker_type: str = "regular"
|
||||
stickers: list[FakeSticker] = field(default_factory=list)
|
||||
thumbnail: FakeThumbnail | None = None
|
||||
|
||||
|
||||
class FakeBot:
|
||||
"""Implements just the two coroutines the downloader calls."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sets: dict[str, FakeStickerSet] | None = None,
|
||||
*,
|
||||
extensions: dict[str, str] | None = None,
|
||||
) -> None:
|
||||
self._sets = sets or {}
|
||||
#: file_id -> extension served by the fake CDN URL.
|
||||
self._extensions = extensions or {}
|
||||
self.get_sticker_set_calls: list[str] = []
|
||||
self.get_file_calls: list[str] = []
|
||||
|
||||
async def get_sticker_set(self, name: str) -> FakeStickerSet:
|
||||
self.get_sticker_set_calls.append(name)
|
||||
try:
|
||||
return self._sets[name]
|
||||
except KeyError:
|
||||
raise BadRequest("Stickerset_invalid") from None
|
||||
|
||||
async def get_file(self, file_id: str) -> FakeFile:
|
||||
self.get_file_calls.append(file_id)
|
||||
extension = self._extensions.get(file_id, "webp")
|
||||
return FakeFile(file_path=f"https://cdn.example/file/{file_id}.{extension}")
|
||||
|
||||
|
||||
class FakeFetcher:
|
||||
"""Returns deterministic bytes and can be told to fail for some URLs."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
payload: bytes = b"sticker-bytes",
|
||||
failures: dict[str, Exception] | None = None,
|
||||
) -> None:
|
||||
self._payload = payload
|
||||
self._failures = failures or {}
|
||||
self.urls: list[str] = []
|
||||
self.max_concurrent = 0
|
||||
self._in_flight = 0
|
||||
|
||||
async def fetch(self, url: str) -> bytes:
|
||||
self.urls.append(url)
|
||||
self._in_flight += 1
|
||||
self.max_concurrent = max(self.max_concurrent, self._in_flight)
|
||||
try:
|
||||
await asyncio.sleep(0)
|
||||
for needle, error in self._failures.items():
|
||||
if needle in url:
|
||||
raise error
|
||||
return self._payload
|
||||
finally:
|
||||
self._in_flight -= 1
|
||||
|
||||
|
||||
async def no_sleep(_delay: float) -> None:
|
||||
"""Drop-in for ``asyncio.sleep`` so retry tests run instantly."""
|
||||
return None
|
||||
|
||||
|
||||
def make_sticker(index: int, **overrides: Any) -> FakeSticker:
|
||||
"""A static sticker with a PNG thumbnail, unless overridden."""
|
||||
defaults: dict[str, Any] = {
|
||||
"file_id": f"file{index}",
|
||||
"file_unique_id": f"uniq{index}",
|
||||
"thumbnail": FakeThumbnail(file_id=f"thumb{index}"),
|
||||
}
|
||||
defaults.update(overrides)
|
||||
return FakeSticker(**defaults)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pack() -> FakeStickerSet:
|
||||
return FakeStickerSet(
|
||||
name="TestPack",
|
||||
title="Test Pack",
|
||||
stickers=[make_sticker(1), make_sticker(2)],
|
||||
thumbnail=FakeThumbnail(file_id="packthumb"),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bot(pack: FakeStickerSet) -> FakeBot:
|
||||
return FakeBot({pack.name: pack})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fetcher() -> FakeFetcher:
|
||||
return FakeFetcher()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config(tmp_path) -> DownloadConfig:
|
||||
return DownloadConfig(output_dir=tmp_path / "downloads")
|
||||
Reference in New Issue
Block a user