1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
14pub struct AgencyRecord {
15 #[serde(default, skip_serializing_if = "Option::is_none")]
17 pub agency_id: Option<String>,
18
19 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub name: Option<String>,
22
23 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub abbreviation: Option<String>,
26
27 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub code: Option<String>,
30
31 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub department: Option<Value>,
35
36 #[serde(flatten)]
38 pub extra: HashMap<String, Value>,
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use serde_json::json;
45
46 #[test]
47 fn decode_minimal() {
48 let body = json!({
49 "agency_id": "97",
50 "name": "Department of Defense",
51 "abbreviation": "DOD",
52 "code": "9700"
53 });
54 let a: AgencyRecord = serde_json::from_value(body).expect("decode");
55 assert_eq!(a.name.as_deref(), Some("Department of Defense"));
56 assert_eq!(a.code.as_deref(), Some("9700"));
57 assert!(a.extra.is_empty());
58 }
59
60 #[test]
61 fn extra_captures_forward_compatible_fields() {
62 let body = json!({
63 "name": "Department of Defense",
64 "code": "9700",
65 "future_field": {"version": 2}
66 });
67 let a: AgencyRecord = serde_json::from_value(body).expect("decode");
68 assert!(a.extra.contains_key("future_field"));
69 assert_eq!(
70 a.extra.get("future_field").and_then(|v| v.get("version")),
71 Some(&json!(2))
72 );
73 }
74
75 #[test]
76 fn round_trip_emits_extras() {
77 let body = json!({
78 "name": "GSA",
79 "code": "4700",
80 "future": "x"
81 });
82 let a: AgencyRecord = serde_json::from_value(body.clone()).expect("decode");
83 let re = serde_json::to_value(&a).expect("re-encode");
84 assert_eq!(re.get("future"), Some(&json!("x")));
85 assert_eq!(re.get("name"), Some(&json!("GSA")));
86 }
87}