test(audit_heuristics): add 3 regression tests for lazy-loading (Phase 12)
Three regression-guard tests in tests/test_audit_heuristics.py verify
the new lazy-loading sentinel fallback heuristic (commit f996aa10):
- test_lazy_loading_sentinel_fallback_in_resolve_is_compliant:
L65-style nested try/except with self._cached = _FiledialogStub()
in _resolve (mirrors the actual site in src/gui_2.py:65)
-> expects INTERNAL_COMPLIANT
- test_lazy_loading_sentinel_fallback_in_load_is_compliant:
direct self._cached = _FooStub() in _load
-> expects INTERNAL_COMPLIANT
- test_lazy_loading_sentinel_fallback_in_get_is_compliant:
direct self._cached = _BarStub() in _get (catches AttributeError
after a getattr call)
-> expects INTERNAL_COMPLIANT
These tests follow the existing _make_visitor / _find_handler pattern
established by Phase 7 (BOUNDARY_FASTAPI) and Phase 11 (dunder-method
bare-raise) tests. They lock the heuristic's behavior so future edits
to scripts/audit_exception_handling.py cannot accidentally reclassify
the 2 gui_2.py sites (L65, L69) back to UNCLEAR.
Pre-Phase 12: 3 tests in this file (Phase 7 + Phase 11).
Post-Phase 12: 6 tests. 13/13 tests pass (3 new + 10 existing).
Phase 12 result_migration_gui_2_20260619.
This commit is contained in:
@@ -221,3 +221,78 @@ def test_bare_raise_in_getattribute_is_programmer_raise():
|
||||
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||
f"got {category}. Hint: {hint}"
|
||||
)
|
||||
|
||||
|
||||
# Phase 12 Task 12.1 - Regression-guard tests for the lazy-loading sentinel
|
||||
# fallback heuristic.
|
||||
# Per Phase 12 spec (INTERNAL_COMPLIANT classification for lazy-loading
|
||||
# sentinel fallbacks in methods named _resolve/_load/_get/_try_load):
|
||||
# - The except body must NOT re-raise
|
||||
# - The except body must assign to a self.<attr> (directly or via nested try)
|
||||
# - The except set must be in {AttributeError, ImportError, ModuleNotFoundError}
|
||||
# - The enclosing function name must be in the lazy-loader set
|
||||
# Pre-Phase 12 baseline: 2 UNCLEAR sites in src/gui_2.py at L65, L69
|
||||
# (both in _LazyModule._resolve). Post-Phase 12: 0 UNCLEAR.
|
||||
|
||||
def test_lazy_loading_sentinel_fallback_in_resolve_is_compliant():
|
||||
src = (
|
||||
"def _resolve(self):\n"
|
||||
" try:\n"
|
||||
" self._cached = getattr(self._mod, self._attr_name)\n"
|
||||
" except AttributeError:\n"
|
||||
" try:\n"
|
||||
" self._cached = _importlib.import_module(self._sub_name)\n"
|
||||
" except (ImportError, ModuleNotFoundError):\n"
|
||||
" self._cached = _FiledialogStub()\n"
|
||||
" return self._cached\n"
|
||||
)
|
||||
visitor = _make_visitor(src, "_resolve")
|
||||
try_node = _find_handler(visitor)
|
||||
handler = try_node.handlers[0]
|
||||
category, hint = visitor._classify_except(handler, try_node)
|
||||
assert category == "INTERNAL_COMPLIANT", (
|
||||
f"Phase 12 regression: lazy-loading sentinel fallback in `_resolve` "
|
||||
f"(L65-style nested try with `self._cached = _FiledialogStub()`) "
|
||||
f"should be INTERNAL_COMPLIANT (canonical graceful-degradation pattern); "
|
||||
f"got {category}. Hint: {hint}"
|
||||
)
|
||||
|
||||
|
||||
def test_lazy_loading_sentinel_fallback_in_load_is_compliant():
|
||||
src = (
|
||||
"def _load(self, name):\n"
|
||||
" try:\n"
|
||||
" self._cached = _importlib.import_module(name)\n"
|
||||
" except (ImportError, ModuleNotFoundError):\n"
|
||||
" self._cached = _FooStub()\n"
|
||||
" return self._cached\n"
|
||||
)
|
||||
visitor = _make_visitor(src, "_load")
|
||||
try_node = _find_handler(visitor)
|
||||
handler = try_node.handlers[0]
|
||||
category, hint = visitor._classify_except(handler, try_node)
|
||||
assert category == "INTERNAL_COMPLIANT", (
|
||||
f"Phase 12 regression: lazy-loading sentinel fallback in `_load` "
|
||||
f"(direct `self._cached = _FooStub()`) should be INTERNAL_COMPLIANT "
|
||||
f"(canonical graceful-degradation pattern); got {category}. Hint: {hint}"
|
||||
)
|
||||
|
||||
|
||||
def test_lazy_loading_sentinel_fallback_in_get_is_compliant():
|
||||
src = (
|
||||
"def _get(self, attr_name):\n"
|
||||
" try:\n"
|
||||
" return getattr(self._module, attr_name)\n"
|
||||
" except AttributeError:\n"
|
||||
" self._cached = _BarStub()\n"
|
||||
" return self._cached\n"
|
||||
)
|
||||
visitor = _make_visitor(src, "_get")
|
||||
try_node = _find_handler(visitor)
|
||||
handler = try_node.handlers[0]
|
||||
category, hint = visitor._classify_except(handler, try_node)
|
||||
assert category == "INTERNAL_COMPLIANT", (
|
||||
f"Phase 12 regression: lazy-loading sentinel fallback in `_get` "
|
||||
f"(direct `self._cached = _BarStub()`) should be INTERNAL_COMPLIANT "
|
||||
f"(canonical graceful-degradation pattern); got {category}. Hint: {hint}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user