173 lines
5.8 KiB
Python
173 lines
5.8 KiB
Python
from __future__ import annotations
|
|
|
|
import ast
|
|
from dataclasses import FrozenInstanceError
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
import generate.foundational_families as foundational_families
|
|
from generate.foundational_families import (
|
|
FoundationalFamilySpec,
|
|
get_foundational_family,
|
|
get_foundational_family_by_relation_type,
|
|
iter_foundational_families,
|
|
require_foundational_family,
|
|
)
|
|
|
|
|
|
EXPECTED_FAMILY_IDS = (
|
|
"binding.quantity_entity",
|
|
"state_change.transition",
|
|
"state_change.unary_delta",
|
|
)
|
|
|
|
|
|
def test_registry_contains_only_the_two_approved_specs_in_deterministic_order() -> None:
|
|
families = iter_foundational_families()
|
|
|
|
assert isinstance(families, tuple)
|
|
assert tuple(family.family_id for family in families) == EXPECTED_FAMILY_IDS
|
|
assert tuple(family.family_id for family in iter_foundational_families()) == (
|
|
EXPECTED_FAMILY_IDS
|
|
)
|
|
|
|
|
|
def test_public_family_accessors() -> None:
|
|
quantity = get_foundational_family("binding.quantity_entity")
|
|
state_change = require_foundational_family("state_change.transition")
|
|
unary_delta = require_foundational_family("state_change.unary_delta")
|
|
|
|
assert quantity is not None
|
|
assert quantity.family_id == "binding.quantity_entity"
|
|
assert state_change.family_id == "state_change.transition"
|
|
assert unary_delta.family_id == "state_change.unary_delta"
|
|
assert get_foundational_family("missing.family") is None
|
|
|
|
with pytest.raises(KeyError, match="missing.family"):
|
|
require_foundational_family("missing.family")
|
|
|
|
|
|
def test_lookup_by_primary_relation_type() -> None:
|
|
quantity = get_foundational_family_by_relation_type("quantity_entity")
|
|
state_change = get_foundational_family_by_relation_type("state_change")
|
|
unary_delta = get_foundational_family_by_relation_type("unary_delta")
|
|
|
|
assert quantity is get_foundational_family("binding.quantity_entity")
|
|
assert state_change is get_foundational_family("state_change.transition")
|
|
assert unary_delta is get_foundational_family("state_change.unary_delta")
|
|
assert get_foundational_family_by_relation_type("missing_relation") is None
|
|
|
|
|
|
def test_registry_keys_are_unique() -> None:
|
|
families = iter_foundational_families()
|
|
family_ids = tuple(family.family_id for family in families)
|
|
relation_types = tuple(family.primary_relation_type for family in families)
|
|
|
|
assert len(family_ids) == len(set(family_ids))
|
|
assert len(relation_types) == len(set(relation_types))
|
|
|
|
|
|
def test_specs_are_frozen_and_only_authorized_slices_are_implemented() -> None:
|
|
for family in iter_foundational_families():
|
|
assert isinstance(family, FoundationalFamilySpec)
|
|
assert family.serving_allowed is False
|
|
assert "not serving" in family.serving_status.lower()
|
|
|
|
with pytest.raises(FrozenInstanceError):
|
|
family.display_name = "mutated" # type: ignore[misc]
|
|
|
|
assert require_foundational_family(
|
|
"binding.quantity_entity"
|
|
).implementation_authorized is True
|
|
assert require_foundational_family(
|
|
"state_change.transition"
|
|
).implementation_authorized is False
|
|
assert require_foundational_family(
|
|
"state_change.unary_delta"
|
|
).implementation_authorized is True
|
|
|
|
|
|
def test_required_adr_0224_fields_are_populated() -> None:
|
|
required_fields = (
|
|
"family_id",
|
|
"display_name",
|
|
"status",
|
|
"related_adrs",
|
|
"domains",
|
|
"summary",
|
|
"surface_chunk_patterns",
|
|
"semantic_neighborhood",
|
|
"construction_signatures",
|
|
"required_roles",
|
|
"optional_roles",
|
|
"hazards_confusers",
|
|
"frame_representation",
|
|
"contract_readiness_criteria",
|
|
"verification_style",
|
|
"refusal_conditions",
|
|
"cross_domain_evidence",
|
|
"current_state",
|
|
"target_state",
|
|
"serving_status",
|
|
"primary_relation_type",
|
|
"future_adapter",
|
|
)
|
|
|
|
for family in iter_foundational_families():
|
|
assert all(getattr(family, field) for field in required_fields)
|
|
assert "ADR-0224" in family.related_adrs
|
|
assert family.hazards_confusers
|
|
assert family.refusal_conditions
|
|
assert family.current_state != family.target_state
|
|
|
|
|
|
def test_each_family_has_at_least_two_non_math_evidence_examples() -> None:
|
|
math_domains = {
|
|
"arithmetic",
|
|
"arithmetic_quantitative",
|
|
"arithmetic_proportional",
|
|
"mathematics",
|
|
}
|
|
|
|
for family in iter_foundational_families():
|
|
non_math_evidence = tuple(
|
|
evidence
|
|
for evidence in family.cross_domain_evidence
|
|
if evidence.domain not in math_domains
|
|
)
|
|
assert len(non_math_evidence) >= 2
|
|
assert all(evidence.example for evidence in non_math_evidence)
|
|
assert all(evidence.expected_roles for evidence in non_math_evidence)
|
|
|
|
|
|
def test_registry_module_has_no_markdown_or_filesystem_loading_surface() -> None:
|
|
source_path = Path(foundational_families.__file__)
|
|
tree = ast.parse(source_path.read_text(encoding="utf-8"))
|
|
|
|
imported_modules = {
|
|
alias.name
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.Import)
|
|
for alias in node.names
|
|
}
|
|
imported_from_modules = {
|
|
node.module
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.ImportFrom) and node.module is not None
|
|
}
|
|
called_names = {
|
|
node.func.id
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name)
|
|
}
|
|
called_attributes = {
|
|
node.func.attr
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute)
|
|
}
|
|
|
|
assert "pathlib" not in imported_modules | imported_from_modules
|
|
assert "markdown" not in imported_modules | imported_from_modules
|
|
assert "open" not in called_names
|
|
assert not ({"read_text", "read_bytes"} & called_attributes)
|