"""CLI entrypoint tests: `python app.py --cli --output `. Run as a real subprocess (not in-process) so argparse, exit codes and stdout behavior are tested exactly as a user would invoke them. """ import os import sys import zipfile import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[1] FIXTURE_EBOOK = ROOT / "test_book.epub" def _run_cli(*args): env = dict(os.environ) return subprocess.run( [sys.executable, str(ROOT / "app.py"), *args], capture_output=True, text=True, timeout=120, env=env, cwd=str(ROOT), ) def test_cli_convert_success(tmp_path): out_dir = tmp_path / "out" proc = _run_cli("--cli", str(FIXTURE_EBOOK), "--output", str(out_dir)) assert proc.returncode == 0, proc.stderr assert "Saved:" in proc.stdout pdfs = list(out_dir.glob("*.pdf")) assert len(pdfs) == 1 assert pdfs[0].stat().st_size > 1024 assert pdfs[0].read_bytes()[:4] == b"%PDF" def test_cli_missing_file_exits_2(tmp_path): proc = _run_cli("--cli", str(tmp_path / "nope.epub"), "--output", str(tmp_path)) assert proc.returncode == 2 assert "not found" in proc.stdout def test_cli_corrupt_epub_exits_1(tmp_path): bad = tmp_path / "bad.epub" bad.write_bytes(b"not a zip") proc = _run_cli("--cli", str(bad), "--output", str(tmp_path)) assert proc.returncode == 1 assert "error:" in proc.stdout