"""Config snapshot unified diff (GetConfig history).""" from __future__ import annotations from datetime import UTC, datetime, timedelta from shelly_manager.core.config_snapshot_diff import ( pick_older_newer, settings_unified_diff_text, sort_snapshots_chronologically, ) from shelly_manager.core.models import ConfigSnapshot def _snap( *, sid: str, created: datetime, label: str, settings: dict, ) -> ConfigSnapshot: return ConfigSnapshot( id=sid, device_id="DEV", created_at=created, label=label, settings=settings, ) def test_sort_snapshots_chronologically_oldest_first() -> None: t0 = datetime(2026, 3, 20, 0, 37, tzinfo=UTC) t1 = datetime(2026, 3, 20, 0, 42, tzinfo=UTC) a = _snap(sid="a", created=t1, label="newer", settings={}) b = _snap(sid="b", created=t0, label="older", settings={}) out = sort_snapshots_chronologically([a, b]) assert [x.label for x in out] == ["older", "newer"] def test_pick_older_newer_swaps_when_user_picks_newer_as_a() -> None: """Oldest-first list: index 0 older, index 1 newer — if user picks A=1 B=0, still get older→newer.""" t0 = datetime(2026, 3, 20, 0, 37, tzinfo=UTC) t1 = datetime(2026, 3, 20, 0, 42, tzinfo=UTC) snaps = [ _snap(sid="b", created=t0, label="older", settings={"x": 1}), _snap(sid="a", created=t1, label="newer", settings={"x": 2}), ] older, newer = pick_older_newer(snaps, 1, 0) assert older.label == "older" assert newer.label == "newer" def test_settings_unified_diff_text_has_line_separated_structure() -> None: """Regression: diff must contain newlines so each +/- line is separate (not one wrapped blob).""" old = {"ble": {"enable": True}} new = {"ble": {"enable": False}} text = settings_unified_diff_text(old, new, fromfile="older/settings.json", tofile="newer/settings.json") assert text.count("\n") >= 4 lines = text.splitlines() assert lines[0].startswith("--- ") assert lines[1].startswith("+++ ") assert any(line.startswith("@@") for line in lines) # Every content/hunk line must be its own line (no embedded @@ mid-line) for line in lines: assert "\n" not in line minus_lines = [ln for ln in lines if ln.startswith("-") and not ln.startswith("---")] plus_lines = [ln for ln in lines if ln.startswith("+") and not ln.startswith("+++")] assert minus_lines assert plus_lines def test_settings_unified_diff_identical_empty() -> None: cfg = {"a": 1} assert settings_unified_diff_text(cfg, cfg) == "" def test_pick_older_newer_same_timestamp_tie_break() -> None: t = datetime(2026, 3, 20, 12, 0, tzinfo=UTC) s1 = _snap(sid="aaa", created=t, label="first", settings={}) s2 = _snap(sid="zzz", created=t, label="second", settings={}) snaps = sort_snapshots_chronologically([s2, s1]) older, newer = pick_older_newer(snaps, 0, 1) assert older.id == "aaa" assert newer.id == "zzz"