221 lines
6.6 KiB
Python
221 lines
6.6 KiB
Python
"""Tests for code fixers."""
|
|
|
|
import pytest
|
|
from pathlib import Path
|
|
|
|
from src.analyzers.base import SeverityLevel, FindingCategory
|
|
from src.fixers import (
|
|
SQLInjectionFixer,
|
|
EvalUsageFixer,
|
|
ExceptionSwallowFixer,
|
|
MagicNumberFixer,
|
|
RedundantOperationFixer,
|
|
)
|
|
|
|
|
|
class TestSQLInjectionFixer:
|
|
"""Tests for SQL injection fixer."""
|
|
|
|
def setup_method(self):
|
|
self.fixer = SQLInjectionFixer()
|
|
|
|
def test_fixes_sql_injection(self):
|
|
code = 'cursor.execute("SELECT * FROM users WHERE name = \'" + user_input + "\'")'
|
|
finding = self._create_finding()
|
|
tree = self._parse_code(code)
|
|
result = self.fixer.fix(code, finding, tree)
|
|
assert "?" in result or '"' in result
|
|
|
|
def _create_finding(self):
|
|
from src.analyzers.base import Finding
|
|
return Finding(
|
|
rule_id="security.sql_injection",
|
|
rule_name="SQL Injection Detection",
|
|
severity=SeverityLevel.CRITICAL,
|
|
category=FindingCategory.SECURITY,
|
|
message="SQL injection detected",
|
|
suggestion="Use parameterized queries",
|
|
file_path=Path("test.py"),
|
|
line_number=1,
|
|
column=0,
|
|
)
|
|
|
|
def _parse_code(self, code):
|
|
from src.analyzers import PythonParser
|
|
parser = PythonParser()
|
|
return parser.parse(code)
|
|
|
|
|
|
class TestEvalUsageFixer:
|
|
"""Tests for eval/exec fixer."""
|
|
|
|
def setup_method(self):
|
|
self.fixer = EvalUsageFixer()
|
|
|
|
def test_comments_out_eval(self):
|
|
code = 'result = eval(user_input)'
|
|
finding = self._create_finding()
|
|
tree = self._parse_code(code)
|
|
result = self.fixer.fix(code, finding, tree)
|
|
assert "# eval(" in result
|
|
|
|
def _create_finding(self):
|
|
from src.analyzers.base import Finding
|
|
return Finding(
|
|
rule_id="security.eval_usage",
|
|
rule_name="Eval Usage Detection",
|
|
severity=SeverityLevel.CRITICAL,
|
|
category=FindingCategory.SECURITY,
|
|
message="eval detected",
|
|
suggestion="Avoid eval",
|
|
file_path=Path("test.py"),
|
|
line_number=1,
|
|
column=0,
|
|
)
|
|
|
|
def _parse_code(self, code):
|
|
from src.analyzers import PythonParser
|
|
parser = PythonParser()
|
|
return parser.parse(code)
|
|
|
|
|
|
class TestExceptionSwallowFixer:
|
|
"""Tests for exception swallowing fixer."""
|
|
|
|
def setup_method(self):
|
|
self.fixer = ExceptionSwallowFixer()
|
|
|
|
def test_adds_exception_logging(self):
|
|
code = """try:
|
|
dangerous()
|
|
except:
|
|
pass
|
|
"""
|
|
finding = self._create_finding()
|
|
tree = self._parse_code(code)
|
|
result = self.fixer.fix(code, finding, tree)
|
|
assert "logger.error" in result or "Exception as e" in result
|
|
|
|
def _create_finding(self):
|
|
from src.analyzers.base import Finding
|
|
return Finding(
|
|
rule_id="antipattern.exception_swallow",
|
|
rule_name="Exception Swallow Detection",
|
|
severity=SeverityLevel.MEDIUM,
|
|
category=FindingCategory.ANTIPATTERN,
|
|
message="Exception swallowing detected",
|
|
suggestion="Log the exception",
|
|
file_path=Path("test.py"),
|
|
line_number=2,
|
|
column=0,
|
|
)
|
|
|
|
def _parse_code(self, code):
|
|
from src.analyzers import PythonParser
|
|
parser = PythonParser()
|
|
return parser.parse(code)
|
|
|
|
|
|
class TestMagicNumberFixer:
|
|
"""Tests for magic number fixer."""
|
|
|
|
def setup_method(self):
|
|
self.fixer = MagicNumberFixer()
|
|
|
|
def test_replaces_magic_number(self):
|
|
code = "result = 42"
|
|
finding = self._create_finding()
|
|
tree = self._parse_code(code)
|
|
result = self.fixer.fix(code, finding, tree)
|
|
assert "MAGIC_NUMBER_42" in result
|
|
|
|
def _create_finding(self):
|
|
from src.analyzers.base import Finding
|
|
return Finding(
|
|
rule_id="antipattern.magic_number",
|
|
rule_name="Magic Number Detection",
|
|
severity=SeverityLevel.LOW,
|
|
category=FindingCategory.ANTIPATTERN,
|
|
message="Magic number detected",
|
|
suggestion="Define as constant",
|
|
file_path=Path("test.py"),
|
|
line_number=1,
|
|
column=0,
|
|
)
|
|
|
|
def _parse_code(self, code):
|
|
from src.analyzers import PythonParser
|
|
parser = PythonParser()
|
|
return parser.parse(code)
|
|
|
|
|
|
class TestRedundantOperationFixer:
|
|
"""Tests for redundant operation fixer."""
|
|
|
|
def setup_method(self):
|
|
self.fixer = RedundantOperationFixer()
|
|
|
|
def test_removes_redundant_list_call(self):
|
|
code = "result = list(list(my_list))"
|
|
finding = self._create_finding()
|
|
tree = self._parse_code(code)
|
|
result = self.fixer.fix(code, finding, tree)
|
|
assert "list(list(" not in result
|
|
|
|
def _create_finding(self):
|
|
from src.analyzers.base import Finding
|
|
return Finding(
|
|
rule_id="performance.redundant_operation",
|
|
rule_name="Redundant Operation Detection",
|
|
severity=SeverityLevel.LOW,
|
|
category=FindingCategory.PERFORMANCE,
|
|
message="Redundant operation detected",
|
|
suggestion="Remove redundant call",
|
|
file_path=Path("test.py"),
|
|
line_number=1,
|
|
column=0,
|
|
)
|
|
|
|
def _parse_code(self, code):
|
|
from src.analyzers import PythonParser
|
|
parser = PythonParser()
|
|
return parser.parse(code)
|
|
|
|
|
|
class TestFixerRegistry:
|
|
"""Tests for fixer registry."""
|
|
|
|
def test_get_fixer_returns_correct_fixer(self):
|
|
from src.fixers import FixerRegistry
|
|
registry = FixerRegistry()
|
|
fixer = registry.get_fixer("security.sql_injection")
|
|
assert fixer is not None
|
|
assert isinstance(fixer, SQLInjectionFixer)
|
|
|
|
def test_get_fixer_returns_none_for_unknown_rule(self):
|
|
from src.fixers import FixerRegistry
|
|
registry = FixerRegistry()
|
|
fixer = registry.get_fixer("unknown.rule_id")
|
|
assert fixer is None
|
|
|
|
def test_can_fix_checks_correctly(self):
|
|
from src.fixers import FixerRegistry
|
|
from src.analyzers.base import Finding
|
|
registry = FixerRegistry()
|
|
|
|
finding = Finding(
|
|
rule_id="security.sql_injection",
|
|
rule_name="Test",
|
|
severity=SeverityLevel.CRITICAL,
|
|
category=FindingCategory.SECURITY,
|
|
message="Test",
|
|
suggestion="Test",
|
|
file_path=Path("test.py"),
|
|
line_number=1,
|
|
column=0,
|
|
)
|
|
assert registry.can_fix(finding) is True
|
|
|
|
finding.rule_id = "unknown.rule"
|
|
assert registry.can_fix(finding) is False
|