diff --git a/tests/test_service.py b/tests/test_service.py index fe764c50..5b0df30e 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -209,6 +209,68 @@ def _location( ) +@pytest.mark.parametrize( + ("kind", "historical_ids"), + (("briefing", ["historical-verbatim"]), ("forecast", ["historical-verbatim", "historical-summary"])), +) +def test_build_payload_serializes_article_groups_consistently( + tmp_path: Path, + kind: str, + historical_ids: list[str], +) -> None: + now = pendulum.datetime(2026, 7, 13, 8, tz="Asia/Shanghai") + + def article(identifier: str, *, is_verbatim: bool = False) -> Article: + return Article( + id=identifier, + source_id="feed", + source_name=f"Publisher {identifier}", + title=f"Title {identifier}", + url=f"https://example.invalid/{identifier}", + published_at=now.add(minutes=len(identifier)), + content=f"Content {identifier}", + is_verbatim=is_verbatim, + ) + + def expected(item: Article) -> dict[str, object]: + return { + "source_id": item.id, + "publisher": item.source_name, + "title": item.title, + "url": item.url, + "published_at": item.published_at.isoformat(), + "content": item.content, + "verbatim": item.is_verbatim, + } + + new = article("new") + deferred = article("deferred") + historical_verbatim = article("historical-verbatim", is_verbatim=True) + historical_summary = article("historical-summary") + historical = (historical_verbatim, historical_summary) + + with SQLiteStateStore(tmp_path / f"{kind}.sqlite3") as state: + service = object.__new__(BriefingService) + service._settings = _TestSettings(timezone=pendulum.timezone("Asia/Shanghai")) + service._location = _location() + service._state = state + payload = service._build_payload( + kind, + now, + None, + (new,), + (deferred,), + historical, + (), + (), + (), + ) + + assert payload["new_articles"] == [expected(new)] + assert payload["deferred_articles"] == [expected(deferred)] + assert payload["historical_articles"] == [expected(item) for item in historical if item.id in historical_ids] + + @pytest.mark.parametrize( ("location", "expected_scope"), ( diff --git a/weather_briefing/service.py b/weather_briefing/service.py index 570bf870..e37cf572 100644 --- a/weather_briefing/service.py +++ b/weather_briefing/service.py @@ -30,6 +30,18 @@ _LOGGER = logging.getLogger("weather_briefing.service") +def _serialize_article(article: Article) -> dict[str, object]: + return { + "source_id": article.id, + "publisher": article.source_name, + "title": article.title, + "url": article.url, + "published_at": article.published_at.isoformat(), + "content": article.content, + "verbatim": article.is_verbatim, + } + + class BriefingSettings(Protocol): """Expose the settings required by briefing orchestration.""" @@ -462,40 +474,10 @@ def _build_payload( "forecast_date": str(forecast_date or now.in_timezone(self._settings.timezone).date()), "region": self._location.name, "location_scope": location_scope, - "new_articles": [ - { - "source_id": article.id, - "publisher": article.source_name, - "title": article.title, - "url": article.url, - "published_at": article.published_at.isoformat(), - "content": article.content, - "verbatim": article.is_verbatim, - } - for article in articles - ], - "deferred_articles": [ - { - "source_id": article.id, - "publisher": article.source_name, - "title": article.title, - "url": article.url, - "published_at": article.published_at.isoformat(), - "content": article.content, - "verbatim": article.is_verbatim, - } - for article in deferred_articles - ], + "new_articles": [_serialize_article(article) for article in articles], + "deferred_articles": [_serialize_article(article) for article in deferred_articles], "historical_articles": [ - { - "source_id": article.id, - "publisher": article.source_name, - "title": article.title, - "url": article.url, - "published_at": article.published_at.isoformat(), - "content": article.content, - "verbatim": article.is_verbatim, - } + _serialize_article(article) for article in historical_articles if kind == "forecast" or article.is_verbatim ],