"""v0.2 destination transforms (spec v0.2 section 12.1).""" import pytest from mas_conformance import statute_document from mas_core.generator import DESTINATION_PROFILES, CannotExpress, for_destination from mas_core.statute import build_statute def statute(resource=True, interaction=True, id_case="insensitive", version="0.2"): doc = statute_document("valid-great-service.json") doc["mas_version"] = version if version == "0.2": doc["alternate_syntax"] = {"resource": resource, "interaction": interaction} doc["equivalence"]["resource_id_case"] = id_case return build_statute(doc, "great-service.example") V2 = statute() IONOS = DESTINATION_PROFILES["ionos-forward"] def test_canonical_when_nothing_is_needed(): r = for_destination("ticket=GS-1+comments", V2, ()) assert (r.local_part, r.applied) == ("ticket=GS-1+comments", ()) def test_ionos_forward_profile(): # the MAS-WP-0003 case: IONOS refuses '=' and forces lower case r = for_destination("ticket=GS-85QJ8WC09P+comments", V2, IONOS) assert r.local_part == "ticket--gs-85qj8wc09p+comments" assert r.applied == ("resource-alternate", "lowercase") def test_transforms_apply_only_where_they_change_something(): assert for_destination("support", V2, IONOS).applied == () assert for_destination("ticket=gs-1", V2, IONOS).applied == ("resource-alternate",) def test_interaction_alternate(): assert for_destination("ticket!callback", V2, ("interaction-alternate",)).local_part == "ticket---callback" @pytest.mark.parametrize("st, code", [ (statute(resource=False), "transform-not-permitted"), # no '--' switch (statute(version="0.1"), "transform-not-permitted"), # v0.1 statute (statute(id_case="exact"), "would-be-misread"), # lower-casing changes the id ]) def test_refuses_what_the_namespace_would_misread(st, code): with pytest.raises(CannotExpress) as e: for_destination("ticket=GS-1", st, IONOS) assert e.value.code == code def test_refuses_id_containing_equals(): with pytest.raises(CannotExpress) as e: for_destination("ticket=RE=2026-4711", V2, ("resource-alternate",)) assert e.value.code == "cannot-express" def test_refuses_case_change_in_facet(): with pytest.raises(CannotExpress) as e: for_destination("ticket=gs-1+Comments", V2, ("lowercase",)) assert e.value.code == "would-be-misread" def test_length_is_checked_after_transforms(): lp = "ticket=" + "a" * 57 # 64 octets canonical, 65 with '--' assert len(lp) == 64 with pytest.raises(CannotExpress) as e: for_destination(lp, V2, ("resource-alternate",)) assert e.value.code == "too-long" def test_lossy_transforms_need_explicit_permission(): with pytest.raises(CannotExpress): for_destination("ticket=gs-1+comments", V2, ("drop-facet",)) r = for_destination("ticket!callback", V2, ("drop-interaction",), allow_lossy=True) assert r.local_part == "ticket" and r.warnings