02cd9d519c
Lint & Test / test (push) Successful in 1m56s
- Rename Python package: wled_controller -> ledgrab - Rename env var prefix: WLED_ -> LEDGRAB_ (with auto-migration for old vars) - Rename localStorage key: wled_api_key -> ledgrab_api_key (with migration) - Rename HA integration domain: wled_screen_controller -> ledgrab - Update all imports, build scripts, Docker, installer, config, docs - Remove HA integration (moved to ledgrab-haos-integration repo) - Remove hacs.json (belongs in HA repo now) - Add startup warning for users with old WLED_ env vars - All tests pass (715/715), ruff clean, tsc clean, frontend builds
162 lines
5.3 KiB
Python
162 lines
5.3 KiB
Python
"""Tests for SyncClockStore — CRUD, speed clamping, name uniqueness."""
|
|
|
|
import pytest
|
|
|
|
from ledgrab.storage.sync_clock import SyncClock
|
|
from ledgrab.storage.sync_clock_store import SyncClockStore
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_db) -> SyncClockStore:
|
|
return SyncClockStore(tmp_db)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SyncClock model
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockModel:
|
|
def test_to_dict_round_trip(self, make_sync_clock):
|
|
clock = make_sync_clock(name="RT", speed=2.5, description="test", tags=["a"])
|
|
data = clock.to_dict()
|
|
restored = SyncClock.from_dict(data)
|
|
assert restored.id == clock.id
|
|
assert restored.name == "RT"
|
|
assert restored.speed == 2.5
|
|
assert restored.description == "test"
|
|
assert restored.tags == ["a"]
|
|
|
|
def test_from_dict_defaults(self):
|
|
data = {
|
|
"id": "sc_1",
|
|
"name": "Default",
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
clock = SyncClock.from_dict(data)
|
|
assert clock.speed == 1.0
|
|
assert clock.description is None
|
|
assert clock.tags == []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SyncClockStore CRUD
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockStoreCRUD:
|
|
def test_create_clock(self, store):
|
|
c = store.create_clock(name="Clock A")
|
|
assert c.id.startswith("sc_")
|
|
assert c.name == "Clock A"
|
|
assert c.speed == 1.0
|
|
assert store.count() == 1
|
|
|
|
def test_create_clock_with_options(self, store):
|
|
c = store.create_clock(name="Fast", speed=5.0, description="speedy", tags=["anim"])
|
|
assert c.speed == 5.0
|
|
assert c.description == "speedy"
|
|
assert c.tags == ["anim"]
|
|
|
|
def test_get_clock(self, store):
|
|
created = store.create_clock(name="Get")
|
|
got = store.get_clock(created.id)
|
|
assert got.name == "Get"
|
|
|
|
def test_get_all_clocks(self, store):
|
|
store.create_clock("A")
|
|
store.create_clock("B")
|
|
assert len(store.get_all_clocks()) == 2
|
|
|
|
def test_delete_clock(self, store):
|
|
c = store.create_clock("Del")
|
|
store.delete_clock(c.id)
|
|
assert store.count() == 0
|
|
|
|
def test_delete_not_found(self, store):
|
|
with pytest.raises(ValueError, match="not found"):
|
|
store.delete_clock("nope")
|
|
|
|
def test_update_clock(self, store):
|
|
c = store.create_clock(name="Old", speed=1.0)
|
|
updated = store.update_clock(c.id, name="New", speed=3.0)
|
|
assert updated.name == "New"
|
|
assert updated.speed == 3.0
|
|
|
|
def test_update_clock_partial(self, store):
|
|
c = store.create_clock(name="Keep", speed=2.0, description="orig")
|
|
updated = store.update_clock(c.id, speed=4.0)
|
|
assert updated.name == "Keep"
|
|
assert updated.speed == 4.0
|
|
assert updated.description == "orig"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Speed clamping
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSpeedClamping:
|
|
def test_create_clamps_low(self, store):
|
|
c = store.create_clock(name="Low", speed=0.01)
|
|
assert c.speed == 0.1
|
|
|
|
def test_create_clamps_high(self, store):
|
|
c = store.create_clock(name="High", speed=100.0)
|
|
assert c.speed == 10.0
|
|
|
|
def test_update_clamps_low(self, store):
|
|
c = store.create_clock(name="UL", speed=1.0)
|
|
updated = store.update_clock(c.id, speed=-5.0)
|
|
assert updated.speed == 0.1
|
|
|
|
def test_update_clamps_high(self, store):
|
|
c = store.create_clock(name="UH", speed=1.0)
|
|
updated = store.update_clock(c.id, speed=999.0)
|
|
assert updated.speed == 10.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Name uniqueness
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockNameUniqueness:
|
|
def test_duplicate_name_create(self, store):
|
|
store.create_clock("Same")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.create_clock("Same")
|
|
|
|
def test_duplicate_name_update(self, store):
|
|
store.create_clock("First")
|
|
c2 = store.create_clock("Second")
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
store.update_clock(c2.id, name="First")
|
|
|
|
def test_rename_to_own_name_ok(self, store):
|
|
c = store.create_clock("Self")
|
|
updated = store.update_clock(c.id, name="Self", speed=9.0)
|
|
assert updated.speed == 9.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Persistence
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSyncClockPersistence:
|
|
def test_persist_and_reload(self, tmp_path):
|
|
from ledgrab.storage.database import Database
|
|
|
|
db = Database(tmp_path / "sc_persist.db")
|
|
s1 = SyncClockStore(db)
|
|
c = s1.create_clock(name="Persist", speed=2.5)
|
|
cid = c.id
|
|
|
|
s2 = SyncClockStore(db)
|
|
loaded = s2.get_clock(cid)
|
|
assert loaded.name == "Persist"
|
|
assert loaded.speed == 2.5
|
|
db.close()
|