import pytest from mas_conformance import statute_cases, statute_document from mas_core.statute import ( ERROR, WARNING, InheritanceCycle, StatuteInvalid, build_statute, lint, resolve_inheritance, ) CASES = statute_cases() @pytest.mark.parametrize("case", CASES, ids=[c["id"] for c in CASES]) def test_statute_case(case): doc = statute_document(case["file"]) findings = lint(doc, case["host"]) errors = [f for f in findings if f.severity == ERROR] if case["expect"] == "valid": assert not errors, errors build_statute(doc, case["host"]) assert set(case.get("warnings", [])) <= {f.code for f in findings if f.severity == WARNING} else: assert errors and {f.layer for f in errors} == {case["expect"]} assert set(case.get("codes", [])) <= {f.code for f in errors} with pytest.raises(StatuteInvalid) as exc: build_statute(doc, case["host"]) assert exc.value.layer == case["expect"] def test_schema_valid_but_semantically_rejected(): doc = statute_document("semantic-p2-disabled-modes.json") assert not [f for f in lint(doc) if f.layer == "schema"] with pytest.raises(StatuteInvalid): build_statute(doc) def _doc(ns, inherits=None, **over): d = {"mas_version": "0.1", "namespace": ns, "profiles": {"p1": True, "p2": True}, "equivalence": {"local_part_case": "exact", "dot_folding": False}} if inherits: d["inherits"] = inherits d.update(over) return d def url(ns): return f"https://{ns}/.well-known/mas" def test_inheritance_defaults_only(): parent = build_statute(_doc("parent.example", resource_types={"ticket": {"enabled": True}, "invoice": {"enabled": True}}, interaction_modes={"callback": {"enabled": True}}, addresses={"support": {"kind": "function"}})) child = build_statute(_doc("child.example", url("parent.example"), resource_types={"invoice": {"enabled": False}})) merged = resolve_inheritance(child, url("child.example"), lambda u: parent) assert merged.namespace == "child.example" assert merged.resource_type_enabled("ticket") # inherited default assert not merged.resource_type_enabled("invoice") # child overrides assert merged.interaction_mode_enabled("callback") assert "support" not in merged.addresses # registry never inherits assert merged.inherited_from == (url("parent.example"),) @pytest.mark.parametrize("length", [2, 3, 4]) def test_inheritance_cycles(length): names = [f"n{i}.example" for i in range(length)] docs = {url(n): build_statute(_doc(n, url(names[(i + 1) % length]))) for i, n in enumerate(names)} with pytest.raises(InheritanceCycle) as exc: resolve_inheritance(docs[url(names[0])], url(names[0]), docs.__getitem__) assert exc.value.chain[0] == exc.value.chain[-1] def _with_address(entry): doc = statute_document("valid-great-service.json") doc["addresses"]["intake"] = entry return {f.code: f.severity for f in lint(doc, "great-service.example")} def test_intake_for_lint(): assert "intake-unknown-type" not in _with_address({"kind": "function", "intake_for": "ticket"}) assert _with_address({"kind": "function", "intake_for": "invoice"})["intake-unknown-type"] == ERROR assert _with_address({"kind": "group", "intake_for": "ticket"})["intake-not-function"] == ERROR def _v02(**extra): doc = statute_document("valid-great-service.json") doc["mas_version"] = "0.2" doc.update(extra) return doc def test_v02_statute_builds_with_new_fields(): doc = _v02(alternate_syntax={"resource": True, "interaction": True}) doc["equivalence"]["resource_id_case"] = "insensitive" st = build_statute(doc, "great-service.example") assert (st.mas_version, st.alt_resource, st.alt_interaction, st.resource_id_case) == \ ("0.2", True, True, "insensitive") plain = build_statute(_v02(), "great-service.example") assert (plain.alt_resource, plain.alt_interaction, plain.resource_id_case) == (False, False, "exact") def test_v01_statute_rejects_v02_fields(): doc = statute_document("valid-great-service.json") doc["alternate_syntax"] = {"resource": True} assert any(f.severity == ERROR and f.layer == "schema" for f in lint(doc, "great-service.example")) def test_stand_in_lint(): doc = _v02(alternate_syntax={"resource": True, "interaction": True}) doc["addresses"]["ticket--legacy"] = {"kind": "function"} doc["addresses"]["sales---callback"] = {"kind": "function"} codes = [f.code for f in lint(doc, "great-service.example") if f.severity == ERROR] assert codes.count("stand-in-collision") == 2 off = _v02() off["addresses"]["ticket--legacy"] = {"kind": "function"} assert "stand-in-collision" not in {f.code for f in lint(off, "great-service.example")}