import pytest from pathlib import Path from logimage.application.use_cases.generate_puzzles import ( GeneratePuzzlesRequest, GeneratePuzzlesUseCase, ) from tests.fakes.fakes import FakeImageSource, FakeImageConverter, FakePdfExporter def _make_use_case() -> tuple[GeneratePuzzlesUseCase, FakeImageSource, FakeImageConverter, FakePdfExporter]: source = FakeImageSource() converter = FakeImageConverter() exporter = FakePdfExporter() use_case = GeneratePuzzlesUseCase(source, converter, exporter) return use_case, source, converter, exporter def test_generate_single_puzzle_calls_fetch_once() -> None: use_case, source, _, _ = _make_use_case() use_case.execute(GeneratePuzzlesRequest()) assert len(source.fetch_calls) == 1 def test_generate_count_5_calls_fetch_5_times() -> None: use_case, source, _, _ = _make_use_case() use_case.execute(GeneratePuzzlesRequest(count=5)) assert len(source.fetch_calls) == 5 def test_theme_forwarded_to_source() -> None: use_case, source, _, _ = _make_use_case() use_case.execute(GeneratePuzzlesRequest(theme="cats")) assert source.fetch_calls[0] == "cats" def test_no_theme_passes_none_to_source() -> None: use_case, source, _, _ = _make_use_case() use_case.execute(GeneratePuzzlesRequest()) assert source.fetch_calls[0] is None def test_solution_flag_forwarded_to_exporter() -> None: use_case, _, _, exporter = _make_use_case() use_case.execute(GeneratePuzzlesRequest(with_solution=True)) assert exporter.last_with_solution is True def test_output_path_forwarded_to_exporter() -> None: use_case, _, _, exporter = _make_use_case() path = Path("my_output.pdf") use_case.execute(GeneratePuzzlesRequest(output_path=path)) assert exporter.last_path == path def test_difficulty_easy_uses_10x10(monkeypatch: pytest.MonkeyPatch) -> None: source = FakeImageSource() exporter = FakePdfExporter() sizes_used: list[tuple[int, int]] = [] class CapturingConverter(FakeImageConverter): def to_grid(self, image_bytes: bytes, width: int, height: int): # type: ignore[override] sizes_used.append((width, height)) return super().to_grid(image_bytes, width, height) use_case = GeneratePuzzlesUseCase(source, CapturingConverter(), exporter) use_case.execute(GeneratePuzzlesRequest(difficulty="easy")) assert sizes_used[0] == (10, 10) def test_difficulty_hard_uses_20x20(monkeypatch: pytest.MonkeyPatch) -> None: source = FakeImageSource() exporter = FakePdfExporter() sizes_used: list[tuple[int, int]] = [] class CapturingConverter(FakeImageConverter): def to_grid(self, image_bytes: bytes, width: int, height: int): # type: ignore[override] sizes_used.append((width, height)) return super().to_grid(image_bytes, width, height) use_case = GeneratePuzzlesUseCase(source, CapturingConverter(), exporter) use_case.execute(GeneratePuzzlesRequest(difficulty="hard")) assert sizes_used[0] == (20, 20) def test_custom_size_overrides_difficulty(monkeypatch: pytest.MonkeyPatch) -> None: source = FakeImageSource() exporter = FakePdfExporter() sizes_used: list[tuple[int, int]] = [] class CapturingConverter(FakeImageConverter): def to_grid(self, image_bytes: bytes, width: int, height: int): # type: ignore[override] sizes_used.append((width, height)) return super().to_grid(image_bytes, width, height) use_case = GeneratePuzzlesUseCase(source, CapturingConverter(), exporter) use_case.execute(GeneratePuzzlesRequest(difficulty="easy", size=(25, 30))) assert sizes_used[0] == (25, 30) def test_puzzle_title_comes_from_image_source() -> None: source = FakeImageSource(title="Beautiful Cat") exporter = FakePdfExporter() use_case = GeneratePuzzlesUseCase(source, FakeImageConverter(), exporter) use_case.execute(GeneratePuzzlesRequest()) assert exporter.exported_puzzles[0].title == "Beautiful Cat" def test_puzzle_image_bytes_comes_from_image_source() -> None: source = FakeImageSource(content=b"real-image-bytes") exporter = FakePdfExporter() use_case = GeneratePuzzlesUseCase(source, FakeImageConverter(), exporter) use_case.execute(GeneratePuzzlesRequest()) assert exporter.exported_puzzles[0].image_bytes == b"real-image-bytes"