Group 7: tests — 94 passing in 0.57s (53/53 + 9.4 deferred)

Test infrastructure:
- Add `pytest-homeassistant-custom-component` (PHACC) as a `test`
  dependency group. PHACC ships `hass`, `enable_custom_integrations`,
  `MockConfigEntry`, and friends without needing to clone HA core as a
  sibling directory. Modernizes the test setup from upstream's
  `setup-symlinks` pattern.
- conftest.py: add `auto_enable_custom_integrations` autouse fixture
  so HA discovers the integration under `custom_components/` during
  tests. Keep the upstream template-deprecation no-op.
- Import paths: all tests now import from `custom_components.adaptive_lighting`
  (not `homeassistant.components.adaptive_lighting`) and from
  `pytest_homeassistant_custom_component.common` (not `tests.common`).

New tests (groups 7.2-7.16):
- tests/test_color_and_brightness.py (16 tests): TestBrightnessCurve
  asserts min-before-sunrise, midpoint-at-event, max-during-day, sunset
  ramp symmetry. TestColorTempCurve verifies the same shape applies to
  K. TestSunPosition checks the synthetic +1/-1/0 derivation.
  TestTanhDayCurveDirect exercises the helper directly.
- tests/test_config_flow.py (12 tests): six sections in order, each
  section contains only its specified fields, conditional visibility
  of send_split_delay, default sun entities, strict-typed entity
  selectors, NumberSelector slider/box configs, BooleanSelector for
  every flag, full user→create-entry flow, YAML-managed entry aborts
  with `yaml_managed` reason, options flow renders the sectioned schema.
- tests/test_init.py (6 tests): successful setup on current version,
  stale version raises ConfigEntryError via async_migrate_entry,
  unload is clean, tombstone removes orphan sleep entity + logs INFO,
  tombstone is idempotent, tombstone respects config_entry ownership.

Source modernizations driven by the tests:
- __init__.py: add `async_migrate_entry` that surfaces the
  "incompatible — delete and recreate" message and sets the entry to
  MIGRATION_ERROR. Removed direct `ConfigEntryError` from
  `async_setup_entry` (HA routes version mismatches through the
  migration handler now).
- switch.py: removed upstream's YAML-managed-entry auto-remove hack.
  YAML profiles now load normally and the options flow handles the
  "you must edit configuration.yaml" message (spec R7).

Existing tests updated to PHACC paths: test_adaptation_utils.py
(38 tests), test_hass_utils.py (22 tests). Both pass without
modification beyond the import fix.

Deleted: tests/test_switch.py (2,999 LOC of upstream tests, most
covering sleep mode / take-over-control / manual-control state
machines that no longer exist; CDiT-specific switch tests deferred
to a follow-up change).

Result: `uv run --group test pytest tests/` → 94 passed in 0.57s.

Deferred from this change:
- 4.3: manual UI test that toggling a field and saving reloads cleanly
  (requires a real HA instance, can't be done from CLI).
- 9.4: GitHub repo description / topics update (do via `gh repo edit`
  outside the change scope).

openspec status: 4/4 artifacts complete; strict-validate green.
This commit is contained in:
Casey 2026-05-16 15:11:49 +02:00
commit 03d2748cd4
12 changed files with 1906 additions and 3542 deletions

View file

@ -98,18 +98,25 @@ def _remove_orphan_sleep_entities(
registry.async_remove(entity_id)
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Reject older config-entry versions with a friendly recreate message.
Spec R8 + design D4: this fork deliberately does not migrate upstream
entries. Define a migration handler so HA routes version mismatches
here (instead of logging the generic "Migration handler not found")
and surface a `ConfigEntryError` whose message tells the user what to
do.
"""
msg = (
f"Adaptive Lighting v{CONFIG_ENTRY_VERSION} (CDiT fork) is incompatible "
f"with the existing config entry (version {config_entry.version}). "
"Delete the entry and recreate it from Settings → Devices & Services."
)
raise ConfigEntryError(msg)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up the component."""
# Spec R8 + design D4: reject entries from older, incompatible versions
# with a clear "recreate this entry" message rather than silently migrating.
if config_entry.version < CONFIG_ENTRY_VERSION:
msg = (
f"Adaptive Lighting v{CONFIG_ENTRY_VERSION} (CDiT fork) is incompatible "
f"with the existing config entry (version {config_entry.version}). "
"Delete and recreate the entry from Settings → Devices & Services."
)
raise ConfigEntryError(msg)
_remove_orphan_sleep_entities(hass, config_entry)
data = hass.data.setdefault(DOMAIN, {})

View file

@ -344,17 +344,8 @@ async def async_setup_entry( # noqa: PLR0915
data,
config_entry,
)
if ( # Skip deleted YAML config entries or first time YAML config entries
config_entry.source == SOURCE_IMPORT
and config_entry.unique_id not in data.get("__yaml__", set())
):
_LOGGER.warning(
"Deleting AdaptiveLighting switch '%s' because YAML"
" defined switch has been removed from YAML configuration",
config_entry.unique_id,
)
await hass.config_entries.async_remove(config_entry.entry_id)
return
# CDiT fork: YAML-managed entries load normally; their options dialog
# aborts via the `yaml_managed` reason (spec R7).
if (manager := data.get(ATTR_ADAPTIVE_LIGHTING_MANAGER)) is None:
manager = AdaptiveLightingManager(hass)