mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
"""Pure operational-store rules independent of the HA WebSocket harness."""
|
|
import pytest
|
|
|
|
from custom_components.houseplan.virtual_lights import (
|
|
async_reconcile_virtual_lights,
|
|
async_toggle_virtual_light,
|
|
async_virtual_light_snapshot,
|
|
eligible_virtual_light_ids,
|
|
)
|
|
|
|
|
|
class FakeStore:
|
|
def __init__(self, data=None):
|
|
self.data = data
|
|
self.writes = []
|
|
|
|
async def async_load(self):
|
|
return self.data
|
|
|
|
async def async_save(self, data):
|
|
self.data = data
|
|
self.writes.append(data)
|
|
|
|
|
|
def _config(*markers):
|
|
return {"spaces": [], "markers": list(markers), "settings": {}}
|
|
|
|
|
|
def _manual(marker_id, **extra):
|
|
return {
|
|
"id": marker_id, "binding": "virtual", "is_light": True,
|
|
"tap_action": "toggle", **extra,
|
|
}
|
|
|
|
|
|
def test_eligibility_is_the_exact_triple_and_hidden_is_not_lifecycle():
|
|
config = _config(
|
|
_manual("eligible", hidden=True),
|
|
_manual("wrong-action", tap_action="info"),
|
|
_manual("wrong-role", is_light=False),
|
|
_manual("removed", removed=True),
|
|
{"id": "ha", "binding": "entity:light.lamp", "is_light": True, "tap_action": "toggle"},
|
|
)
|
|
assert eligible_virtual_light_ids(config) == {"eligible"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_revision_gap_fails_safe_on_and_known_transition_preserves_only_eligible():
|
|
store = FakeStore({"rev": 5, "config_rev": 2, "off": ["keep", "drop"]})
|
|
gap = await async_virtual_light_snapshot(store, _config(_manual("keep")), 4)
|
|
assert gap == {"rev": 6, "config_rev": 4, "off": []}
|
|
|
|
store = FakeStore({"rev": 8, "config_rev": 4, "off": ["keep", "drop"]})
|
|
carried = await async_reconcile_virtual_lights(
|
|
store,
|
|
_config(_manual("keep", hidden=True), _manual("drop", is_light=False)),
|
|
5,
|
|
previous_config_rev=4,
|
|
)
|
|
assert carried == {"rev": 9, "config_rev": 5, "off": ["keep"]}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_toggle_accepts_only_an_id_and_inverts_server_current_state():
|
|
store = FakeStore()
|
|
config = _config(_manual("lamp"))
|
|
first = await async_toggle_virtual_light(store, config, 1, "lamp")
|
|
second = await async_toggle_virtual_light(store, config, 1, "lamp")
|
|
assert first == {"marker_id": "lamp", "on": False, "rev": 1}
|
|
assert second == {"marker_id": "lamp", "on": True, "rev": 2}
|
|
assert await async_toggle_virtual_light(store, config, 1, "missing") is None
|