From 291a0d283ec4f1410b71b6d82599439af76bd809 Mon Sep 17 00:00:00 2001 From: said Date: Sun, 24 May 2026 11:18:27 +0100 Subject: [PATCH] codex: restore c golden update mode --- .../c_parser_implementation_checklist.md | 3 +- docs/c_parser/c_parser_reference.md | 23 +++++++------- tests/parser/c/README.md | 10 +++---- tests/parser/c/test_c_error_fixture_suite.py | 30 +++++++++++++++++++ tests/parser/c/test_c_fixture_suite.py | 20 ++++++++++++- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/docs/c_parser/c_parser_implementation_checklist.md b/docs/c_parser/c_parser_implementation_checklist.md index e20409a16..c4357772d 100644 --- a/docs/c_parser/c_parser_implementation_checklist.md +++ b/docs/c_parser/c_parser_implementation_checklist.md @@ -408,7 +408,8 @@ Scope: inputs. - [x] Regenerate all fixtures with the standalone golden script. - [x] Regenerate selected fixtures with the standalone golden script. -- [x] Keep golden regeneration out of the comparison tests. +- [x] Regenerate full C golden suites from comparison tests when + `C_PARSER_UPDATE_GOLDENS=1` is set. - [x] Create a C error golden generator. - [x] Store expected error type, message fragments, diagnostic fragments, and parser entrypoint metadata. diff --git a/docs/c_parser/c_parser_reference.md b/docs/c_parser/c_parser_reference.md index 212c9bd51..cd81ce893 100644 --- a/docs/c_parser/c_parser_reference.md +++ b/docs/c_parser/c_parser_reference.md @@ -481,10 +481,10 @@ resolution. The `json` regression inputs intentionally retain recoverable diagnostics from unsupported constructs; they do not claim complete library parsing. Remaining parser-suite skips cover the pinned/provenanced corpus target and compiler-preprocessed `.i`/`#line` -behavior; golden inventory checks also skip deliberately while update mode is -rewriting their baselines. Future implementation branches should activate only -the tests for the capability they implement, then merge those branches back -into `c-parser/main`. +behavior. Golden comparison tests rewrite their baselines when +`C_PARSER_UPDATE_GOLDENS=1` is set. Future implementation branches should +activate only the tests for the capability they implement, then merge those +branches back into `c-parser/main`. ### Declaration Coverage Boundary @@ -567,15 +567,12 @@ headers, such as `nanosvg.h` before `nanosvgrast.h`; an input without a sibling is parsed as a one-file project. Golden filenames use the project stem, such as `api.json` or `jsmn.json`. Goldens can be regenerated for all active projects with -`python -m tests.parser.c.generate_c_parser_goldens` or for selected paths -relative to `tests/data/c/` by adding either member filename; any matching -sibling is included automatically. Fatal diagnostic goldens are regenerated -with -`python -m tests.parser.c.errors.generate_c_parser_error_goldens`. -The parser goldens are regenerated by the standalone scripts above, not by -the comparison tests. Until include-expanded parsing is implemented, a paired -project records the source-to-header include edge but parses the `.c` and -`.h` members separately. +`C_PARSER_UPDATE_GOLDENS=1 PYTHONPATH=. pytest -q tests/parser/c/test_c_fixture_suite.py`. +Fatal diagnostic goldens are regenerated with +`C_PARSER_UPDATE_GOLDENS=1 PYTHONPATH=. pytest -q tests/parser/c/test_c_error_fixture_suite.py`. +The standalone generator modules remain available for targeted refreshes. +Until include-expanded parsing is implemented, a paired project records the +source-to-header include edge but parses the `.c` and `.h` members separately. STB is treated as a family of independent single-file libraries: each top-level `.h` or `.c` input generates its own one-file project golden rather diff --git a/tests/parser/c/README.md b/tests/parser/c/README.md index 6303bd4b7..446e796ab 100644 --- a/tests/parser/c/README.md +++ b/tests/parser/c/README.md @@ -49,7 +49,7 @@ produces `nanosvg.json`; STB produces one golden per top-level library input. Regenerate all parser goldens with: ```bash -python -m tests.parser.c.generate_c_parser_goldens +C_PARSER_UPDATE_GOLDENS=1 PYTHONPATH=. pytest -q tests/parser/c/test_c_fixture_suite.py ``` Regenerate selected projects by naming either input relative to @@ -65,9 +65,9 @@ Fatal diagnostic fixtures live in `tests/data/c/errors/parser/` and their expected metadata lives in `fixtures/errors/`. Regenerate them with: ```bash -python -m tests.parser.c.errors.generate_c_parser_error_goldens +C_PARSER_UPDATE_GOLDENS=1 PYTHONPATH=. pytest -q tests/parser/c/test_c_error_fixture_suite.py ``` -The comparison tests are read-only. Regenerate the expected files with the -standalone generator, then rerun the tests to compare against the checked-in -baselines. +The standalone generator modules remain available for targeted refreshes, but +the comparison tests also rewrite their checked-in baselines when +`C_PARSER_UPDATE_GOLDENS=1` is set. diff --git a/tests/parser/c/test_c_error_fixture_suite.py b/tests/parser/c/test_c_error_fixture_suite.py index 5dfcc9a81..690b06fd4 100644 --- a/tests/parser/c/test_c_error_fixture_suite.py +++ b/tests/parser/c/test_c_error_fixture_suite.py @@ -2,6 +2,7 @@ """C parser error fixture and diagnostic golden regression tests.""" import json +import os from pathlib import Path import pytest @@ -21,6 +22,25 @@ def _load_expected_error(expected_path: Path) -> dict: return json.loads(expected_path.read_text(encoding="utf-8")) +def _dump_expected_error(path: Path, error_type: str, exc, parser: str) -> None: + payload = { + "parser": parser, + "error_type": error_type, + "message_contains": [exc.base_message], + "diagnostic_contains": [ + f"error[{exc.code}]", + exc.base_message, + exc.source_line.strip() if exc.source_line else "", + ], + } + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") + + +def _update_mode_enabled() -> bool: + return os.getenv("C_PARSER_UPDATE_GOLDENS", "0") == "1" + + def test_c_error_fixture_suite_has_fixtures(): fixtures = [path for path in _ERRORS_DIR.glob("*") if path.suffix.lower() in _SOURCE_SUFFIXES] assert fixtures, "No C parser error fixtures found in tests/data/c/errors/parser" @@ -47,6 +67,16 @@ def test_c_error_fixture_suite_reports_expected_diagnostics(): expected_path = _expected_path_for_fixture(fixture) source = fixture.read_text(encoding="utf-8") + if _update_mode_enabled(): + try: + parse_c_file(source, filename=fixture.name) + raise AssertionError( + f"Expected CParseError from {fixture.name} but no error was raised" + ) + except CParseError as exc: + _dump_expected_error(expected_path, "CParseError", exc, "parse_c_file") + continue + expected = _load_expected_error(expected_path) assert expected["parser"] == "parse_c_file" assert expected["error_type"] == "CParseError" diff --git a/tests/parser/c/test_c_fixture_suite.py b/tests/parser/c/test_c_fixture_suite.py index be550f0e6..46718dc48 100644 --- a/tests/parser/c/test_c_fixture_suite.py +++ b/tests/parser/c/test_c_fixture_suite.py @@ -2,6 +2,7 @@ """C parser grouped-project fixture/golden regression tests.""" import json +import os from pathlib import Path import pytest @@ -64,6 +65,15 @@ def _expected_path_for_project(data_subdir: str, project_key: Path) -> Path: return (_FIXTURES_DIR / data_subdir / project_key).with_suffix(".json") +def _load_expected(expected_path: Path) -> dict: + return json.loads(expected_path.read_text(encoding="utf-8")) + + +def _dump_expected(path: Path, parsed: dict) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(parsed, indent=2) + "\n", encoding="utf-8") + + def _normalize_resolved_paths(value): if isinstance(value, dict): resolved_path = value.get("resolved_path") @@ -101,6 +111,10 @@ def _serialize_project(fixtures: list[Path]) -> dict: return _normalize_resolved_paths(_parse_project(fixtures).to_dict()) +def _update_mode_enabled() -> bool: + return os.getenv("C_PARSER_UPDATE_GOLDENS", "0") == "1" + + @pytest.mark.parametrize("data_subdir", _FIXTURE_GROUPS) def test_c_fixture_golden_suite_has_inputs(data_subdir): fixtures = sorted((_DATA_DIR / data_subdir).glob("*")) @@ -125,7 +139,11 @@ def test_c_fixture_golden_suite_compares_project_json(data_subdir): expected_path = _expected_path_for_project(data_subdir, project_key) parsed = _serialize_project(fixtures) - expected = json.loads(expected_path.read_text(encoding="utf-8")) + if _update_mode_enabled(): + _dump_expected(expected_path, parsed) + continue + + expected = _load_expected(expected_path) assert parsed == expected