From 8ab8260b331eb33334eaf5f7615e9915898ead0e Mon Sep 17 00:00:00 2001 From: Joshua Date: Thu, 17 Sep 2026 16:56:36 -0400 Subject: [PATCH] test: prove configured horizon bounds generation (TEST-001) --- tests/test_lifecycle.py | 55 ++++++++++++++++++++++++++++++++++++--- tests/test_materialize.py | 16 ++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/tests/test_lifecycle.py b/tests/test_lifecycle.py index 3acd258..b81f3f9 100644 --- a/tests/test_lifecycle.py +++ b/tests/test_lifecycle.py @@ -352,6 +352,39 @@ async def test_day_rollover_listener_materializes_ha_local_horizon( ) +async def test_day_rollover_uses_configured_horizon_days(hass, make_entry) -> None: + """The daily run materializes only the configured horizon window.""" + import datetime + + from custom_components.nestquest.dao_instances import QuestInstancesDao + + entry = _wire(make_entry(options={CONF_HORIZON_DAYS: 5}), hass.registry) + assert await async_setup_entry(hass, entry) is True + database = entry.runtime_data.database + + # A definition created AFTER setup has no instances yet (create does not + # materialize); firing the daily listener must generate only the horizon. + child_id = await _seed_daily_child_and_definition( + database, _local_today(hass) + ) + await hass.time_change.fire() + + today = _local_today(hass) + end = (today + datetime.timedelta(days=5)).isoformat() + records = await QuestInstancesDao(database).list_by_date_range( + child_id, today.isoformat(), end + ) + assert len(records) == 6 + + beyond = (today + datetime.timedelta(days=6)).isoformat() + beyond_end = ( + today + datetime.timedelta(days=DEFAULT_HORIZON_DAYS) + ).isoformat() + assert await QuestInstancesDao(database).list_by_date_range( + child_id, beyond, beyond_end + ) == [] + + def test_day_rollover_time_change_tracker_rejects_local_kwarg() -> None: """The fake async_track_time_change mirrors HA 2024.6 (no ``local`` kwarg). @@ -471,11 +504,19 @@ async def test_setup_backfills_configured_horizon_days(hass, make_entry) -> None today = _local_today(hass) end = (today + datetime.timedelta(days=5)).isoformat() - records = await QuestInstancesDao(entry.runtime_data.database).list_by_date_range( - child_id, today.isoformat(), end - ) + records = await QuestInstancesDao( + entry.runtime_data.database + ).list_by_date_range(child_id, today.isoformat(), end) assert len(records) == 6 + beyond = (today + datetime.timedelta(days=6)).isoformat() + beyond_end = ( + today + datetime.timedelta(days=DEFAULT_HORIZON_DAYS) + ).isoformat() + assert await QuestInstancesDao( + entry.runtime_data.database + ).list_by_date_range(child_id, beyond, beyond_end) == [] + def test_configured_horizon_days_validates_and_falls_back() -> None: """The configured horizon is validated; a malformed value uses the default.""" @@ -549,6 +590,14 @@ async def test_regenerate_service_uses_configured_horizon_days( ) assert len(records) == 6 + beyond = (today + datetime.timedelta(days=6)).isoformat() + beyond_end = ( + today + datetime.timedelta(days=DEFAULT_HORIZON_DAYS) + ).isoformat() + assert await QuestInstancesDao(database).list_by_date_range( + child_id, beyond, beyond_end + ) == [] + async def test_unload_deregisters_regenerate_service(hass, make_entry) -> None: """Unload removes the ``regenerate`` service so no stale entry leaks.""" diff --git a/tests/test_materialize.py b/tests/test_materialize.py index 66c9ad3..b124369 100644 --- a/tests/test_materialize.py +++ b/tests/test_materialize.py @@ -7,6 +7,7 @@ import datetime import pytest from custom_components.nestquest.dao_children import ChildrenDao +from custom_components.nestquest.const import DEFAULT_HORIZON_DAYS from custom_components.nestquest.dao_instances import ( CompletionEventsDao, QuestInstancesDao, @@ -1142,6 +1143,14 @@ def test_regenerate_for_definition_respects_horizon_days(tmp_path) -> None: child.id, start_iso, horizon_end.isoformat() ) assert len(records) == 6 + + # The window is BOUNDED: nothing must exist at day 6 or later (a + # hard-coded 14-day default would still emit rows there). + beyond = (today + datetime.timedelta(days=6)).isoformat() + beyond_end = ( + today + datetime.timedelta(days=DEFAULT_HORIZON_DAYS) + ).isoformat() + assert await dao.list_by_date_range(child.id, beyond, beyond_end) == [] return None _with_db(tmp_path, "regenerate-def-horizon.db")(_body) @@ -1172,6 +1181,13 @@ def test_regenerate_for_child_respects_horizon_days(tmp_path) -> None: child.id, start_iso, horizon_end.isoformat() ) assert len(records) == 6 + + # Bounded window: nothing must exist at day 6 or later. + beyond = (today + datetime.timedelta(days=6)).isoformat() + beyond_end = ( + today + datetime.timedelta(days=DEFAULT_HORIZON_DAYS) + ).isoformat() + assert await dao.list_by_date_range(child.id, beyond, beyond_end) == [] return None _with_db(tmp_path, "regenerate-child-horizon.db")(_body)