"""Tests for the output-target response-builder registry. Locks in the safety net that replaced the previous silent ``LedOutputTargetResponse(defaults)`` fallback in ``output_targets._target_to_response``. """ from __future__ import annotations import pytest from ledgrab.api.routes import output_targets from ledgrab.api.routes.output_targets import ( _assert_target_response_coverage, _target_to_response, _TARGET_RESPONSE_BUILDERS, ) from ledgrab.storage.ha_light_output_target import HALightOutputTarget from ledgrab.storage.wled_output_target import WledOutputTarget from ledgrab.storage.z2m_light_output_target import Z2MLightOutputTarget EXPECTED_TARGET_CLASSES = {WledOutputTarget, HALightOutputTarget, Z2MLightOutputTarget} def test_registry_covers_every_known_target_subclass(): assert set(_TARGET_RESPONSE_BUILDERS.keys()) == EXPECTED_TARGET_CLASSES def test_every_registered_builder_is_callable(): for cls, builder in _TARGET_RESPONSE_BUILDERS.items(): assert callable(builder), f"builder for {cls.__name__} is not callable" def test_unregistered_target_class_raises_in_target_to_response(): """Reaching ``_target_to_response`` with an unmapped class raises loudly instead of silently returning a malformed LedOutputTargetResponse. """ class _RogueTarget: id = "tgt_rogue" name = "rogue" with pytest.raises(RuntimeError, match="No response builder"): _target_to_response(_RogueTarget()) def test_coverage_assertion_raises_on_drift(monkeypatch): """Removing a builder from the registry makes the import-time check fail.""" pruned = { cls: builder for cls, builder in _TARGET_RESPONSE_BUILDERS.items() if cls is not WledOutputTarget } monkeypatch.setattr(output_targets, "_TARGET_RESPONSE_BUILDERS", pruned) with pytest.raises(RuntimeError, match="WledOutputTarget"): _assert_target_response_coverage() def test_coverage_assertion_raises_on_extra_entry(monkeypatch): """An entry keyed by an unknown class is also caught.""" class _RogueTargetClass: pass extended = {**_TARGET_RESPONSE_BUILDERS, _RogueTargetClass: lambda t: None} monkeypatch.setattr(output_targets, "_TARGET_RESPONSE_BUILDERS", extended) with pytest.raises(RuntimeError, match="_RogueTargetClass"): _assert_target_response_coverage()