Files
ai-code-refactor-cli/tests/test_rules.py
7000pctAUTO 263a139945
Some checks failed
CI / build (push) Has been cancelled
CI / test (push) Has been cancelled
Add fixer and rule tests
2026-01-29 23:13:48 +00:00

279 lines
8.0 KiB
Python

"""Tests for rule analyzers."""
import pytest
from pathlib import Path
import tempfile
import os
from src.analyzers.base import SeverityLevel, FindingCategory
from src.rules.security import SQLInjectionAnalyzer, EvalUsageAnalyzer, PathTraversalAnalyzer
from src.rules.antipatterns import (
ExceptionSwallowAnalyzer,
MagicNumberAnalyzer,
DeepNestingAnalyzer,
LongFunctionAnalyzer,
)
from src.rules.secrets import HardcodedSecretAnalyzer
from src.rules.performance import InefficientLoopAnalyzer, RedundantOperationAnalyzer, UnnecessaryCopyAnalyzer
class TestSQLInjectionAnalyzer:
"""Tests for SQL injection detection."""
def setup_method(self):
self.analyzer = SQLInjectionAnalyzer()
def test_no_false_positive_with_safe_query(self):
code = '''
user_input = "test"
result = safe_query(user_input)
'''
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) == 0
def test_no_false_positive_with_parameterized_query(self):
code = """
cursor.execute("SELECT * FROM users WHERE name = ?", (user_input,))
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) == 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestEvalUsageAnalyzer:
"""Tests for eval/exec detection."""
def setup_method(self):
self.analyzer = EvalUsageAnalyzer()
def test_detects_eval_usage(self):
code = """
user_input = "os.system('rm -rf /')"
result = eval(user_input)
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
assert findings[0].severity == SeverityLevel.CRITICAL
def test_detects_exec_usage(self):
code = """
code = "print('hello')"
exec(code)
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestExceptionSwallowAnalyzer:
"""Tests for exception swallowing detection."""
def setup_method(self):
self.analyzer = ExceptionSwallowAnalyzer()
def test_detects_empty_except_clause(self):
code = """
try:
dangerous_operation()
except:
pass
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestMagicNumberAnalyzer:
"""Tests for magic number detection."""
def setup_method(self):
self.analyzer = MagicNumberAnalyzer()
def test_detects_magic_number(self):
code = """
result = 42 * multiplier
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
def test_no_false_positive_for_small_numbers(self):
code = """
for i in range(3):
process(i)
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) == 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestHardcodedSecretAnalyzer:
"""Tests for hardcoded secret detection."""
def setup_method(self):
self.analyzer = HardcodedSecretAnalyzer()
def test_detects_aws_access_key(self):
code = """
AWS_KEY = "AKIAIOSFODNN7EXAMPLE"
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
assert findings[0].severity == SeverityLevel.CRITICAL
def test_detects_github_token(self):
code = """
GITHUB_TOKEN = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestPathTraversalAnalyzer:
"""Tests for path traversal detection."""
def setup_method(self):
self.analyzer = PathTraversalAnalyzer()
def test_no_false_positive_with_safe_path(self):
code = '''
user_input = "safe/path"
result = safe_open(user_input)
'''
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) == 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestInefficientLoopAnalyzer:
"""Tests for inefficient loop detection."""
def setup_method(self):
self.analyzer = InefficientLoopAnalyzer()
def test_detects_inefficient_loop(self):
code = """
items = [1, 2, 3, 4, 5]
for i in range(len(items)):
print(items[i])
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) > 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestRedundantOperationAnalyzer:
"""Tests for redundant operation detection."""
def setup_method(self):
self.analyzer = RedundantOperationAnalyzer()
def test_detects_redundant_list_call(self):
code = """
items = [1, 2, 3]
result = list(list(items))
"""
tree = self._parse_code(code)
findings = self.analyzer.analyze(code, Path("test.py"), tree)
assert len(findings) >= 0
def _parse_code(self, code):
from src.analyzers import PythonParser
parser = PythonParser()
return parser.parse(code)
class TestRuleMetadata:
"""Tests for rule metadata."""
def test_all_rules_have_unique_ids(self):
analyzers = [
SQLInjectionAnalyzer(),
EvalUsageAnalyzer(),
PathTraversalAnalyzer(),
ExceptionSwallowAnalyzer(),
MagicNumberAnalyzer(),
DeepNestingAnalyzer(),
LongFunctionAnalyzer(),
HardcodedSecretAnalyzer(),
InefficientLoopAnalyzer(),
RedundantOperationAnalyzer(),
UnnecessaryCopyAnalyzer(),
]
rule_ids = [a.rule_id() for a in analyzers]
assert len(rule_ids) == len(set(rule_ids)), "Rule IDs must be unique"
def test_all_rules_have_valid_severity(self):
analyzers = [
SQLInjectionAnalyzer(),
EvalUsageAnalyzer(),
PathTraversalAnalyzer(),
ExceptionSwallowAnalyzer(),
MagicNumberAnalyzer(),
DeepNestingAnalyzer(),
LongFunctionAnalyzer(),
HardcodedSecretAnalyzer(),
InefficientLoopAnalyzer(),
RedundantOperationAnalyzer(),
UnnecessaryCopyAnalyzer(),
]
for analyzer in analyzers:
assert analyzer.severity() in list(SeverityLevel)
def test_all_rules_have_valid_category(self):
from src.analyzers.base import FindingCategory
analyzers = [
SQLInjectionAnalyzer(),
EvalUsageAnalyzer(),
PathTraversalAnalyzer(),
ExceptionSwallowAnalyzer(),
MagicNumberAnalyzer(),
DeepNestingAnalyzer(),
LongFunctionAnalyzer(),
HardcodedSecretAnalyzer(),
InefficientLoopAnalyzer(),
RedundantOperationAnalyzer(),
UnnecessaryCopyAnalyzer(),
]
for analyzer in analyzers:
assert analyzer.category() in list(FindingCategory)