from __future__ import annotations import importlib.util from pathlib import Path ROOT = Path(__file__).resolve().parents[2] SCRIPT = ROOT / "scripts" / "plan_1c_moxel_next_experiments.py" SPEC = importlib.util.spec_from_file_location("plan_1c_moxel_next_experiments", SCRIPT) assert SPEC and SPEC.loader planner = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(planner) def test_build_plan_includes_named_range_experiments_for_candidate_rules() -> None: registry = { "rules": [ {"target": "moxel.inline_text_cell.column", "read_status": "verified_read"}, {"target": "moxel.named_range.left", "read_status": "candidate_read"}, {"target": "moxel.named_range.right", "read_status": "candidate_read"}, {"target": "moxel.named_range.top", "read_status": "candidate_read"}, {"target": "moxel.named_range.bottom", "read_status": "candidate_read"}, ] } plan = planner.build_plan(registry) ids = {item["id"] for item in plan["experiments"]} assert "named_range_rectangular_area" in ids assert "named_range_horizontal_resize" in ids assert "named_range_vertical_resize" in ids assert plan["counts"]["named_range_experiments"] == 3 def test_build_plan_keeps_property_experiments_even_without_named_range_gaps() -> None: plan = planner.build_plan({"rules": [{"target": "moxel.inline_text_cell.column", "read_status": "verified_read"}]}) assert plan["counts"]["named_range_experiments"] == 0 assert plan["counts"]["property_experiments"] >= 1 def test_build_plan_prioritizes_named_range_presence_when_verification_has_no_samples() -> None: registry = { "rules": [ {"target": "moxel.named_range.left", "read_status": "candidate_read"}, {"target": "moxel.named_range.right", "read_status": "candidate_read"}, ] } verification = { "results": [ { "target": "moxel.named_range.left", "probes": [{"evidence": {"ok": 0, "total": 0}}], } ] } plan = planner.build_plan(registry, verification) assert plan["experiments"][0]["id"] == "named_range_presence_probe" assert "named_ranges" in plan["experiments"][0]["expected_signal"]