Files
2026-09-30 17:09:40 +08:00

124 lines
5.4 KiB
Python

import copy
import hashlib
import json
import unittest
from unittest.mock import patch
import seed_registry as m
class Seeds(unittest.TestCase):
def test_order_independent(self):
a, b = m.SeedRegistry(461), m.SeedRegistry(461)
keys = [("mode", "PAM15", str(replicate), str(epoch)) for replicate in range(5) for epoch in range(50)]
for key in keys:
a.add("training", key)
for key in reversed(keys):
b.add("training", key)
self.assertEqual(a.manifest(), b.manifest())
self.assertEqual(a.manifest()["independent_count"], 250)
self.assertTrue(m.validate_manifest(a.manifest()))
def test_splits_disjoint_and_no_sequential_overlap(self):
r = m.SeedRegistry(461)
for split in ("training", "evaluation", "design"):
for replicate in range(5):
for epoch in range(100):
r.add(split, ("shared-name", str(replicate), str(epoch)))
out = r.manifest()
seeds = [x["seed"] for x in out["independent_streams"]]
self.assertEqual(len(set(seeds)), 1500)
self.assertEqual(out["training_evaluation_seed_overlap"], 0)
self.assertTrue(all(0 <= s < 2**63 for s in seeds))
def test_alias_explicit_not_independent(self):
r = m.SeedRegistry(461)
seed = r.add("training", ("paired", "0"))
self.assertEqual(seed, r.alias("training", ("frozen", "0"), "training", ("paired", "0"), reason="Same prescheduled CS inputs, different learning policy"))
out = r.manifest()
self.assertEqual(out["independent_count"], 1)
self.assertEqual(out["alias_count"], 1)
self.assertFalse(out["aliases_count_as_independent_replicates"])
self.assertTrue(m.validate_manifest(out))
def test_no_cross_split_alias(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
with self.assertRaisesRegex(ValueError, "Cross-split"):
r.alias("evaluation", ("a",), "training", ("a",), reason="Not permitted")
def test_no_alias_chain(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
r.alias("training", ("b",), "training", ("a",), reason="Control")
with self.assertRaisesRegex(ValueError, "not another alias"):
r.alias("training", ("c",), "training", ("b",), reason="Invalid chain")
def test_no_silent_duplicate(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
with self.assertRaisesRegex(ValueError, "Duplicate"):
r.add("training", ("a",))
with self.assertRaisesRegex(ValueError, "Duplicate"):
r.alias("training", ("a",), "training", ("a",), reason="Invalid")
r.alias("training", ("b",), "training", ("a",), reason="Control")
with self.assertRaisesRegex(ValueError, "Duplicate"):
r.add("training", ("b",))
def test_collision_fails_without_resampling(self):
r = m.SeedRegistry(1)
with patch.object(m, "seed_for", return_value=(123, "a" * 64)):
r.add("training", ("a",))
with self.assertRaisesRegex(ValueError, "Seed collision"):
r.add("evaluation", ("b",))
self.assertEqual(len(r._streams), 1)
def test_mutations_detected(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
original = r.manifest()
for mutate in (lambda x: x["independent_streams"][0].update(seed=7),
lambda x: x.update(training_evaluation_seed_overlap=1),
lambda x: x.update(independent_count=2),
lambda x: x.update(payload_sha256="a" * 64),
lambda x: x.update(training_executed=True)):
corrupt = copy.deepcopy(original)
mutate(corrupt)
with self.assertRaises(ValueError):
m.validate_manifest(corrupt)
def test_manifest_copy_not_mutable_alias(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
out = r.manifest()
out["independent_streams"][0]["key"][0] = "changed"
self.assertEqual(r.manifest()["independent_streams"][0]["key"], ["a"])
self.assertTrue(m.validate_manifest(json.loads(json.dumps(r.manifest()))))
def test_json_numeric_boolean_type_changes_rejected_even_when_rehashed(self):
r = m.SeedRegistry(1)
r.add("training", ("a",))
for field, replacement in (("training_executed", 0), ("independent_count", 1.0)):
for rehash in (False, True):
corrupt = r.manifest()
corrupt[field] = replacement
if rehash:
payload = {key: value for key, value in corrupt.items() if key != "payload_sha256"}
corrupt["payload_sha256"] = hashlib.sha256(m._canonical(payload).encode("utf-8")).hexdigest()
with self.subTest(field=field, rehash=rehash), self.assertRaises(ValueError):
m.validate_manifest(corrupt)
def test_reject_invalid_values(self):
for master in (True, -1, 2**63, 1.0, "1"):
with self.assertRaises(ValueError):
m.SeedRegistry(master)
for key in ([], "a", [""], [" a"], ["a "]):
with self.assertRaises(ValueError):
m.seed_for(1, "training", key)
with self.assertRaises(ValueError):
m.seed_for(1, "unknown", ["a"])
if __name__ == "__main__":
unittest.main()