From ebe05e011e9186f287a18a5081dacd10b7463d8c Mon Sep 17 00:00:00 2001 From: Tony Burns Date: Fri, 2 Jan 2026 17:44:50 -0500 Subject: [PATCH] test: add edge case coverage for factories and equality Add tests for: - Duplicate keys behavior in from_records (last-wins) - Empty file handling with key parameter in from_file - Custom default value in Table.get() - Equality with different auto_reload after external changes - Transaction equality with different write sequences --- tests/unit/test_factories.py | 20 ++++++++++++++++++++ tests/unit/test_table.py | 23 +++++++++++++++++++++++ tests/unit/test_transaction.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/tests/unit/test_factories.py b/tests/unit/test_factories.py index 7dfc559..be204e3 100644 --- a/tests/unit/test_factories.py +++ b/tests/unit/test_factories.py @@ -60,6 +60,19 @@ def test_compound_key(self, tmp_path: "Path") -> None: assert table.count() == 2 assert table.get(("acme", 1)) == {"org": "acme", "id": 1, "name": "alice"} + def test_duplicate_keys_last_wins(self, tmp_path: "Path") -> None: + records = [ + {"id": "alice", "role": "admin"}, + {"id": "alice", "role": "user"}, # Duplicate key, different value + ] + table = Table.from_records( + tmp_path / "test.jsonlt", + records, + key="id", + ) + assert table.count() == 1 + assert table.get("alice") == {"id": "alice", "role": "user"} + def test_file_has_header(self, tmp_path: "Path") -> None: table = Table.from_records( tmp_path / "test.jsonlt", @@ -296,6 +309,13 @@ def test_max_file_size_exceeded(self, tmp_path: "Path") -> None: with pytest.raises(LimitError, match="file size"): _ = Table.from_file(path, max_file_size=10) # Very small limit + def test_empty_file_with_key(self, tmp_path: "Path") -> None: + path = tmp_path / "test.jsonlt" + _ = path.write_bytes(b"") # 0-byte file + + table = Table.from_file(path, key="id") + assert table.count() == 0 + class TestFactoryIntegration: def test_roundtrip_from_records_to_from_file(self, tmp_path: "Path") -> None: diff --git a/tests/unit/test_table.py b/tests/unit/test_table.py index 7fba922..d06e9d1 100644 --- a/tests/unit/test_table.py +++ b/tests/unit/test_table.py @@ -1283,6 +1283,14 @@ def test_getitem_missing_key_raises_keyerror( assert exc_info.value.args[0] == "nonexistent" + def test_get_with_custom_default(self, make_table: "Callable[..., Table]") -> None: + table = make_table() + default: JSONObject = {"id": "default", "role": "none"} + + result = table.get("nonexistent", default) + + assert result == default + def test_setitem_with_matching_key( self, make_table: "Callable[..., Table]" ) -> None: @@ -1536,3 +1544,18 @@ def test_table_is_not_hashable(self, make_table: "Callable[..., Table]") -> None with pytest.raises(TypeError, match="unhashable type"): _ = hash(table) + + def test_eq_with_different_auto_reload_after_external_change( + self, tmp_path: "Path" + ) -> None: + table_path = tmp_path / "test.jsonlt" + _ = table_path.write_text('{"id": "alice", "v": 1}\n') + + table1 = Table(table_path, key="id", auto_reload=True) + table2 = Table(table_path, key="id", auto_reload=False) + + # Wait a bit to ensure mtime changes + time.sleep(0.01) + _ = table_path.write_text('{"id": "alice", "v": 2}\n') + + assert table1 != table2 diff --git a/tests/unit/test_transaction.py b/tests/unit/test_transaction.py index e02f187..439e046 100644 --- a/tests/unit/test_transaction.py +++ b/tests/unit/test_transaction.py @@ -1425,6 +1425,34 @@ def test_finalized_vs_active_not_equal(self, tmp_path: "Path") -> None: finally: tx2.abort() + def test_eq_same_table_different_writes(self, tmp_path: "Path") -> None: + """Two transactions from same table with different writes are unequal. + + Verifies that sequential transactions from the same table with different + write sequences have different snapshots and compare as unequal. + """ + path = tmp_path / "test.jsonlt" + _ = path.write_text('{"id": "alice", "v": 1}\n') + + table = Table(path, key="id") + + # First transaction: add bob + tx1 = table.transaction() + tx1.put({"id": "bob", "v": 2}) + tx1.commit() + + # Second transaction: add carol (different write) + tx2 = table.transaction() + tx2.put({"id": "carol", "v": 3}) + + try: + # tx1 is committed (has alice+bob in snapshot) + # tx2 is active (has alice+bob+carol in snapshot) + # They differ in both finalized status and snapshot content + assert tx1 != tx2 + finally: + tx2.abort() + def test_transaction_is_not_hashable( self, make_table: "Callable[..., Table]" ) -> None: