bio-semantics / src /test_semantics.py
SNAPKITTYWEST's picture
Upload folder using huggingface_hub
9ae68e3 verified
Raw
History Blame Contribute Delete
3.87 kB
# test_semantics.py
import copy
import unittest
from semantics import validate_dataset, ptm_parity
def fixture():
# Explicitly synthetic: excluded from scientific conclusions.
return {
"dataset_id": "synthetic-validator-fixture",
"synthetic": True,
"observations": [{
"observation_id": "fixture-o1",
"sample_id": "fixture-s1",
"gene_id": "fixture-g1",
"condition": "control",
"timepoint": None,
"replicate": None,
"batch": None,
"cell_type": None,
"count": "0",
"missing_reason": None,
"exposure": 1.0,
"normalized_expression": None,
"normalization": None,
"measurement_quality": None,
}],
}
class SemanticsTests(unittest.TestCase):
conditions = ["control", "comparison"]
def test_zero_and_missing_remain_distinct_without_mutation(self):
data = fixture()
missing = copy.deepcopy(data["observations"][0])
missing.update(
observation_id="fixture-o2",
count=None,
missing_reason="not_measured",
)
data["observations"].append(missing)
before = copy.deepcopy(data)
validate_dataset(data, self.conditions)
self.assertEqual(data, before)
self.assertEqual(data["observations"][0]["count"], "0")
self.assertIsNone(data["observations"][1]["count"])
def test_bad_counts_are_rejected(self):
for count in [0, True, "-1", "1.5", "1e3", "01", " 1", "2147483648"]:
with self.subTest(count=count):
data = fixture()
data["observations"][0]["count"] = count
with self.assertRaises(ValueError):
validate_dataset(data, self.conditions)
def test_invalid_states_are_rejected(self):
patches = [
{"count": None}, # no missing reason
{"missing_reason": "not_measured"}, # count still present
{"exposure": 0},
{"exposure": float("inf")},
{"exposure": True},
{"condition": "undeclared"},
{"normalized_expression": 1.2}, # no provenance
{"measurement_quality": float("nan")},
]
for patch in patches:
with self.subTest(patch=patch):
data = fixture()
data["observations"][0].update(patch)
with self.assertRaises(ValueError):
validate_dataset(data, self.conditions)
def test_duplicate_identity_and_condition_config(self):
data = fixture()
data["observations"].append(copy.deepcopy(data["observations"][0]))
with self.assertRaises(ValueError):
validate_dataset(data, self.conditions)
with self.assertRaises(ValueError):
validate_dataset(fixture(), ["control", "control"])
def test_normalized_expression_requires_declared_sources(self):
data = fixture()
data["observations"][0].update(
normalized_expression=2.5,
normalization={
"method": "synthetic-test-transform",
"source_ids": ["synthetic-source-artifact"],
},
)
validate_dataset(data, self.conditions)
def test_ptm_outputs_and_resource_bound(self):
for bits, output in [("", "0"), ("0", "0"), ("1", "1"), ("1011", "1")]:
with self.subTest(bits=bits):
result = ptm_parity(bits)
self.assertEqual(result["output"], output)
self.assertEqual(result["transitions"], len(bits) + 1)
self.assertEqual(result["total_tape_cells"], len(bits) + 1)
self.assertEqual(ptm_parity("102")["status"], "rejected")
if __name__ == "__main__":
unittest.main()