Verified with the coordinated workspace changes by devkit full run 2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed). This shared UI pass does not mark the individual module reviews complete.
340 lines
13 KiB
Python
Executable File
340 lines
13 KiB
Python
Executable File
"""Coverage inventory is explicit intent, never execution or guessed completion."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import re
|
|
import shutil
|
|
import sys
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "tools/devkit"))
|
|
from govoplan_devkit.catalog import build_coverage, build_stages, module_ui_stages # noqa: E402
|
|
from govoplan_devkit.coverage import canonical_invocations # noqa: E402
|
|
from govoplan_devkit.package_tests import ( # noqa: E402
|
|
CORE_COMPONENT_SUITES,
|
|
declared_tests,
|
|
read_package,
|
|
)
|
|
from govoplan_devkit.workspace import Project, Repository # noqa: E402
|
|
|
|
|
|
@pytest.fixture
|
|
def fixture(tmp_path):
|
|
core = Repository("govoplan-core", tmp_path / "govoplan-core", ("core",))
|
|
meta = Repository("govoplan", tmp_path / "govoplan", ("meta",))
|
|
module = Repository("govoplan-example", tmp_path / "govoplan-example", ("example",))
|
|
for repo in (core, meta, module):
|
|
(repo.path / "webui/scripts").mkdir(parents=True)
|
|
(repo.path / "webui/tests").mkdir()
|
|
scripts = {
|
|
"test:components": "node scripts/run-component-tests.mjs",
|
|
**{
|
|
f"test:{name}": f"node scripts/run-component-tests.mjs {name}"
|
|
for name in CORE_COMPONENT_SUITES
|
|
},
|
|
}
|
|
(core.path / "webui/package.json").write_text(json.dumps({"scripts": scripts}))
|
|
(core.path / "webui/scripts/run-component-tests.mjs").write_text("// fixture")
|
|
(module.path / "webui/package.json").write_text(
|
|
json.dumps(
|
|
{
|
|
"scripts": {
|
|
"test:safe": "node --test tests/source.test.mjs",
|
|
"test:compound": "tsc && node test.js",
|
|
"test:bad-quote": "node 'broken",
|
|
}
|
|
}
|
|
)
|
|
)
|
|
(module.path / "webui/tests/source.test.mjs").write_text("// fixture")
|
|
script = meta.path / "tools/checks/check-focused.sh"
|
|
script.parent.mkdir(parents=True)
|
|
phase_metadata = ROOT / "tools/checks/focused-phases.json"
|
|
shutil.copyfile(phase_metadata, script.with_name("focused-phases.json"))
|
|
bodies = {
|
|
"core-ui": 'cd "$ROOT/webui"\n"$NPM" run test:components -- layout-primitives page-layout data-grid-actions mail-components\n',
|
|
"module-ui": 'cd "$WORKSPACE_ROOT/govoplan-example/webui"\n"$NPM" run test:compound\n',
|
|
}
|
|
script.write_text(
|
|
"\n".join(
|
|
f"focused_phase_{phase['id'].replace('-', '_')}() {{\n# devkit-phase: {phase['id']} begin\n"
|
|
+ bodies.get(phase["id"], 'cd "$ROOT"\n')
|
|
+ f"# devkit-phase: {phase['id']} end\n}}\n"
|
|
for phase in json.loads(phase_metadata.read_text())["phases"]
|
|
)
|
|
)
|
|
project = Project("Fixture", (meta, core, module), {})
|
|
with (
|
|
patch("govoplan_devkit.workspace.load_project", return_value=project),
|
|
patch("govoplan_devkit.coverage.load_project", return_value=project),
|
|
):
|
|
yield tmp_path, core, module, project
|
|
|
|
|
|
def rows(coverage, repo="govoplan-core"):
|
|
return {row["name"]: row for row in coverage["suites"] if row["repo"] == repo}
|
|
|
|
|
|
def test_core_aliases_are_explicitly_excluded_in_quick_and_covered_by_one_ui_stage(
|
|
fixture,
|
|
):
|
|
root, _, _, _ = fixture
|
|
quick = rows(build_coverage(root, "quick", [], False))
|
|
ui = rows(build_coverage(root, "ui", [], False))
|
|
for suite in CORE_COMPONENT_SUITES:
|
|
assert quick["test:" + suite]["disposition"] == "excluded"
|
|
assert "quick" in quick["test:" + suite]["reason"]
|
|
assert ui["test:" + suite]["disposition"] == "covered_elsewhere"
|
|
assert ui["test:" + suite]["covering_stage"] == "core.component-batch"
|
|
assert ui["test:components"]["covered_components"] == list(CORE_COMPONENT_SUITES)
|
|
|
|
|
|
def test_full_reports_only_four_of_sixteen_components_and_exact_shell_suite(fixture):
|
|
root, _, _, _ = fixture
|
|
result = build_coverage(root, "full", ["example"], False)
|
|
core = rows(result)
|
|
aliases = [core["test:" + suite] for suite in CORE_COMPONENT_SUITES]
|
|
assert sum(item["disposition"] == "covered_elsewhere" for item in aliases) == 4
|
|
assert sum(item["disposition"] == "excluded" for item in aliases) == 12
|
|
assert len(core["test:components"]["covered_components"]) == 4
|
|
assert "4/16" in core["test:components"]["reason"]
|
|
module = rows(result, "govoplan-example")
|
|
assert module["test:compound"]["disposition"] == "planned"
|
|
assert module["test:safe"]["disposition"] == "excluded"
|
|
assert result["stages"] == [
|
|
"focused." + phase["id"]
|
|
for phase in json.loads(
|
|
(ROOT / "tools/checks/focused-phases.json").read_text()
|
|
)["phases"]
|
|
]
|
|
assert core["test:components"]["covering_stage"] == "focused.core-ui"
|
|
assert module["test:compound"]["covering_stage"] == "focused.module-ui"
|
|
|
|
|
|
def test_prebuilt_plan_avoids_replanning(fixture):
|
|
root, _, _, _ = fixture
|
|
stages = build_stages(root, "quick", [], False)
|
|
with patch(
|
|
"govoplan_devkit.catalog.build_stages",
|
|
side_effect=AssertionError("must not replan"),
|
|
):
|
|
result = build_coverage(root, "quick", [], False, stages=stages)
|
|
assert rows(result, "govoplan-example")["test:safe"]["disposition"] == "planned"
|
|
assert sum(result["counts"].values()) == result["suite_count"]
|
|
assert all(item["reason"] for item in result["suites"])
|
|
|
|
|
|
def test_missing_or_spoofed_phase_stage_does_not_grant_component_coverage(fixture):
|
|
root, _, _, _ = fixture
|
|
stages = build_stages(root, "full", [], False)
|
|
without_core = [item for item in stages if item["id"] != "focused.core-ui"]
|
|
result = build_coverage(root, "full", [], False, stages=without_core)
|
|
assert rows(result)["test:components"]["covered_components"] == []
|
|
assert (
|
|
rows(result, "govoplan-example")["test:compound"]["covering_stage"]
|
|
== "focused.module-ui"
|
|
)
|
|
next(item for item in stages if item["id"] == "focused.core-ui")["argv"] = ["true"]
|
|
spoofed = build_coverage(root, "full", [], False, stages=stages)
|
|
assert rows(spoofed)["test:components"]["covered_components"] == []
|
|
|
|
|
|
@pytest.mark.parametrize("wrapper", ["heredoc", "function", "conditional"])
|
|
def test_lookalike_phase_wrappers_outside_top_level_do_not_grant_coverage(
|
|
fixture, wrapper
|
|
):
|
|
root, core, _, project = fixture
|
|
meta = next(repo.path for repo in project.repositories if repo.name == "govoplan")
|
|
path = meta / "tools/checks/check-focused.sh"
|
|
fake = 'focused_phase_core_ui() {\n# devkit-phase: core-ui begin\ncd "$ROOT/webui"\n"$NPM" run test:spoof\n# devkit-phase: core-ui end\n}\n'
|
|
prefix = {
|
|
"heredoc": "cat <<'BODY'\n" + fake + "BODY\n",
|
|
"function": "unused() {\n" + fake + "}\n",
|
|
"conditional": "if false; then\n" + fake + "fi\n",
|
|
}[wrapper]
|
|
path.write_text(prefix + path.read_text())
|
|
result = canonical_invocations(root, meta, core.path)
|
|
assert result["notes"] == []
|
|
assert [item["name"] for item in result["npm"]] == [
|
|
"test:components",
|
|
"test:compound",
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize("damage", ["missing", "duplicate", "bad-end"])
|
|
def test_invalid_marked_phase_bodies_do_not_infer_coverage(fixture, damage):
|
|
root, core, _, project = fixture
|
|
meta = next(repo.path for repo in project.repositories if repo.name == "govoplan")
|
|
path = meta / "tools/checks/check-focused.sh"
|
|
text = path.read_text()
|
|
if damage == "missing":
|
|
text = text.replace("focused_phase_core_ui()", "unregistered_core_ui()")
|
|
elif damage == "duplicate":
|
|
text += text
|
|
else:
|
|
text = text.replace(
|
|
"# devkit-phase: core-ui end", "# devkit-phase: another end"
|
|
)
|
|
path.write_text(text)
|
|
result = canonical_invocations(root, meta, core.path)
|
|
assert result["npm"] == [] and result["node"] == []
|
|
assert "no phase coverage inferred" in result["notes"][0]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"repo_name,name,command",
|
|
[
|
|
("govoplan-example", "test:components", "node scripts/run-component-tests.mjs"),
|
|
(
|
|
"govoplan-core",
|
|
"test:dialog-focus",
|
|
"node scripts/run-component-tests.mjs dialog-focus && npm run dev",
|
|
),
|
|
(
|
|
"govoplan-core",
|
|
"test:unrecognized",
|
|
"node scripts/run-component-tests.mjs dialog-focus",
|
|
),
|
|
],
|
|
)
|
|
def test_component_alias_exemption_is_exact_and_core_only(
|
|
tmp_path, repo_name, name, command
|
|
):
|
|
repo = Repository(repo_name, tmp_path / repo_name)
|
|
package = repo.path / "webui/package.json"
|
|
package.parent.mkdir(parents=True)
|
|
package.write_text(json.dumps({"scripts": {name: command}}))
|
|
declared = declared_tests(repo, package)
|
|
assert declared[0]["component_suite"] is None
|
|
assert declared[0]["_argv"] is None
|
|
assert module_ui_stages(repo, reason="fixture") == []
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"body",
|
|
[
|
|
"[]",
|
|
"null",
|
|
'{"scripts":[]}',
|
|
'{"scripts":{"test:bad":42}}',
|
|
'{"scripts":{"test:one":"node a","test:one":"node b"}}',
|
|
"[" * 2000 + "]" * 2000,
|
|
],
|
|
)
|
|
def test_malformed_package_metadata_is_a_controlled_error(tmp_path, body):
|
|
package = tmp_path / "package.json"
|
|
package.write_text(body)
|
|
with pytest.raises(ValueError):
|
|
read_package(package)
|
|
|
|
|
|
def test_oversize_package_and_symlinked_test_are_not_discovered(tmp_path):
|
|
repo = Repository("example", tmp_path)
|
|
webui = tmp_path / "webui"
|
|
(webui / "tests").mkdir(parents=True)
|
|
package = webui / "package.json"
|
|
package.write_text(" " * (1024 * 1024 + 1))
|
|
with pytest.raises(ValueError):
|
|
read_package(package)
|
|
package.write_text(
|
|
json.dumps({"scripts": {"test:escape": "node tests/escape.mjs"}})
|
|
)
|
|
(webui / "tests/escape.mjs").symlink_to(tmp_path / "outside.mjs")
|
|
(tmp_path / "outside.mjs").write_text("// fixture")
|
|
assert module_ui_stages(repo, reason="fixture") == []
|
|
|
|
|
|
def test_unparseable_and_sensitive_commands_do_not_leak_into_coverage(fixture):
|
|
root, _, module, _ = fixture
|
|
package = module.path / "webui/package.json"
|
|
package.write_text(
|
|
json.dumps(
|
|
{
|
|
"scripts": {
|
|
"test:secret": "node tests/source.test.mjs --token unknown-private-value",
|
|
"test:broken": "node 'unknown-other-secret",
|
|
}
|
|
}
|
|
)
|
|
)
|
|
result = build_coverage(root, "quick", [], False)
|
|
encoded = json.dumps(result)
|
|
assert (
|
|
"unknown-private-value" not in encoded and "unknown-other-secret" not in encoded
|
|
)
|
|
assert "_argv" not in encoded and '"command"' not in encoded
|
|
assert all(
|
|
item["disposition"] == "unsupported"
|
|
for item in rows(result, "govoplan-example").values()
|
|
)
|
|
|
|
|
|
def test_custom_check_coverage_redacts_separate_token_and_includes_unselected(tmp_path):
|
|
project = tmp_path / "project.json"
|
|
project.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"repositories": [{"name": "app", "path": "."}],
|
|
"checks": [
|
|
{
|
|
"id": "one",
|
|
"argv": ["check", "--token", "unknown-private-value"],
|
|
},
|
|
{"id": "two", "argv": ["true"]},
|
|
],
|
|
"profiles": {"quick": ["one"]},
|
|
}
|
|
)
|
|
)
|
|
result = build_coverage(tmp_path, "quick", [], False, project)
|
|
assert "unknown-private-value" not in json.dumps(result)
|
|
assert result["counts"]["planned"] == 1 and result["counts"]["excluded"] == 1
|
|
|
|
|
|
def test_canonical_parser_does_not_credit_comments_heredocs_conditionals_or_chains(
|
|
tmp_path,
|
|
):
|
|
meta, core = tmp_path / "govoplan", tmp_path / "govoplan-core"
|
|
path = meta / "tools/checks/check-focused.sh"
|
|
path.parent.mkdir(parents=True)
|
|
path.write_text(
|
|
'cd "$ROOT/webui"\n# "$NPM" run test:comment\n"$PYTHON" - <<\'PY\'\n"$NPM" run test:heredoc\nPY\nif false; then\n"$NPM" run test:conditional\nfi\n"$NPM" run test:compound && true\n"$NPM" run test:real\n'
|
|
)
|
|
result = canonical_invocations(tmp_path, meta, core)
|
|
assert [item["name"] for item in result["npm"]] == ["test:real"]
|
|
|
|
|
|
def test_real_canonical_gate_has_four_explicit_component_suites():
|
|
result = canonical_invocations(ROOT.parent, ROOT, ROOT.parent / "govoplan-core")
|
|
calls = [item for item in result["npm"] if item["name"] == "test:components"]
|
|
assert len(calls) == 1
|
|
assert calls[0]["args"] == [
|
|
"layout-primitives",
|
|
"page-layout",
|
|
"data-grid-actions",
|
|
"mail-components",
|
|
]
|
|
assert calls[0]["phase"] == "core-ui"
|
|
for name, phase in (
|
|
("test:module-permutations", "module-builds"),
|
|
("test:conformance", "browser"),
|
|
):
|
|
matching = [item for item in result["npm"] if item["name"] == name]
|
|
assert len(matching) == 1 and matching[0]["phase"] == phase
|
|
|
|
|
|
def test_known_core_component_aliases_match_the_owned_runner_registry():
|
|
runner = (
|
|
ROOT.parent / "govoplan-core/webui/scripts/run-component-tests.mjs"
|
|
).read_text()
|
|
block = runner.split("export const componentSuites = Object.freeze({", 1)[1].split(
|
|
"});", 1
|
|
)[0]
|
|
assert set(re.findall(r'^ "([a-z0-9-]+)":', block, re.M)) == set(
|
|
CORE_COMPONENT_SUITES
|
|
)
|