"""Run with: .venv/Scripts/python.exe -B -m unittest test_book_file""" import tempfile import unittest from pathlib import Path from types import SimpleNamespace from unittest.mock import AsyncMock, patch import httpx from fastapi import FastAPI from app.api.books import router from app.core.database import get_db class BookFileTests(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.temp = tempfile.TemporaryDirectory() self.root = Path(self.temp.name) self.file = self.root / "sample.epub" self.content = b"PK\x03\x04original-epub-bytes" self.file.write_bytes(self.content) self.db = SimpleNamespace(get=AsyncMock(return_value=SimpleNamespace(file_path=str(self.file)))) app = FastAPI() app.include_router(router, prefix="/api") async def fake_db(): yield self.db app.dependency_overrides[get_db] = fake_db self.client = httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") self.config = patch("app.api.books.settings", SimpleNamespace(upload_dir=str(self.root))) self.config.start() async def asyncTearDown(self): await self.client.aclose() self.config.stop() self.temp.cleanup() async def test_original_bytes_and_type(self): response = await self.client.get("/api/books/book-id/file") self.assertEqual(response.status_code, 200) self.assertEqual(response.content, self.content) self.assertEqual(response.headers["content-type"], "application/epub+zip") async def test_unknown_book(self): self.db.get.return_value = None self.assertEqual((await self.client.get("/api/books/unknown/file")).status_code, 404) async def test_missing_file(self): self.db.get.return_value.file_path = str(self.root / "missing.epub") self.assertEqual((await self.client.get("/api/books/book-id/file")).status_code, 404) async def test_outside_upload_directory(self): self.db.get.return_value.file_path = str(self.root.parent / "outside.epub") self.assertEqual((await self.client.get("/api/books/book-id/file")).status_code, 404) async def test_non_epub_not_served(self): self.db.get.return_value.file_path = str(self.root / "secrets.txt") self.assertEqual((await self.client.get("/api/books/book-id/file")).status_code, 404)