Skip to content

Commit 26c3023

Browse files
Sort the scanned-errors map so the catalog is reproducible
The objectModel errors "raises" map is keyed by iterating the public function set, whose order is hash-seed dependent, so run.py emitted the catalog with a different key order each run: two runs over the same input were byte-different, and any regenerate-and-check-byte-identical flow saw spurious diffs. Sort the iteration so the map keys are stable; a test asserts the scanned-errors keys come out sorted.
1 parent e9eda42 commit 26c3023

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

parser/object_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ def _scan_errors(src_root: Path, public: set) -> dict:
270270
ensure_codes = {f: v["direct"] for f, v in raw.items()
271271
if f.startswith("ensure_")}
272272
result = {}
273-
for fn in public:
273+
for fn in sorted(public):
274274
rec = raw.get(fn)
275275
if not rec:
276276
continue

tests/test_object_model.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
import json
1212
import re
1313
import sys
14+
import tempfile
1415
import unittest
1516
from pathlib import Path
1617

1718
ROOT = Path(__file__).resolve().parents[1]
1819
sys.path.insert(0, str(ROOT))
1920

20-
from parser.object_model import attach_object_model, find_mobilitydb_src
21+
from parser.object_model import (
22+
_scan_errors, attach_object_model, find_mobilitydb_src)
2123

2224
MODEL = ROOT / "meta" / "object-model.json"
2325
_INTERNAL = {"T_TDOUBLE2", "T_TDOUBLE3", "T_TDOUBLE4"} # not public classes
@@ -198,6 +200,24 @@ def test_errors_source_unavailable_is_honest(self):
198200
self.assertEqual(om["errors"]["raises"], {}) # not fabricated
199201
self.assertEqual(len(om["errors"]["codes"]), 21)
200202

203+
def test_scanned_errors_are_sorted_for_reproducibility(self):
204+
# The raises map is keyed by the public function set; iterating a set is
205+
# hash-seed dependent, so the keys are sorted to keep the emitted catalog
206+
# byte-identical across runs.
207+
src = (
208+
'Datum zzz_fn(int x) {\n'
209+
' meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, "bad");\n}\n'
210+
'Datum aaa_fn(int y) {\n'
211+
' meos_error(ERROR, MEOS_ERR_INVALID_ARG_TYPE, "bad");\n}\n'
212+
'Datum mmm_fn(int z) {\n'
213+
' meos_error(ERROR, MEOS_ERR_INVALID_ARG_VALUE, "bad");\n}\n'
214+
)
215+
with tempfile.TemporaryDirectory() as d:
216+
(Path(d) / "x.c").write_text(src)
217+
result = _scan_errors(Path(d), {"zzz_fn", "aaa_fn", "mmm_fn"})
218+
self.assertEqual(list(result), ["aaa_fn", "mmm_fn", "zzz_fn"])
219+
self.assertEqual(list(result), sorted(result))
220+
201221

202222
# ---------------------------------------------------------------------------
203223
# Drift gate: the curated lattice must equal what MEOS actually defines.

0 commit comments

Comments
 (0)