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:
@@ -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}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user