- Fixed undefined 'tool' variable in display_history function - Changed '[tool]' markup tag usage to proper Rich syntax - All tests now pass (38/38 unit tests) - Type checking passes with mypy --strict
215 lines
7.1 KiB
Python
215 lines
7.1 KiB
Python
"""Tests for the analyzer module."""
|
|
|
|
import pytest
|
|
from cli_diff_auditor.analyzer import AuditResult, DiffAuditor, FileAnalyzer
|
|
from cli_diff_auditor.diff_parser import ChangeType, DiffHunk, DiffLine, FileDiff
|
|
from cli_diff_auditor.rules import RulesLoader, Severity
|
|
|
|
|
|
class TestAuditResult:
|
|
"""Test cases for AuditResult class."""
|
|
|
|
def test_add_finding_error(self):
|
|
"""Test adding an error finding."""
|
|
result = AuditResult()
|
|
result.add_finding(type('Finding', (), {
|
|
'severity': Severity.ERROR
|
|
})())
|
|
|
|
assert result.errors_count == 1
|
|
assert result.warnings_count == 0
|
|
assert result.info_count == 0
|
|
|
|
def test_add_finding_warning(self):
|
|
"""Test adding a warning finding."""
|
|
result = AuditResult()
|
|
result.add_finding(type('Finding', (), {
|
|
'severity': Severity.WARNING
|
|
})())
|
|
|
|
assert result.errors_count == 0
|
|
assert result.warnings_count == 1
|
|
assert result.info_count == 0
|
|
|
|
def test_add_finding_info(self):
|
|
"""Test adding an info finding."""
|
|
result = AuditResult()
|
|
result.add_finding(type('Finding', (), {
|
|
'severity': Severity.INFO
|
|
})())
|
|
|
|
assert result.errors_count == 0
|
|
assert result.warnings_count == 0
|
|
assert result.info_count == 1
|
|
|
|
def test_get_summary(self):
|
|
"""Test getting the summary."""
|
|
result = AuditResult()
|
|
|
|
for _ in range(2):
|
|
result.add_finding(type('Finding', (), {'severity': Severity.ERROR})())
|
|
for _ in range(3):
|
|
result.add_finding(type('Finding', (), {'severity': Severity.WARNING})())
|
|
for _ in range(1):
|
|
result.add_finding(type('Finding', (), {'severity': Severity.INFO})())
|
|
|
|
summary = result.get_summary()
|
|
|
|
assert summary["error"] == 2
|
|
assert summary["warning"] == 3
|
|
assert summary["info"] == 1
|
|
assert summary["total"] == 6
|
|
|
|
def test_has_errors(self):
|
|
"""Test checking for errors."""
|
|
result = AuditResult()
|
|
assert result.has_errors() is False
|
|
|
|
result.add_finding(type('Finding', (), {'severity': Severity.ERROR})())
|
|
assert result.has_errors() is True
|
|
|
|
def test_has_findings(self):
|
|
"""Test checking for any findings."""
|
|
result = AuditResult()
|
|
assert result.has_findings() is False
|
|
|
|
result.add_finding(type('Finding', (), {'severity': Severity.INFO})())
|
|
assert result.has_findings() is True
|
|
|
|
|
|
class TestFileAnalyzer:
|
|
"""Test cases for FileAnalyzer class."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.rules_loader = RulesLoader()
|
|
self.rules_loader.load_builtin_rules()
|
|
self.analyzer = FileAnalyzer(self.rules_loader)
|
|
|
|
def test_analyze_file_diff_finds_debug_print(self):
|
|
"""Test that debug prints are detected."""
|
|
file_diff = FileDiff(file_path="test.py")
|
|
hunk = DiffHunk(old_start=1, old_lines=2, new_start=1, new_lines=2)
|
|
hunk.lines = [
|
|
DiffLine(line_number=1, content="print('hello')", change_type=ChangeType.ADDED),
|
|
]
|
|
file_diff.hunks.append(hunk)
|
|
|
|
findings = self.analyzer.analyze_file_diff(file_diff)
|
|
|
|
assert len(findings) == 1
|
|
assert findings[0].rule_id == "debug-print"
|
|
|
|
def test_analyze_file_diff_finds_console_log(self):
|
|
"""Test that console.log is detected."""
|
|
file_diff = FileDiff(file_path="test.js")
|
|
hunk = DiffHunk(old_start=1, old_lines=2, new_start=1, new_lines=2)
|
|
hunk.lines = [
|
|
DiffLine(line_number=1, content="console.log('test')", change_type=ChangeType.ADDED),
|
|
]
|
|
file_diff.hunks.append(hunk)
|
|
|
|
findings = self.analyzer.analyze_file_diff(file_diff)
|
|
|
|
assert len(findings) == 1
|
|
assert findings[0].rule_id == "console-log"
|
|
|
|
def test_analyze_file_diff_ignores_clean_code(self):
|
|
"""Test that clean code has no findings."""
|
|
file_diff = FileDiff(file_path="test.py")
|
|
hunk = DiffHunk(old_start=1, old_lines=2, new_start=1, new_lines=2)
|
|
hunk.lines = [
|
|
DiffLine(line_number=1, content="def hello():", change_type=ChangeType.ADDED),
|
|
DiffLine(line_number=2, content=" return 'world'", change_type=ChangeType.ADDED),
|
|
]
|
|
file_diff.hunks.append(hunk)
|
|
|
|
findings = self.analyzer.analyze_file_diff(file_diff)
|
|
|
|
assert len(findings) == 0
|
|
|
|
def test_analyze_binary_file(self):
|
|
"""Test that binary files are skipped."""
|
|
file_diff = FileDiff(file_path="image.png", is_binary=True)
|
|
hunk = DiffHunk(old_start=1, old_lines=1, new_start=1, new_lines=1)
|
|
hunk.lines = [
|
|
DiffLine(line_number=1, content="binary data", change_type=ChangeType.ADDED),
|
|
]
|
|
file_diff.hunks.append(hunk)
|
|
|
|
findings = self.analyzer.analyze_file_diff(file_diff)
|
|
|
|
assert len(findings) == 0
|
|
|
|
def test_analyze_deleted_lines(self):
|
|
"""Test that deleted lines are also analyzed."""
|
|
file_diff = FileDiff(file_path="test.py")
|
|
hunk = DiffHunk(old_start=1, old_lines=2, new_start=1, new_lines=1)
|
|
hunk.lines = [
|
|
DiffLine(line_number=1, content="print('old')", change_type=ChangeType.DELETED),
|
|
]
|
|
file_diff.hunks.append(hunk)
|
|
|
|
findings = self.analyzer.analyze_file_diff(file_diff)
|
|
|
|
assert len(findings) == 1
|
|
assert findings[0].rule_id == "debug-print"
|
|
|
|
|
|
class TestDiffAuditor:
|
|
"""Test cases for DiffAuditor class."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test fixtures."""
|
|
self.auditor = DiffAuditor()
|
|
|
|
def test_get_all_rules(self):
|
|
"""Test getting all rules."""
|
|
rules = self.auditor.get_rules()
|
|
|
|
assert len(rules) > 0
|
|
assert any(r.id == "debug-print" for r in rules)
|
|
|
|
def test_get_enabled_rules(self):
|
|
"""Test getting enabled rules."""
|
|
self.auditor.disable_rules(["debug-print", "console-log"])
|
|
|
|
enabled = self.auditor.get_enabled_rules()
|
|
rule_ids = [r.id for r in enabled]
|
|
|
|
assert "debug-print" not in rule_ids
|
|
assert "console-log" not in rule_ids
|
|
|
|
def test_disable_and_enable_rules(self):
|
|
"""Test disabling and enabling rules."""
|
|
self.auditor.disable_rules(["debug-print"])
|
|
enabled = self.auditor.get_enabled_rules()
|
|
assert "debug-print" not in [r.id for r in enabled]
|
|
|
|
self.auditor.enable_rules(["debug-print"])
|
|
enabled = self.auditor.get_enabled_rules()
|
|
assert "debug-print" in [r.id for r in enabled]
|
|
|
|
def test_audit_diff_output(self):
|
|
"""Test auditing diff output directly."""
|
|
diff_output = """diff --git a/test.py b/test.py
|
|
index 1234567..89abcdef 100644
|
|
--- a/test.py
|
|
+++ b/test.py
|
|
@@ -1,2 +1,2 @@
|
|
-old
|
|
+print('debug')
|
|
"""
|
|
result = self.auditor.audit_diff_output(diff_output)
|
|
|
|
assert result.files_scanned == 1
|
|
assert result.has_findings()
|
|
assert result.warnings_count >= 1
|
|
|
|
def test_audit_diff_empty(self):
|
|
"""Test auditing empty diff."""
|
|
result = self.auditor.audit_diff_output("")
|
|
|
|
assert result.files_scanned == 0
|
|
assert not result.has_findings()
|