- golden_helpers, scripts/golden_update.py (--check), test_golden на 66 ОСВ и синтетике; make golden-update/golden-check/test-fixtures - тест покрытия словарей (R-22): счётчик срабатываний Pattern; из osv_headers.yaml удалены неиспользуемые service_columns kpp/code/quantity/currency - синтетика s14–s16 в генераторе и таблице ожиданий; skip вместо падения при отсутствии osv/synthetic (T11.1); комментарий R-21 в s07 (T11.2) - линтер: предел адреса 10 вместо 4 (T3.1), обращение cell(3, 4) (T3.8); реальные файлы не фиксируют BU/RUB (T3.9) - README: golden-процесс; отмечены Task 12 и пункты 4.2, 4.3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
64 lines
3.0 KiB
Python
64 lines
3.0 KiB
Python
"""Golden-снимки разбора (design D-10): результат парсера для каждого файла `fixtures/osv/**` и синтетики равен
|
||
снимку в `fixtures/golden/expected_osv_parse/` (зеркало дерева `osv/`), без volatile-полей.
|
||
|
||
Снимок — регрессия, а не оракул (оракулы — ручная сверка «Итого» и property-тест). Обновление — `make golden-update`,
|
||
отдельным коммитом в репозиторий fixtures с просмотром diff.
|
||
"""
|
||
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
from golden_helpers import golden_path, render, snapshot_text, unified_diff
|
||
|
||
from src.parser import Parser, get_parser
|
||
|
||
pytestmark = pytest.mark.fixtures
|
||
|
||
MISSING = "нет снимка: выполните make golden-update ({path})"
|
||
MAX_DIFF_CHARS = 6000
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def parser() -> Parser:
|
||
return get_parser()
|
||
|
||
|
||
def check_snapshot(fixtures_dir: Path, file: Path, parser: Parser) -> None:
|
||
snapshot = golden_path(fixtures_dir, file)
|
||
if not snapshot.is_file():
|
||
pytest.fail(MISSING.format(path=snapshot.relative_to(fixtures_dir).as_posix()), pytrace=False)
|
||
stored = snapshot.read_text(encoding="utf-8")
|
||
current = snapshot_text(render(parser, file))
|
||
if stored != current:
|
||
diff = unified_diff(stored, current, name=snapshot.relative_to(fixtures_dir).as_posix())
|
||
if len(diff) > MAX_DIFF_CHARS:
|
||
diff = (
|
||
diff[:MAX_DIFF_CHARS] + f"\n… (diff обрезан, всего {len(diff)} символов; полный — make golden-update)"
|
||
)
|
||
pytest.fail(
|
||
"результат разбора отличается от снимка (намеренная правка парсера — make golden-update и коммит "
|
||
f"в fixtures с просмотром diff):\n{diff}",
|
||
pytrace=False,
|
||
)
|
||
|
||
|
||
def test_osv_file_matches_golden_snapshot(fixtures_dir: Path, osv_file: Path, parser: Parser) -> None:
|
||
check_snapshot(fixtures_dir, osv_file, parser)
|
||
|
||
|
||
def test_synthetic_file_matches_golden_snapshot(fixtures_dir: Path, synthetic_file: Path, parser: Parser) -> None:
|
||
check_snapshot(fixtures_dir, synthetic_file, parser)
|
||
|
||
|
||
def test_every_snapshot_has_a_source_file(fixtures_dir: Path) -> None:
|
||
"""Лишний снимок (файл удалён или переименован) — ошибка: `make golden-update` его удаляет."""
|
||
from fixtures_helpers import osv_fixture_files, synthetic_files # noqa: PLC0415 - только для этого теста
|
||
|
||
expected = {
|
||
golden_path(fixtures_dir, file) for file in [*osv_fixture_files(fixtures_dir), *synthetic_files(fixtures_dir)]
|
||
}
|
||
directory = fixtures_dir / "golden" / "expected_osv_parse"
|
||
present = set(directory.rglob("*.json")) if directory.is_dir() else set()
|
||
|
||
assert sorted(path.relative_to(fixtures_dir).as_posix() for path in present - expected) == []
|