60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""Item-ID transactional synthesis cursor (A2): no omission, no false coverage."""
|
|
|
|
from rune.orchestration.cursor import SynthesisCursor
|
|
|
|
|
|
def test_commit_records_exact_inputs_and_advances():
|
|
c = SynthesisCursor()
|
|
txn = c.begin(["e1", "e2"])
|
|
c.include(txn, "e1")
|
|
c.include(txn, "e2")
|
|
receipt = c.commit(txn, "out1")
|
|
assert receipt.input_ids == ("e1", "e2")
|
|
assert receipt.output_id == "out1"
|
|
assert receipt.prior_cursor is None
|
|
assert receipt.covered == 2
|
|
assert c.covered() == {"e1", "e2"}
|
|
|
|
|
|
def test_same_input_set_covered_exactly_once():
|
|
c = SynthesisCursor()
|
|
t1 = c.begin(["e1", "e2"])
|
|
c.commit(t1, "out1")
|
|
# A second commit over the same input set must not double-cover them.
|
|
t2 = c.begin(["e1", "e2"])
|
|
c.include(t2, "e1")
|
|
c.include(t2, "e2")
|
|
r2 = c.commit(t2, "out2")
|
|
assert r2.covered == 0 # already covered by the first commit
|
|
assert c.covered() == {"e1", "e2"}
|
|
|
|
|
|
def test_crash_before_commit_does_not_advance():
|
|
c = SynthesisCursor()
|
|
txn = c.begin(["e1"])
|
|
c.include(txn, "e1")
|
|
# Simulate crash: never call commit; start a fresh cursor over the same state.
|
|
assert c.covered() == set()
|
|
assert c.prior_cursor() is None
|
|
|
|
|
|
def test_prior_cursor_links_to_previous_commit():
|
|
c = SynthesisCursor()
|
|
t1 = c.begin(["e1"])
|
|
c.commit(t1, "out1")
|
|
t2 = c.begin(["e2"])
|
|
c.commit(t2, "out2")
|
|
r2 = c.receipts()[-1]
|
|
assert r2.prior_cursor == ("out1",)
|
|
assert len(c.receipts()) == 2
|
|
|
|
|
|
def test_partial_include_is_not_committed():
|
|
c = SynthesisCursor()
|
|
txn = c.begin(["e1", "e2"])
|
|
c.include(txn, "e1")
|
|
# e2 never included; a commit before including everything must not cover it.
|
|
receipt = c.commit(txn, "out1")
|
|
assert receipt.input_ids == ("e1",)
|
|
assert c.covered() == {"e1"}
|