1use super::OutputFormatter;
2
3#[derive(Default)]
5pub struct JsonFormatter;
6
7impl JsonFormatter {
8 pub fn new() -> Self {
9 Self
10 }
11
12 fn to_json<T: serde::Serialize + ?Sized>(&self, value: &T) -> String {
13 serde_json::to_string_pretty(value)
16 .unwrap_or_else(|e| serde_json::json!({ "error": e.to_string() }).to_string())
17 }
18}
19
20with_report_methods!(impl_serializing!(JsonFormatter, to_json;));
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25 use crate::dns::{DnsRecord, RecordType};
26 use crate::status::StatusResponse;
27
28 #[test]
29 fn test_json_format_status() {
30 let response = StatusResponse::new("example.com".to_string());
31 let formatter = JsonFormatter::new();
32 let output = formatter.format_status(&response);
33 assert!(output.contains("example.com"));
34 assert!(output.contains("domain"));
35 }
36
37 #[test]
38 fn test_json_format_dns_records() {
39 let records = vec![DnsRecord {
40 name: "example.com".to_string(),
41 record_type: RecordType::A,
42 ttl: 300,
43 data: crate::dns::RecordData::A {
44 address: "93.184.216.34".to_string(),
45 },
46 }];
47 let formatter = JsonFormatter::new();
48 let output = formatter.format_dns(&records);
49 assert!(output.contains("93.184.216.34"));
50 assert!(output.contains("\"A\""));
51 }
52
53 #[test]
54 fn error_fallback_is_valid_json() {
55 struct Failing;
58 impl serde::Serialize for Failing {
59 fn serialize<S: serde::Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
60 Err(serde::ser::Error::custom("bad \"value\"\n"))
61 }
62 }
63 let out = JsonFormatter::new().to_json(&Failing);
64 let parsed: serde_json::Value = serde_json::from_str(&out).unwrap();
65 assert_eq!(parsed["error"], "bad \"value\"\n");
66 }
67
68 #[test]
69 fn dig_and_trace_serialize_as_objects() {
70 use crate::dns::{DnsQueryResult, DnsStatus, DnsTrace};
73 let result = DnsQueryResult {
74 name: "gone.seer.test".to_string(),
75 record_type: RecordType::A,
76 server: None,
77 answered_locally: false,
78 status: DnsStatus::NxDomain,
79 flags: Vec::new(),
80 answers: Vec::new(),
81 failed_types: Vec::new(),
82 authority: Vec::new(),
83 wildcard: None,
84 query_time_ms: 7,
85 };
86 let json: serde_json::Value =
87 serde_json::from_str(&JsonFormatter::new().format_dig(&result)).unwrap();
88 assert_eq!(json["status"], "NXDOMAIN");
89 assert_eq!(json["server"], serde_json::Value::Null);
90
91 let trace = DnsTrace {
92 name: "gone.seer.test".to_string(),
93 record_type: RecordType::A,
94 hops: Vec::new(),
95 status: DnsStatus::NxDomain,
96 answers: Vec::new(),
97 error: Some("stopped".to_string()),
98 };
99 let json: serde_json::Value =
100 serde_json::from_str(&JsonFormatter::new().format_dns_trace(&trace)).unwrap();
101 assert_eq!(json["status"], "NXDOMAIN");
102 assert_eq!(json["error"], "stopped");
103 }
104}