Improve test suite

Improves the existing test suite by splitting the single test file into multiple files.

Also adds the ability for other people to use the tests with some example data.
This commit is contained in:
Golumpa 2026-07-15 17:30:19 +01:00
parent 60eef77dd2
commit dd07335d39
13 changed files with 1447 additions and 1046 deletions

View file

@ -0,0 +1,153 @@
from tests.support import * # noqa: F401,F403
class UidCompatibilityTests(unittest.TestCase):
def test_uid_source_matches_committed_network_fixture(self):
fixture = load_network_fixture()
rows = annotate_groups(fixture_session().build_rows("permanent"))
self.assertEqual(rows[0]["uid"], fixture["expected"]["permanent_first_uid"])
def test_uid_uses_pool_timestamp_and_ordinal_only(self):
row = {
"pool_group_id": "Lottery_LimitedCharacter",
"timestamp_raw_hex": "40e93247c3097b23",
"dice": 5,
"reward_key_hex": "10a58d957dd1a58dad95d17dc1c800",
"quantity": 50,
}
changed_content = {
**row,
"dice": 1,
"reward_key_hex": "98bdc9ad7dd9a5b99501",
"quantity": 1,
}
changed_pool = {**row, "pool_group_id": "Lottery_Permanent"}
self.assertEqual(make_uid(row, 0), "74a9ef4aacde549dfe8e8e7cc6ddd65b")
self.assertEqual(make_uid(changed_content, 0), make_uid(row, 0))
self.assertNotEqual(make_uid(changed_pool, 0), make_uid(row, 0))
self.assertNotEqual(make_uid(row, 1), make_uid(row, 0))
def test_pages_1_to_5_exports_every_row(self):
annotated = annotate_groups(fixture_session().build_rows("permanent"))
exported = [row for row in annotated if row["export_record"] is True]
# Every decoded row is exported; boundary groups are never dropped.
self.assertEqual(len(annotated), 25)
self.assertEqual(len(exported), 25)
@staticmethod
def _synthetic_row(page, timestamp_hex, result_type):
return {
"page": page,
"timestamp_raw_hex": timestamp_hex,
"timestamp_decoded": f"ts-{timestamp_hex}",
"result_type": result_type,
"dice": 4 if result_type == "dice" else 0,
"reward_key_hex": "10a58d9539bdc9b585b101",
"quantity": 1,
}
def test_oldest_group_with_partial_dice_count_exports_without_warning(self):
rows = [self._synthetic_row(1, "aa", "dice") for _ in range(5)]
rows += [self._synthetic_row(2, "bb", "dice") for _ in range(5)]
rows += [self._synthetic_row(3, "bb", "dice") for _ in range(4)]
rows += [self._synthetic_row(3, "bb", "points_gift")]
annotated = annotate_groups(rows)
exported = [row for row in annotated if row["export_record"] is True]
# Oldest group is a partially captured 10-pull on a full final page. Its
# captured prefix is ordinal-stable, so it is exported with stable UIDs.
self.assertEqual(len(exported), 15)
oldest = [row for row in annotated if row["timestamp_raw_hex"] == "bb"]
self.assertTrue(all(row["uid"] for row in oldest))
self.assertTrue(all(row["uid_status"] == "stable" for row in oldest))
self.assertEqual([row["timestamp_group_ordinal"] for row in oldest], list(range(10)))
def test_incomplete_oldest_prefix_keeps_stable_uids(self):
full = [self._synthetic_row(1, "aa", "dice") for _ in range(5)]
full += [self._synthetic_row(2, "bb", "dice") for _ in range(3)]
full += [self._synthetic_row(3, "bb", "dice") for _ in range(2)]
truncated = [r for r in full if r["page"] in (1, 2)]
full_rows = annotate_groups([dict(r) for r in full])
trunc_rows = annotate_groups([dict(r) for r in truncated])
full_uids = [r["uid"] for r in full_rows if r["timestamp_raw_hex"] == "bb"][:3]
trunc_uids = [r["uid"] for r in trunc_rows if r["timestamp_raw_hex"] == "bb"]
# Capturing only the first 3 of a 5-record oldest group yields the same
# UIDs those rows have in the full capture.
self.assertEqual(len(trunc_uids), 3)
self.assertEqual(trunc_uids, full_uids)
def test_oldest_group_with_ten_dice_exports_on_full_final_page(self):
rows = [self._synthetic_row(1, "aa", "dice") for _ in range(5)]
rows += [self._synthetic_row(2, "bb", "dice") for _ in range(5)]
rows += [self._synthetic_row(3, "bb", "dice") for _ in range(5)]
annotated = annotate_groups(rows)
exported = [row for row in annotated if row["export_record"] is True]
self.assertEqual(len(exported), 15)
def test_run_selection_anchors_to_page_1_and_keeps_newest(self):
# Page 2's response was lost: captured pages 1, 3, 4, 5.
pairs = [(p, p * 2, 0, 0, 0, 0, b"", "permanent") for p in (1, 3, 4, 5)]
run, warnings = select_continuous_run_from_page_1(pairs)
# The page-1 run (just page 1, the newest history) is kept; later pages are
# ignored with a gap warning, never silently discarding page 1.
self.assertEqual([p[0] for p in run], [1])
self.assertEqual(len(warnings), 1)
self.assertEqual(warnings[0]["code"], "PAGE_GAP_DETECTED")
self.assertEqual(warnings[0]["ignored_pages"], [3, 4, 5])
def test_run_selection_warns_when_page_1_missing(self):
pairs = [(p, p * 2, 0, 0, 0, 0, b"", "permanent") for p in (3, 4, 5)]
run, warnings = select_continuous_run_from_page_1(pairs)
self.assertEqual([p[0] for p in run], [3, 4, 5])
self.assertEqual(warnings[0]["code"], "DID_NOT_START_AT_PAGE_1")
def test_committed_network_scan_exports_all_rows(self):
fixture = load_network_fixture()
annotated = annotate_groups(fixture_session().build_rows("permanent"))
exported = [row for row in annotated if row["export_record"] is True]
self.assertEqual(len(annotated), fixture["expected"]["permanent_records"])
self.assertEqual(len(exported), fixture["expected"]["permanent_records"])
def test_monopoly_uid_compatibility_vectors_are_frozen(self):
vectors = [
("Lottery_Permanent", "0000000000000000", 0, "5da57468adb23fcfde530fd849a25767"),
("Lottery_Permanent", "00a243eb689b7a23", 0, "8f9fb9bc92a867f6f41e5839e94c7991"),
("Lottery_Permanent", "00a243eb689b7a23", 1, "6a0bea71d091b9b7063780fcc86238d5"),
("Lottery_LimitedCharacter", "00a243eb689b7a23", 0, "b8f5d3c27315c70ceafbe8eb2bab0fc2"),
("Lottery_LimitedCharacter", "ffffffffffffffff", 9, "66916e1f077fdf7664f0f0edc4c64eb8"),
]
for pool_group_id, timestamp_raw_hex, ordinal, expected_uid in vectors:
with self.subTest(
pool_group_id=pool_group_id,
timestamp=timestamp_raw_hex,
ordinal=ordinal,
):
row = {
"pool_group_id": pool_group_id,
"timestamp_raw_hex": timestamp_raw_hex,
}
self.assertEqual(make_uid(row, ordinal), expected_uid)
def test_arc_uid_compatibility_vectors_are_frozen(self):
vectors = [
("0000000000000000", 0, "faa0b07cefd71758d4a8d64bc2a2f78e"),
("00a243eb689b7a23", 0, "7a7ef75281fcced043f691d269477cfa"),
("00a243eb689b7a23", 1, "f798c076ea1d137a08fe62df859e8a7f"),
("ffffffffffffffff", 9, "d114cc6c313a15f55ca12910801d78ea"),
]
for timestamp_raw_hex, ordinal, expected_uid in vectors:
with self.subTest(timestamp=timestamp_raw_hex, ordinal=ordinal):
self.assertEqual(make_arc_uid(timestamp_raw_hex, ordinal), expected_uid)