from __future__ import annotations from claire.hlc import HLC, HLCGenerator def test_hlc_monotonic_within_same_wall_ms() -> None: """Two ticks in the same millisecond must bump the counter.""" clock = [1_000_000_000_000] gen = HLCGenerator("m1", now_fn=lambda: clock[0]) a = gen.tick() b = gen.tick() assert a < b assert a.wall_ms == b.wall_ms assert b.counter == a.counter + 1 def test_hlc_resets_counter_on_wall_advance() -> None: clock = [1_000_000_000_000] gen = HLCGenerator("m1", now_fn=lambda: clock[0]) gen.tick() gen.tick() clock[0] += 50 later = gen.tick() assert later.counter == 0 assert later.wall_ms == 1_000_000_000_050 def test_hlc_update_pulls_forward_from_remote() -> None: """Receiving an HLC from a peer with a higher wall_ms pulls us forward.""" clock = [1_000_000_000_000] gen = HLCGenerator("m1", now_fn=lambda: clock[0]) remote = HLC(wall_ms=2_000_000_000_000, counter=5, machine_id="m2") new = gen.update(remote) assert new.wall_ms == remote.wall_ms assert new.counter == remote.counter + 1 def test_hlc_encode_decode_roundtrip() -> None: hlc = HLC(wall_ms=1716253199000, counter=42, machine_id="abc-123") assert HLC.decode(hlc.encode()) == hlc def test_hlc_string_ordering_matches_tuple_ordering() -> None: """Critical: HLCs sort the same way as strings as they do as tuples.""" a = HLC(wall_ms=1000, counter=1, machine_id="m1") b = HLC(wall_ms=1000, counter=2, machine_id="m1") c = HLC(wall_ms=1001, counter=0, machine_id="m1") encoded = sorted([c.encode(), b.encode(), a.encode()]) assert encoded == [a.encode(), b.encode(), c.encode()]