mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-06 14:39:22 +00:00
test: close the r4 mediums — structural tuple scan and reuse-key inputs (#42)
M1: the AC5 scanner parses the (field, code, message) literal tuple in validation.py structurally instead of naming the two known codes — a third tuple entry with an unregistered code now fails the registry test (verified with an injected invalid_ghost_entity_mutant_probe), and a tuple whose string count is not a multiple of three refuses instead of guessing. M2: the backend reuse key now includes its direct job inputs introduced by this issue — scripts/backend-coverage-baseline.txt (the threshold the comparison step reads), requirements_test.txt (the pip source) and pyproject.toml (ruff/mypy config) — verified: the key changes when the baseline changes and is restored byte-for-byte with the file. User-Visible: no Issue: #42
This commit is contained in:
@@ -49,7 +49,13 @@ export const HARNESS = {
|
||||
|| /^demo\/benchmark_(glow|large_house)\.mjs$/.test(rel),
|
||||
},
|
||||
backend: {
|
||||
roots: ['tests_backend', 'custom_components', 'pytest.ini'],
|
||||
// #42: порог покрытия и пины зависимостей — прямые входы job
|
||||
// (`head -1 baseline` в шаге сравнения; `pip install -r`): их изменение
|
||||
// без правок тестов обязано сбрасывать реюз, иначе baseline-bump молча
|
||||
// пройдёт по старому зелёному маркеру.
|
||||
roots: ['tests_backend', 'custom_components', 'pytest.ini',
|
||||
'scripts/backend-coverage-baseline.txt', 'requirements_test.txt',
|
||||
'pyproject.toml'],
|
||||
// Внутри custom_components/** значим только Python: собранный фронтенд
|
||||
// лежит там же и меняется от любой сборки, а backend его не исполняет.
|
||||
keep: (rel) => !rel.startsWith('custom_components/') || rel.endsWith('.py'),
|
||||
|
||||
@@ -48,7 +48,19 @@ def _emitted_codes() -> tuple[set[str], set[str]]:
|
||||
r'(?:source_error|attribute_error)\s*=\s*"([a-z0-9_]+)"\s*if[^\n]*\\\s*\n\s*else\s*"([a-z0-9_]+)"',
|
||||
validation):
|
||||
fixed |= set(pair)
|
||||
fixed |= set(re.findall(r'"(invalid_(?:light|toggle)_entity)"', validation))
|
||||
# The literal-tuple path (field, code, message) is parsed STRUCTURALLY,
|
||||
# not by naming the two known codes: a third tuple entry with a brand-new
|
||||
# code must land in `fixed` (and so fail the registry test if the code is
|
||||
# unregistered). Fail-closed: a tuple block whose string count is not a
|
||||
# multiple of three means the shape changed — refuse instead of guessing.
|
||||
for block in re.findall(
|
||||
r'for field, code, message in \(\n(.*?)\n\s*\):', validation, re.S):
|
||||
strings = re.findall(r'"([^"]*)"', block)
|
||||
if not strings or len(strings) % 3:
|
||||
raise AssertionError(
|
||||
"unrecognized (field, code, message) tuple shape in validation.py: "
|
||||
f"{len(strings)} string literals — update the AC5 scanner")
|
||||
fixed |= set(strings[1::3])
|
||||
|
||||
families: set[str] = set()
|
||||
families |= {match + "_" if not match.endswith("_") else match
|
||||
|
||||
Reference in New Issue
Block a user