mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[tools] (P7): the wire declines audit carries a self-test whose fixtures must red, and the CI step runs it before the tree audit
Fable review of the B3 rework, should-fix: the audit had no negative
control, so a green run could not say it would have been red. It now takes
--self-test, which writes each inline fixture as a one-file renderer tree in
a temp dir, runs the audit on it and checks both the rc and the line the
audit must print (so a red is red for the fixture's reason):
comment-only site (//) -> rc 1, "has NO SITE"
comment-only site (/* */) -> rc 1, "has NO SITE"
string-literal site -> rc 1, "has NO SITE"
other-branch log -> rc 1, "with no MGLOG_W/E in its own block"
nested-branch log -> rc 1, same
log only in a /* */ comment above -> rc 1, same
nearest log is MGLOG_D -> rc 1, same
good sites (AT form, bare Count under
its own MGLOG_E_ONCE, def row with a
trailing comment) -> rc 0, "0 unlogged, 0 unknown"
8/8, rc 0. Mutants: with the strip disabled 5 of 8 fail (the four
comment/string reds go green and the good fixture's commented row is
lost); with the old 8-line window in place of the block walk 2 of 8 fail
(other-branch, nested-branch). Against the audit as it stood at aab01275,
six of the seven red fixtures passed and the good one failed.
.github/workflows/test.yml: the "Wire declines audit (B3)" step runs
--self-test and then the tree audit, the way the next step runs
trace_cases.py --self-test-transport-matrices before it computes matrices.
This commit is contained in:
@@ -2393,9 +2393,13 @@ jobs:
|
||||
run: python3 scripts/ci/fatal_census.py
|
||||
|
||||
# The decline half of rule I (P7 B3): every WireDeclines.def row has a site, every site a
|
||||
# warning-or-error line. Same shape as the census - tree-only, no build.
|
||||
# warning-or-error line. Same shape as the census - tree-only, no build. The self-test
|
||||
# runs first: its fixtures (a site only in a comment or a string, a log in another
|
||||
# branch, an MGLOG_D) must red, so a green audit is one that could have been red.
|
||||
- name: Wire declines audit (B3)
|
||||
run: python3 scripts/ci/wire_declines_audit.py
|
||||
run: |
|
||||
python3 scripts/ci/wire_declines_audit.py --self-test
|
||||
python3 scripts/ci/wire_declines_audit.py
|
||||
|
||||
- name: Load trace cases
|
||||
id: trace-cases
|
||||
|
||||
@@ -24,10 +24,14 @@ Everything is matched on the text with comments and string/character literals bl
|
||||
or only a string, is not one.
|
||||
|
||||
usage: wire_declines_audit.py [repo-root]
|
||||
wire_declines_audit.py --self-test (negative controls on inline fixtures)
|
||||
"""
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
RENDERER = "MobileGL/MG_Backend/DirectVulkan/Renderer"
|
||||
DEF = os.path.join(RENDERER, "WireDeclines.def")
|
||||
@@ -184,7 +188,102 @@ def audit(root: str) -> int:
|
||||
return 1 if bad else 0
|
||||
|
||||
|
||||
# --self-test: each fixture is (name, def rows text, Fixture.cpp text, expected rc, text the
|
||||
# audit must print - so a red is red for the reason the fixture is about). The red ones are
|
||||
# the holes the B3 fix round closed; the green one proves the audit still accepts the two
|
||||
# shapes the tree uses.
|
||||
NO_SITE = "has NO SITE"
|
||||
NO_LOG = "with no MGLOG_W/E in its own block"
|
||||
_DEF_GHOST = "MGL_WIRE_DECLINE(GhostRow)\n"
|
||||
SELF_TEST_FIXTURES = (
|
||||
("comment-only site (//)", _DEF_GHOST,
|
||||
"void F() {\n"
|
||||
" // MGL_WIRE_DECLINE_AT(GhostRow, \"never counted\");\n"
|
||||
"}\n", 1, NO_SITE),
|
||||
("comment-only site (/* */)", _DEF_GHOST,
|
||||
"void F() {\n"
|
||||
" /* retired:\n"
|
||||
" MGL_WIRE_DECLINE_AT(GhostRow, \"never counted\"); */\n"
|
||||
"}\n", 1, NO_SITE),
|
||||
("string-literal site", _DEF_GHOST,
|
||||
"const char* kDoc = \"MGL_WIRE_DECLINE_AT(GhostRow, x);\";\n", 1, NO_SITE),
|
||||
("other-branch log", _DEF_GHOST,
|
||||
"void F(int x) {\n"
|
||||
" if (x == 1) {\n"
|
||||
" MGLOG_W(\"x is one\");\n"
|
||||
" }\n"
|
||||
" if (x == 2) {\n"
|
||||
" WireDeclineTally::Count(WireDeclineSite::GhostRow);\n"
|
||||
" }\n"
|
||||
"}\n", 1, NO_LOG),
|
||||
("nested-branch log", _DEF_GHOST,
|
||||
"void F(int x) {\n"
|
||||
" if (x) {\n"
|
||||
" if (x == 1) {\n"
|
||||
" MGLOG_W(\"x is one\");\n"
|
||||
" }\n"
|
||||
" WireDeclineTally::Count(WireDeclineSite::GhostRow);\n"
|
||||
" }\n"
|
||||
"}\n", 1, NO_LOG),
|
||||
("log only in a /* */ comment above", _DEF_GHOST,
|
||||
"void F(int x) {\n"
|
||||
" if (x) {\n"
|
||||
" /* MGLOG_W(\"x\"); */\n"
|
||||
" WireDeclineTally::Count(WireDeclineSite::GhostRow);\n"
|
||||
" }\n"
|
||||
"}\n", 1, NO_LOG),
|
||||
("nearest log is MGLOG_D", _DEF_GHOST,
|
||||
"void F(int x) {\n"
|
||||
" if (x) {\n"
|
||||
" MGLOG_D(\"compiled away in Release\");\n"
|
||||
" WireDeclineTally::Count(WireDeclineSite::GhostRow);\n"
|
||||
" }\n"
|
||||
"}\n", 1, NO_LOG),
|
||||
("good sites (AT form, bare Count under its own W/E, def row with trailing comment)",
|
||||
"MGL_WIRE_DECLINE(GoodAt) // the macro form\nMGL_WIRE_DECLINE(GoodBare)\n",
|
||||
"bool F(int x) {\n"
|
||||
" if (x == 1) {\n"
|
||||
" MGL_WIRE_DECLINE_AT(GoodAt, \"x=%d\", x);\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
" if (x == 2) {\n"
|
||||
" MGLOG_E_ONCE(\"x is two: %d, \"\n"
|
||||
" \"declined\", x);\n"
|
||||
" WireDeclineTally::Count(WireDeclineSite::GoodBare);\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
" return true;\n"
|
||||
"}\n", 0, "0 unlogged, 0 unknown"),
|
||||
)
|
||||
|
||||
|
||||
def self_test() -> int:
|
||||
failures = 0
|
||||
for name, def_text, src_text, want, why in SELF_TEST_FIXTURES:
|
||||
with tempfile.TemporaryDirectory(prefix="wire-declines-selftest-") as root:
|
||||
src_dir = os.path.join(root, RENDERER)
|
||||
os.makedirs(src_dir)
|
||||
with open(os.path.join(src_dir, "WireDeclines.def"), "w", encoding="utf-8") as f:
|
||||
f.write(def_text)
|
||||
with open(os.path.join(src_dir, "Fixture.cpp"), "w", encoding="utf-8") as f:
|
||||
f.write(src_text)
|
||||
captured = io.StringIO()
|
||||
with contextlib.redirect_stdout(captured), contextlib.redirect_stderr(captured):
|
||||
got = audit(root)
|
||||
ok = got == want and why in captured.getvalue()
|
||||
failures += 0 if ok else 1
|
||||
print("wire-declines self-test: %-4s %s -> rc %d (want %d, printing \"%s\")"
|
||||
% ("ok" if ok else "FAIL", name, got, want, why))
|
||||
if not ok:
|
||||
sys.stdout.write("".join(" " + l + "\n" for l in captured.getvalue().splitlines()))
|
||||
print("wire-declines self-test: %d/%d fixtures as expected"
|
||||
% (len(SELF_TEST_FIXTURES) - failures, len(SELF_TEST_FIXTURES)))
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--self-test":
|
||||
return self_test()
|
||||
return audit(os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else "."))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user