utils/crdt-sync/crdt_sync/tests/test_log.py
Krzysztof kuhy Rudnicki 6154dc09bf Pin pre-commit's ruff to 0.16.7 and satisfy the CPY001 it brings
The three Python packages pinned ruff twice at different versions:
requirements.txt at 0.16.7, .pre-commit-config.yaml at v0.15.2. Only the
older one ever ran, so `select = ["ALL"]` was enforced two minor versions
behind. Measured before aligning: v0.15.2 reports 0 findings, every 0.16.x
reports CPY001 on each file -- 70 crdt-sync, 23 freedays, 71 gatelock, and
no other rule.

Resolved by adding the notice rather than ignoring the rule, so the gate
keeps its teeth.

Two gatelock modules sat at exactly the 250-line cap, so a one-line header
tipped them to 251. Both are split along a real seam rather than shaved:

  _widget_fills.py    colour arithmetic over LockConfig, no tkinter import
  _surfaces_focus.py  selects among existing surfaces, never mutates them

The focus split keeps _surfaces.py's documented containment (it stays the
only module that creates, moves or destroys windows), and the static guard
in test_recovery_invariants.py globs _surfaces*.py, so the new sibling is
covered with no list to extend. widgets.py re-exports the fills helpers,
which keeps gatelock.widgets the single public surface its tests import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kMvSMtsVMB3d2uoZ56pbp
2026-09-12 18:11:24 +02:00

93 lines
3.3 KiB
Python

# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for merge_logs, including its CRDT convergence properties."""
from __future__ import annotations
from typing import TYPE_CHECKING
from crdt_sync import Hlc, Record, merge_logs
if TYPE_CHECKING:
from collections.abc import Callable
from crdt_sync import Log
class TestMergeLogs:
"""Merge logs."""
def test_returns_the_union_of_disjoint_ids(
self, make_hlc: Callable[..., Hlc]
) -> None:
"""Returns the union of disjoint ids."""
local = {"a": Record(id="a", fields={"text": ("a", make_hlc(100))})}
remote = {"b": Record(id="b", fields={"text": ("b", make_hlc(100))})}
assert merge_logs(local, remote) == {**local, **remote}
def test_merges_a_shared_id_field_by_field(
self, make_hlc: Callable[..., Hlc]
) -> None:
"""Merges a shared id field by field."""
local = {"a": Record(id="a", fields={"text": ("old", make_hlc(100))})}
remote = {"a": Record(id="a", fields={"text": ("new", make_hlc(200))})}
merged = merge_logs(local, remote)
assert merged["a"].fields["text"] == ("new", make_hlc(200))
def test_a_delete_on_one_side_survives_the_merge(
self, make_hlc: Callable[..., Hlc]
) -> None:
"""A delete on one side survives the merge."""
local = {
"a": Record(id="a", fields={}, deleted=True, deleted_hlc=make_hlc(200))
}
remote = {"a": Record(id="a", fields={"text": ("still here", make_hlc(100))})}
assert merge_logs(local, remote)["a"].deleted is True
def test_does_not_mutate_either_input(self, make_hlc: Callable[..., Hlc]) -> None:
"""Does not mutate either input."""
local = {"a": Record(id="a", fields={"text": ("a", make_hlc(100))})}
remote = {"b": Record(id="b", fields={"text": ("b", make_hlc(100))})}
local_before = dict(local)
remote_before = dict(remote)
merge_logs(local, remote)
assert local == local_before
assert remote == remote_before
class TestConvergenceProperties:
"""Convergence properties."""
def _sample_logs(self, make_hlc: Callable[..., Hlc]) -> tuple[Log, Log]:
a = {
"shared": Record(
id="shared", fields={"text": ("a-version", make_hlc(100))}
),
"only-in-a": Record(id="only-in-a", fields={"text": ("a", make_hlc(50))}),
}
b = {
"shared": Record(
id="shared", fields={"text": ("b-version", make_hlc(200))}
),
"only-in-b": Record(id="only-in-b", fields={"text": ("b", make_hlc(50))}),
}
return a, b
def test_is_commutative(self, make_hlc: Callable[..., Hlc]) -> None:
"""Is commutative."""
a, b = self._sample_logs(make_hlc)
assert merge_logs(a, b) == merge_logs(b, a)
def test_is_idempotent(self, make_hlc: Callable[..., Hlc]) -> None:
"""Is idempotent."""
a, _ = self._sample_logs(make_hlc)
assert merge_logs(a, a) == a
def test_repeated_merge_of_the_same_remote_is_a_no_op(
self, make_hlc: Callable[..., Hlc]
) -> None:
"""Repeated merge of the same remote is a no op."""
a, b = self._sample_logs(make_hlc)
once = merge_logs(a, b)
twice = merge_logs(once, b)
assert once == twice