feat: implement mosaic cover generation logic

Made-with: Cursor
This commit is contained in:
cottongin
2026-04-06 19:21:55 -04:00
parent b2d084cd69
commit 362e0c9b8e
2 changed files with 73 additions and 137 deletions

View File

@@ -1,19 +1,16 @@
import json
import os
from collections import Counter
from datetime import date
from unittest.mock import patch, MagicMock
from unittest.mock import patch
from io import BytesIO
from PIL import Image as PILImage, ImageDraw, ImageFont
from src.cover import (
generate_programmatic_cover,
generate_ai_cover,
generate_mosaic_cover,
generate_cover,
_get_dominant_category,
_truncate_to_width,
_get_font,
CATEGORY_PROMPTS,
)
@@ -46,54 +43,31 @@ def test_programmatic_cover_no_headlines(tmp_path):
assert img.size == (480, 800)
def test_ai_cover_is_portrait(tmp_path):
fake_img = PILImage.new("RGB", (480, 800), color="blue")
buf = BytesIO()
fake_img.save(buf, format="JPEG")
fake_bytes = buf.getvalue()
def test_generate_mosaic_cover_single_image(tmp_path):
# Create a dummy image
img_path = str(tmp_path / "dummy.jpg")
img = PILImage.new("RGB", (1000, 500), color="red")
img.save(img_path)
mock_response = MagicMock()
mock_response.content = fake_bytes
mock_response.raise_for_status = MagicMock()
output_dir = str(tmp_path)
week_start = date(2026, 4, 6)
week_end = date(2026, 4, 12)
headlines = ["Test Headline"]
with patch("src.cover.requests.get", return_value=mock_response):
path = generate_ai_cover(
output_dir=str(tmp_path),
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=["Test Headline"],
categories=["Government"],
)
cover_path = generate_mosaic_cover(output_dir, week_start, week_end, headlines, [img_path])
assert os.path.exists(path)
img = PILImage.open(path)
assert img.format == "JPEG"
assert img.size == (480, 800)
def test_ai_cover_falls_back_to_programmatic(tmp_path):
with patch("src.cover.requests.get", side_effect=Exception("API down")):
path = generate_ai_cover(
output_dir=str(tmp_path),
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=["Test"],
categories=["Government"],
)
assert os.path.exists(path)
img = PILImage.open(path)
assert img.format == "JPEG"
assert img.size == (480, 800)
assert os.path.exists(cover_path)
with PILImage.open(cover_path) as result_img:
assert result_img.size == (480, 800)
def test_generate_cover_dispatches(tmp_path):
with patch("src.cover.generate_ai_cover") as mock_ai:
mock_ai.return_value = "/fake/ai.jpg"
result = generate_cover("ai", str(tmp_path), date(2026, 4, 6),
date(2026, 4, 12), ["A"], ["Government"])
assert result == "/fake/ai.jpg"
mock_ai.assert_called_once()
with patch("src.cover.generate_mosaic_cover") as mock_mosaic:
mock_mosaic.return_value = "/fake/mosaic.jpg"
result = generate_cover("mosaic", str(tmp_path), date(2026, 4, 6),
date(2026, 4, 12), ["A"], ["/x/a.jpg"])
assert result == "/fake/mosaic.jpg"
mock_mosaic.assert_called_once()
with patch("src.cover.generate_programmatic_cover") as mock_prog:
mock_prog.return_value = "/fake/text.jpg"
@@ -103,17 +77,6 @@ def test_generate_cover_dispatches(tmp_path):
mock_prog.assert_called_once()
def test_get_dominant_category():
assert _get_dominant_category(["Government", "Government", "Culture"]) == "Government"
assert _get_dominant_category(["Culture", "Government"]) == "Culture"
assert _get_dominant_category([]) == "Default"
def test_category_prompts_include_massachusetts():
for category, prompt in CATEGORY_PROMPTS.items():
assert "Massachusetts" in prompt, f"Prompt for {category} missing 'Massachusetts'"
def test_truncate_to_width_respects_pixel_budget():
font = _get_font(18)
short = "Short text"