Files
ss-tools/backend/tests/test_logging_audit_fixes.py
2026-05-26 09:30:41 +03:00

116 lines
5.1 KiB
Python

# #region TestLoggingAuditFixes [C:3] [TYPE Module] [SEMANTICS test,logging,except,audit]
# @BRIEF Verify Class 2 fix — no bare `except: pass` patterns remain in src/.
# @RELATION BINDS_TO -> [EXT:frontend:PluginLoaderCore]
# @TEST_EDGE: except_pass_replaced -> bare `except: pass` patterns are absent from src/
# @TEST_EDGE: plugin_loader_uses_logger -> plugin_loader.py uses logger, not print
import ast
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
class TestLoggingAuditFixes:
"""Verify that all bare `except: pass` patterns have been replaced with proper logging."""
PLUGIN_LOADER_PATH = Path(__file__).parent.parent / "src" / "core" / "plugin_loader.py"
# #region _collect_src_files [C:1] [TYPE Function]
# @BRIEF Collect all .py files under src/ excluding test/ and mock/ directories.
@staticmethod
def _collect_src_files():
src_root = Path(__file__).parent.parent / "src"
return sorted(
p for p in src_root.rglob("*.py")
if "test" not in p.parts and "mock" not in p.parts and p.name != "__init__.py"
)
# #endregion _collect_src_files
# #region test_except_pass_replaced_with_log [C:2] [TYPE Function]
# @BRIEF AST audit: bare `except: pass` nodes are absent from src/ source files.
def test_except_pass_replaced_with_log(self):
files_with_bare_except_pass = []
for filepath in self._collect_src_files():
try:
tree = ast.parse(filepath.read_text(encoding="utf-8"), filename=str(filepath))
except SyntaxError:
continue
for node in ast.walk(tree):
if not isinstance(node, ast.ExceptHandler):
continue
if node.type is not None:
continue
if len(node.body) == 1 and isinstance(node.body[0], ast.Pass):
files_with_bare_except_pass.append(str(filepath))
break
assert not files_with_bare_except_pass, (
f"Bare `except: pass` found in {len(files_with_bare_except_pass)} file(s):\n"
+ "\n".join(files_with_bare_except_pass)
)
# #endregion test_except_pass_replaced_with_log
# #region test_plugin_loader_uses_logger_not_print [C:2] [TYPE Function]
# @BRIEF plugin_loader.py (src/core/) uses logger for error/warning, not print().
def test_plugin_loader_uses_logger_not_print(self):
code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8")
tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH))
# Find all print() calls in executable code
print_lines = []
for node in ast.walk(tree):
if (isinstance(node, ast.Call)
and isinstance(node.func, ast.Name)
and node.func.id == "print"):
print_lines.append(node.lineno)
assert len(print_lines) == 0, (
f"plugin_loader.py still contains print() calls at lines: {print_lines}"
)
# #endregion test_plugin_loader_uses_logger_not_print
# #region test_plugin_loader_imports_logger [C:2] [TYPE Function]
# @BRIEF plugin_loader.py imports a logger or _logger for structured reporting.
def test_plugin_loader_imports_logger(self):
code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8")
tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH))
has_logger_import = False
for node in ast.walk(tree):
if isinstance(node, (ast.Import, ast.ImportFrom)):
for alias in node.names:
if "logger" in alias.name.lower():
has_logger_import = True
break
assert has_logger_import, (
"plugin_loader.py should import 'logger' or '_logger' "
"for log-based error handling (instead of print)"
)
# #endregion test_plugin_loader_imports_logger
# #region test_plugin_loader_logger_calls_exist [C:2] [TYPE Function]
# @BRIEF plugin_loader.py references logger.error/warning/info in its code.
def test_plugin_loader_logger_calls_exist(self):
code = self.PLUGIN_LOADER_PATH.read_text(encoding="utf-8")
tree = ast.parse(code, filename=str(self.PLUGIN_LOADER_PATH))
logger_calls = []
for node in ast.walk(tree):
if (isinstance(node, ast.Call)
and isinstance(node.func, ast.Attribute)
and isinstance(node.func.value, ast.Name)
and "logger" in node.func.value.id.lower()):
logger_calls.append((node.lineno, node.func.attr))
error_levels = {"error", "warning", "info", "debug", "reason", "reflect", "explore"}
matching = [call for call in logger_calls if call[1] in error_levels]
assert len(matching) >= 4, (
f"plugin_loader.py has only {len(matching)} logger.error/warning/info calls "
f"(expected at least 4 for the 4 replaced print() statements): {matching}"
)
# #endregion test_plugin_loader_logger_calls_exist
# #endregion TestLoggingAuditFixes