"""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)