"""Tests for SyncClockStore — CRUD, speed clamping, name uniqueness.""" import pytest from wled_controller.storage.sync_clock import SyncClock from wled_controller.storage.sync_clock_store import SyncClockStore @pytest.fixture def store(tmp_path) -> SyncClockStore: return SyncClockStore(str(tmp_path / "sync_clocks.json")) # --------------------------------------------------------------------------- # 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): path = str(tmp_path / "sc_persist.json") s1 = SyncClockStore(path) c = s1.create_clock(name="Persist", speed=2.5) cid = c.id s2 = SyncClockStore(path) loaded = s2.get_clock(cid) assert loaded.name == "Persist" assert loaded.speed == 2.5