Add fixer and rule tests
Some checks failed
CI / build (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
2026-01-29 23:13:48 +00:00
parent 3d41fb707c
commit 263a139945

278
tests/test_rules.py Normal file
View File

@@ -0,0 +1,278 @@
"""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)