1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum Severity {
7 Critical,
8 High,
9 Medium,
10 Low,
11}
12
13impl fmt::Display for Severity {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 Severity::Critical => write!(f, "CRITICAL"),
17 Severity::High => write!(f, "HIGH"),
18 Severity::Medium => write!(f, "MEDIUM"),
19 Severity::Low => write!(f, "LOW"),
20 }
21 }
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum AttackCategory {
26 Injection,
27 Protocol,
28 Data,
29 File,
30}
31
32impl fmt::Display for AttackCategory {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 AttackCategory::Injection => write!(f, "injection"),
37 AttackCategory::Protocol => write!(f, "protocol"),
38 AttackCategory::Data => write!(f, "data"),
39 AttackCategory::File => write!(f, "file"),
40 }
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct DetectionResult {
46 pub attack_type: String,
47 pub category: AttackCategory,
48 pub severity: Severity,
49 pub matched_pattern: String,
50 pub offset: usize,
51 pub message: String,
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 fn sample() -> DetectionResult {
59 DetectionResult {
60 attack_type: "xss".into(),
61 category: AttackCategory::Injection,
62 severity: Severity::Critical,
63 matched_pattern: "<script>".into(),
64 offset: 0,
65 message: "XSS detected".into(),
66 }
67 }
68
69 #[test]
70 fn severity_display_uppercase() {
71 assert_eq!(Severity::Critical.to_string(), "CRITICAL");
72 assert_eq!(Severity::High.to_string(), "HIGH");
73 assert_eq!(Severity::Medium.to_string(), "MEDIUM");
74 assert_eq!(Severity::Low.to_string(), "LOW");
75 }
76
77 #[test]
78 fn severity_equality() {
79 assert_eq!(Severity::Critical, Severity::Critical);
80 assert_ne!(Severity::Critical, Severity::High);
81 assert_ne!(Severity::Medium, Severity::Low);
82 }
83
84 #[test]
85 fn attack_category_display_tags() {
86 assert_eq!(AttackCategory::Injection.to_string(), "injection");
87 assert_eq!(AttackCategory::Protocol.to_string(), "protocol");
88 assert_eq!(AttackCategory::Data.to_string(), "data");
89 assert_eq!(AttackCategory::File.to_string(), "file");
90 }
91
92 #[test]
93 fn attack_category_equality() {
94 assert_eq!(AttackCategory::Injection, AttackCategory::Injection);
95 assert_ne!(AttackCategory::Injection, AttackCategory::Protocol);
96 assert_ne!(AttackCategory::Data, AttackCategory::File);
97 }
98
99 #[test]
100 fn detection_result_clone_and_equality() {
101 let a = sample();
102 assert_eq!(a, a.clone());
103 }
104
105 #[test]
106 fn detection_result_field_difference_changes_equality() {
107 let a = sample();
108 let b = DetectionResult {
109 severity: Severity::High,
110 ..a.clone()
111 };
112 assert_ne!(a, b);
113 }
114
115 #[test]
116 fn detection_result_debug_output() {
117 let dbg = format!("{:?}", sample());
118 assert!(dbg.contains("xss"));
119 assert!(dbg.contains("Injection"));
120 assert!(dbg.contains("CRITICAL") || dbg.contains("Critical"));
121 }
122}