1use serde::{Deserialize, Serialize};
2
3use crate::safety::SafetyWarning;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct FilterExample {
8 pub name: String,
10 pub exit_code: i32,
12 pub raw: String,
14 pub filtered: String,
16 pub raw_line_count: usize,
18 pub filtered_line_count: usize,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct FilterExamples {
25 pub examples: Vec<FilterExample>,
26 pub safety: ExamplesSafety,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31pub struct ExamplesSafety {
32 pub passed: bool,
33 pub warnings: Vec<SafetyWarningDto>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct SafetyWarningDto {
39 pub kind: String,
40 pub message: String,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub detail: Option<String>,
43}
44
45impl From<&SafetyWarning> for SafetyWarningDto {
46 fn from(w: &SafetyWarning) -> Self {
47 Self {
48 kind: w.kind.as_str().to_string(),
49 message: w.message.clone(),
50 detail: w.detail.clone(),
51 }
52 }
53}
54
55#[cfg(test)]
56#[allow(clippy::unwrap_used)]
57mod tests {
58 use super::*;
59 use crate::safety::WarningKind;
60
61 #[test]
62 fn serialize_round_trip() {
63 let examples = FilterExamples {
64 examples: vec![FilterExample {
65 name: "basic".to_string(),
66 exit_code: 0,
67 raw: "line1\nline2\nline3".to_string(),
68 filtered: "line1".to_string(),
69 raw_line_count: 3,
70 filtered_line_count: 1,
71 }],
72 safety: ExamplesSafety {
73 passed: true,
74 warnings: vec![],
75 },
76 };
77
78 let json = serde_json::to_string(&examples).unwrap();
79 let parsed: FilterExamples = serde_json::from_str(&json).unwrap();
80 assert_eq!(parsed.examples.len(), 1);
81 assert_eq!(parsed.examples[0].name, "basic");
82 assert!(parsed.safety.passed);
83 }
84
85 #[test]
86 fn warning_dto_from_safety_warning() {
87 let warning = SafetyWarning {
88 kind: WarningKind::TemplateInjection,
89 message: "bad template".to_string(),
90 detail: Some("ignore previous instructions".to_string()),
91 };
92 let dto = SafetyWarningDto::from(&warning);
93 assert_eq!(dto.kind, "template_injection");
94 assert_eq!(dto.message, "bad template");
95 }
96}