Private
Public Access
0
0

test(audit_heuristics): add 5 regression tests for dunder raise (Phase 11)

Five regression-guard tests verify the new dunder-method bare-raise
heuristic in scripts/audit_exception_handling.py:_classify_raise:
- test_bare_raise_attribute_error_in_getattr_is_programmer_raise
- test_bare_raise_name_error_in_getattr_is_programmer_raise
- test_bare_raise_in_setattr_is_programmer_raise
- test_bare_raise_in_delattr_is_programmer_raise
- test_bare_raise_in_getattribute_is_programmer_raise

Each test feeds a minimal source sample through the visitor's
_classify_raise and asserts INTERNAL_PROGRAMMER_RAISE. The tests
cover all 4 dunder methods (__getattr__, __getattribute__,
__setattr__, __delattr__) and both programmer-error exception types
(AttributeError, NameError).

Phase 11 result_migration_gui_2_20260619.
This commit is contained in:
2026-06-20 01:57:33 -04:00
parent 6e03f5aee3
commit a5a06f8516
+84
View File
@@ -137,3 +137,87 @@ def test_phase7_migrated_sites_no_longer_silent_swallow():
f"Phase 7 regression: L{f.line} should not be "
f"INTERNAL_SILENT_SWALLOW after migration; got {f.category}"
)
# Phase 11 Task 11.4 - Regression-guard tests for dunder-method bare-raise heuristic.
# Per Phase 11 spec (INTERNAL_RETHROW classification for dunder methods):
# - Bare `raise AttributeError(name)` / `raise NameError(name)` in
# `__getattr__`, `__getattribute__`, `__setattr__`, `__delattr__` is the
# canonical dunder-method programmer-error pattern (per styleguide
# "Re-Raise Patterns": bare raises are reserved for programmer errors).
# - The audit previously classified these as INTERNAL_RETHROW (suspicious);
# the heuristic must reclassify them as INTERNAL_PROGRAMMER_RAISE.
DUNDER_RAISE_TESTS = {
"__getattr__": "def __getattr__(self, name):\n if name == 'controller':\n raise AttributeError(name)\n raise AttributeError(name)",
"__getattribute__": "def __getattribute__(self, name):\n if name == 'controller':\n raise AttributeError(name)\n raise AttributeError(name)",
"__setattr__": "def __setattr__(self, name, value):\n raise AttributeError(name)",
"__delattr__": "def __delattr__(self, name):\n raise AttributeError(name)",
}
def _classify_first_raise(source, func_name):
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == func_name:
visitor = ExceptionVisitor(str(ROOT / "src" / "_test_dummy.py"))
visitor._func_stack = [node]
for sub in ast.walk(node):
if isinstance(sub, ast.Raise) and sub.exc is not None:
return visitor._classify_raise(sub)
raise AssertionError(f"No raise found in {func_name}")
def test_bare_raise_attribute_error_in_getattr_is_programmer_raise():
src = DUNDER_RAISE_TESTS["__getattr__"]
category, hint = _classify_first_raise(src, "__getattr__")
assert category == "INTERNAL_PROGRAMMER_RAISE", (
f"Phase 11 regression: bare `raise AttributeError(name)` in __getattr__ "
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
f"got {category}. Hint: {hint}"
)
def test_bare_raise_name_error_in_getattr_is_programmer_raise():
src = (
"def __getattr__(self, name):\n"
" if not hasattr(self, 'x'):\n"
" raise NameError(name)\n"
" return self.x"
)
category, hint = _classify_first_raise(src, "__getattr__")
assert category == "INTERNAL_PROGRAMMER_RAISE", (
f"Phase 11 regression: bare `raise NameError(name)` in __getattr__ "
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
f"got {category}. Hint: {hint}"
)
def test_bare_raise_in_setattr_is_programmer_raise():
src = DUNDER_RAISE_TESTS["__setattr__"]
category, hint = _classify_first_raise(src, "__setattr__")
assert category == "INTERNAL_PROGRAMMER_RAISE", (
f"Phase 11 regression: bare `raise AttributeError` in __setattr__ "
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
f"got {category}. Hint: {hint}"
)
def test_bare_raise_in_delattr_is_programmer_raise():
src = DUNDER_RAISE_TESTS["__delattr__"]
category, hint = _classify_first_raise(src, "__delattr__")
assert category == "INTERNAL_PROGRAMMER_RAISE", (
f"Phase 11 regression: bare `raise AttributeError` in __delattr__ "
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
f"got {category}. Hint: {hint}"
)
def test_bare_raise_in_getattribute_is_programmer_raise():
src = DUNDER_RAISE_TESTS["__getattribute__"]
category, hint = _classify_first_raise(src, "__getattribute__")
assert category == "INTERNAL_PROGRAMMER_RAISE", (
f"Phase 11 regression: bare `raise AttributeError(name)` in __getattribute__ "
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
f"got {category}. Hint: {hint}"
)