mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 22:47:14 +01:00
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
166 lines
6.6 KiB
Python
166 lines
6.6 KiB
Python
# Copyright (c) 2026 Krzysztof Rudnicki
|
|
"""Tests for Record, merge_field, and merge_record."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
from crdt_sync import Hlc, Record, merge_field, merge_record
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
|
|
class TestMergeField:
|
|
"""Merge field."""
|
|
|
|
def test_greater_hlc_wins(self, make_hlc: Callable[..., Hlc]) -> None:
|
|
"""Greater HLC wins."""
|
|
older = ("a", make_hlc(100))
|
|
newer = ("b", make_hlc(200))
|
|
assert merge_field(older, newer) == newer
|
|
assert merge_field(newer, older) == newer
|
|
|
|
def test_equal_hlc_keeps_the_first_argument(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Equal HLC keeps the first argument."""
|
|
clock = make_hlc(100)
|
|
a = ("a", clock)
|
|
b = ("a", clock)
|
|
assert merge_field(a, b) == a
|
|
|
|
|
|
class TestMergeRecord:
|
|
"""Merge record."""
|
|
|
|
def test_raises_when_ids_differ(self) -> None:
|
|
"""Raises when ids differ."""
|
|
a = Record(id="a", fields={})
|
|
b = Record(id="b", fields={})
|
|
with pytest.raises(ValueError, match="different ids"):
|
|
merge_record(a, b)
|
|
|
|
def test_merges_disjoint_fields(self, make_hlc: Callable[..., Hlc]) -> None:
|
|
"""Merges disjoint fields."""
|
|
a = Record(id="x", fields={"text": ("hello", make_hlc(100))})
|
|
b = Record(id="x", fields={"priority": ("high", make_hlc(50))})
|
|
merged = merge_record(a, b)
|
|
assert merged.fields == {
|
|
"text": ("hello", make_hlc(100)),
|
|
"priority": ("high", make_hlc(50)),
|
|
}
|
|
|
|
def test_shared_field_keeps_the_later_write(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Shared field keeps the later write."""
|
|
a = Record(id="x", fields={"text": ("old", make_hlc(100))})
|
|
b = Record(id="x", fields={"text": ("new", make_hlc(200))})
|
|
merged = merge_record(a, b)
|
|
assert merged.fields["text"] == ("new", make_hlc(200))
|
|
|
|
def test_delete_is_sticky_against_an_older_non_deleted_copy(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Delete is sticky against an older non deleted copy."""
|
|
deleted = Record(id="x", fields={}, deleted=True, deleted_hlc=make_hlc(200))
|
|
stale = Record(id="x", fields={"text": ("resurrected", make_hlc(100))})
|
|
assert merge_record(deleted, stale).deleted is True
|
|
assert merge_record(stale, deleted).deleted is True
|
|
|
|
def test_neither_side_deleted_stays_not_deleted(self) -> None:
|
|
"""Neither side deleted stays not deleted."""
|
|
a = Record(id="x", fields={})
|
|
b = Record(id="x", fields={})
|
|
merged = merge_record(a, b)
|
|
assert merged.deleted is False
|
|
assert merged.deleted_hlc is None
|
|
|
|
def test_both_sides_deleted_keeps_the_later_delete_clock(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Both sides deleted keeps the later delete clock."""
|
|
a = Record(id="x", fields={}, deleted=True, deleted_hlc=make_hlc(100))
|
|
b = Record(id="x", fields={}, deleted=True, deleted_hlc=make_hlc(200))
|
|
merged = merge_record(a, b)
|
|
assert merged.deleted_hlc == make_hlc(200)
|
|
|
|
def test_both_deleted_but_one_side_missing_a_clock_keeps_the_other(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Both deleted but one side missing a clock keeps the other."""
|
|
a = Record(id="x", fields={}, deleted=True, deleted_hlc=None)
|
|
b = Record(id="x", fields={}, deleted=True, deleted_hlc=make_hlc(200))
|
|
assert merge_record(a, b).deleted_hlc == make_hlc(200)
|
|
# Swapping the operands is the property under test: merge_record
|
|
# must give the same answer either way round.
|
|
# pylint: disable-next=arguments-out-of-order
|
|
assert merge_record(b, a).deleted_hlc == make_hlc(200)
|
|
|
|
def test_is_commutative(self, make_hlc: Callable[..., Hlc]) -> None:
|
|
"""Is commutative."""
|
|
record_a = Record(id="x", fields={"text": ("a", make_hlc(100))})
|
|
record_b = Record(
|
|
id="x", fields={"text": ("b", make_hlc(200)), "extra": ("e", make_hlc(1))}
|
|
)
|
|
assert merge_record(record_a, record_b) == merge_record(record_b, record_a)
|
|
|
|
def test_is_idempotent(self, make_hlc: Callable[..., Hlc]) -> None:
|
|
"""Is idempotent."""
|
|
record = Record(id="x", fields={"text": ("a", make_hlc(100))})
|
|
assert merge_record(record, record) == record
|
|
|
|
|
|
class TestRecordDictRoundTrip:
|
|
"""Record dict round trip."""
|
|
|
|
def test_round_trips_a_record_with_fields(
|
|
self, make_hlc: Callable[..., Hlc]
|
|
) -> None:
|
|
"""Round trips a record with fields."""
|
|
record = Record(id="x", fields={"text": ("hello", make_hlc(100, node_id="pc"))})
|
|
assert Record.from_dict(record.to_dict()) == record
|
|
|
|
def test_round_trips_a_deleted_record(self, make_hlc: Callable[..., Hlc]) -> None:
|
|
"""Round trips a deleted record."""
|
|
record = Record(id="x", fields={}, deleted=True, deleted_hlc=make_hlc(200))
|
|
assert Record.from_dict(record.to_dict()) == record
|
|
|
|
def test_round_trips_a_record_with_no_delete_clock(self) -> None:
|
|
"""Round trips a record with no delete clock."""
|
|
record = Record(id="x", fields={}, deleted=False, deleted_hlc=None)
|
|
assert Record.from_dict(record.to_dict()) == record
|
|
|
|
|
|
class TestCrossLanguageWireFormat:
|
|
"""Pins the exact wire shape shared with crdt_sync_dart's Record.
|
|
|
|
Values chosen here are duplicated verbatim in crdt_sync_dart's
|
|
`test/record_test.dart` (see its ``TestCrossLanguageWireFormat``
|
|
group). If this test and that one both pass, the two languages agree
|
|
on the wire format; if only one changes, the two suites diverge and
|
|
at least one of them fails -- catching exactly the kind of
|
|
key-naming mismatch (``deleted_hlc`` vs ``deletedHlc``) that neither
|
|
language's own round-trip test can see on its own.
|
|
"""
|
|
|
|
def test_matches_the_fixture_shared_with_the_dart_package(self) -> None:
|
|
"""Matches the fixture shared with the dart package."""
|
|
record = Record(
|
|
id="abc123",
|
|
fields={"text": ("hello", Hlc(wall_time_ms=100, counter=0, node_id="pc"))},
|
|
deleted=True,
|
|
deleted_hlc=Hlc(wall_time_ms=1000, counter=0, node_id="node-a"),
|
|
)
|
|
expected = {
|
|
"id": "abc123",
|
|
"fields": {"text": ["hello", "1970-01-01T00:00:00.100Z-0000-pc"]},
|
|
"deleted": True,
|
|
"deleted_hlc": "1970-01-01T00:00:01.000Z-0000-node-a",
|
|
}
|
|
assert record.to_dict() == expected
|
|
assert Record.from_dict(expected) == record
|