tests/test_findings.py
2.8 KB · 95 lines · python Raw
1 """Tests for Finding / Severity / ScanReport."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from pqc_lint.findings import Finding, ScanReport, Severity
8
9
10 def test_severity_ordering():
11 assert Severity.CRITICAL.order > Severity.HIGH.order
12 assert Severity.HIGH.order > Severity.MEDIUM.order
13 assert Severity.MEDIUM.order > Severity.LOW.order
14 assert Severity.LOW.order > Severity.INFO.order
15
16
17 def test_severity_from_str():
18 assert Severity.from_str("CRITICAL") is Severity.CRITICAL
19 assert Severity.from_str("high") is Severity.HIGH
20 assert Severity.from_str("MeDiUm") is Severity.MEDIUM
21 with pytest.raises(ValueError):
22 Severity.from_str("nope")
23
24
25 def test_finding_roundtrip():
26 f = Finding(
27 rule_id="PQC001",
28 severity=Severity.CRITICAL,
29 message="RSA found",
30 file="foo.py",
31 line=4,
32 column=10,
33 snippet="rsa.generate_private_key(...)",
34 suggestion="Use ML-DSA",
35 cwe="CWE-327",
36 language="python",
37 )
38 data = f.to_dict()
39 assert data["severity"] == "critical"
40 assert data["rule_id"] == "PQC001"
41
42 reloaded = Finding.from_dict(data)
43 assert reloaded.rule_id == f.rule_id
44 assert reloaded.severity is Severity.CRITICAL
45 assert reloaded.file == f.file
46 assert reloaded.line == f.line
47 assert reloaded.snippet == f.snippet
48 assert reloaded.cwe == f.cwe
49
50
51 def _mk_finding(severity: Severity, rule_id: str = "PQC001") -> Finding:
52 return Finding(
53 rule_id=rule_id, severity=severity, message="x",
54 file="f.py", line=1,
55 )
56
57
58 def test_scan_report_counts_by_severity():
59 report = ScanReport()
60 report.findings.extend([
61 _mk_finding(Severity.CRITICAL),
62 _mk_finding(Severity.CRITICAL),
63 _mk_finding(Severity.HIGH),
64 _mk_finding(Severity.MEDIUM),
65 ])
66 counts = report.counts_by_severity()
67 assert counts["critical"] == 2
68 assert counts["high"] == 1
69 assert counts["medium"] == 1
70 assert counts["low"] == 0
71
72
73 def test_scan_report_counts_by_rule():
74 report = ScanReport()
75 report.findings.extend([
76 _mk_finding(Severity.CRITICAL, "PQC001"),
77 _mk_finding(Severity.CRITICAL, "PQC001"),
78 _mk_finding(Severity.HIGH, "PQC002"),
79 ])
80 counts = report.counts_by_rule()
81 assert counts["PQC001"] == 2
82 assert counts["PQC002"] == 1
83
84
85 def test_scan_report_has_failing_threshold():
86 report = ScanReport()
87 report.findings.append(_mk_finding(Severity.CRITICAL))
88 assert report.has_failing(Severity.HIGH)
89 assert report.has_failing(Severity.CRITICAL)
90 # only medium, fail-on=high should NOT trigger
91 report2 = ScanReport()
92 report2.findings.append(_mk_finding(Severity.MEDIUM))
93 assert not report2.has_failing(Severity.HIGH)
94 assert report2.has_failing(Severity.LOW)
95