Files
DumiFlex 4ff45d2492 feat(toggles): every toggle can have a Value and a Negative, plus $name.bool (#367)
A toggle with a Value writes it to its variable while on and nothing while off; its Negative goes with the variable. $name.bool reads the switch (true/false) across nodes, in text and in conditions, through __wp_toggle_bools__. Payloads reading $name.bool stamp schema 12; bool is reserved as a tag group.
2026-11-12 02:12:08 +01:00

77 lines
2.6 KiB
Python

"""engine/toggles.py — resolution, outputs and problems."""
import json
from pathlib import Path
import pytest
from engine import toggles
CORPUS = json.loads(
(Path(__file__).parent.parent / "fixtures" / "toggles-corpus.json").read_text("utf-8")
)["cases"]
@pytest.mark.parametrize("case", CORPUS, ids=[c["name"] for c in CORPUS])
def test_corpus(case):
parsed = toggles.parse_config(json.dumps(case["config"]))
cfg, _ = toggles.with_upstream(parsed, case.get("upstream"))
assert toggles.resolve(cfg) == case["values"]
assert toggles.bools(cfg) == case["bools"]
assert toggles.own_negatives(cfg) == case.get("negatives", {})
n = len(case["outputs"])
vals = toggles.output_values(cfg)
assert len(vals) == toggles.MAX_OUTPUTS
assert vals[:n] == case["outputs"]
assert not any(vals[n:])
if "internal" in case:
assert sorted(toggles.internal_vars(cfg)) == case["internal"]
@pytest.mark.parametrize(
"raw", ["", "{", "[]", "null", 5, {"rows": "x"}, {"rows": [1, {"kind": "toggle"}]}],
)
def test_broken_config_is_empty(raw):
cfg = toggles.parse_config(raw)
assert cfg.toggles == []
assert toggles.resolve(cfg) == {}
assert toggles.output_values(cfg) == [False] * 16
def test_parse_reads_dict_and_defaults():
cfg = toggles.parse_config({"mode": "bogus", "rows": [
{"id": "a1", "kind": "toggle", "on": 1, "pin": True, "out": True, "var": " x "},
]})
assert cfg.mode == "any"
t = cfg.toggles[0]
assert (t.name, t.var, t.on, t.pin, t.out) == ("a1", "x", False, True, 0)
def test_more_than_sixteen_pins_are_cut():
rows = [
{"id": f"{i:08x}", "kind": "toggle", "var": f"v{i}", "on": True, "pin": True, "out": i + 1}
for i in range(20)
]
cfg = toggles.parse_config({"rows": rows})
assert len(toggles.output_slots(cfg)) == 16
assert toggles.output_values(cfg) == [True] * 16
def test_problems():
cfg = toggles.parse_config({"mode": "any", "group_var": "", "rows": [
{"id": "1", "name": "A", "var": "x", "needs": "2"},
{"id": "2", "name": "B", "var": "x", "needs": "1"},
{"id": "3", "name": "C", "var": "bad-name"},
]})
msgs = toggles.problems(cfg)
assert any("both write $x" in m for m in msgs)
assert any("bad-name" in m for m in msgs)
assert sum("loop" in m for m in msgs) == 2
def test_problems_group_var_and_pick_one_ignores_loops():
cfg = toggles.parse_config({"mode": "one", "group_var": "1x", "rows": [
{"id": "1", "var": "a", "needs": "1"},
]})
msgs = toggles.problems(cfg)
assert msgs == ["The Pick one variable can't be used: 1x"]