mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 20:27:15 +01:00
pylint scored the suite at 8.58/10, and 277 of the ~300 findings were missing docstrings -- every one of them in crdt_sync/tests/, none in library code. ruff exempts tests from the docstring rules, so the two linters disagreed and the score sat well below the bar. Rather than silence pylint to match ruff, every test class, test function and stub method now says what it pins. Stub arguments that exist only to match a real signature are underscore-prefixed, which is the documented way to say "deliberately unused" and clears the unused-argument findings too. No behaviour change: 259 tests, still 100% branch coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCucBhUkHBBHHbsY7bSdGV
162 lines
6.4 KiB
Python
162 lines
6.4 KiB
Python
"""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)
|
|
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
|