1use serde::{Deserialize, Serialize};
4
5use crate::com::RegionCriterion;
6use crate::enums::RegionType;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct Region {
29 #[serde(flatten)]
31 pub meta: Bo4eMeta,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub region_code: Option<String>,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub name: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub description: Option<String>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub region_type: Option<RegionType>,
48
49 #[serde(default, skip_serializing_if = "Vec::is_empty")]
51 pub criteria: Vec<RegionCriterion>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub parent_region: Option<Box<Region>>,
56
57 #[serde(default, skip_serializing_if = "Vec::is_empty")]
59 pub sub_regions: Vec<Box<Region>>,
60}
61
62impl Bo4eObject for Region {
63 fn type_name_german() -> &'static str {
64 "Region"
65 }
66
67 fn type_name_english() -> &'static str {
68 "Region"
69 }
70
71 fn meta(&self) -> &Bo4eMeta {
72 &self.meta
73 }
74
75 fn meta_mut(&mut self) -> &mut Bo4eMeta {
76 &mut self.meta
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_region_creation() {
86 let region = Region {
87 region_code: Some("DE-BY".to_string()),
88 name: Some("Bavaria".to_string()),
89 region_type: Some(RegionType::SupplyArea),
90 ..Default::default()
91 };
92
93 assert_eq!(region.region_code, Some("DE-BY".to_string()));
94 assert_eq!(region.region_type, Some(RegionType::SupplyArea));
95 }
96
97 #[test]
98 fn test_market_area_region() {
99 let region = Region {
100 region_code: Some("TRADING-HUB-EUROPE".to_string()),
101 name: Some("Trading Hub Europe".to_string()),
102 region_type: Some(RegionType::MarketArea),
103 ..Default::default()
104 };
105
106 assert_eq!(region.region_type, Some(RegionType::MarketArea));
107 }
108
109 #[test]
110 fn test_nested_regions() {
111 let sub_region = Box::new(Region {
112 region_code: Some("DE-BY-M".to_string()),
113 name: Some("Munich Area".to_string()),
114 ..Default::default()
115 });
116
117 let region = Region {
118 region_code: Some("DE-BY".to_string()),
119 name: Some("Bavaria".to_string()),
120 sub_regions: vec![sub_region],
121 ..Default::default()
122 };
123
124 assert_eq!(region.sub_regions.len(), 1);
125 assert_eq!(region.sub_regions[0].name, Some("Munich Area".to_string()));
126 }
127
128 #[test]
129 fn test_serialize() {
130 let region = Region {
131 meta: Bo4eMeta::with_type("Region"),
132 region_code: Some("DE-BY".to_string()),
133 name: Some("Bavaria".to_string()),
134 ..Default::default()
135 };
136
137 let json = serde_json::to_string(®ion).unwrap();
138 assert!(json.contains(r#""regionCode":"DE-BY""#));
139 assert!(json.contains(r#""name":"Bavaria""#));
140 }
141
142 #[test]
143 fn test_roundtrip() {
144 let region = Region {
145 meta: Bo4eMeta::with_type("Region"),
146 region_code: Some("DE-BY".to_string()),
147 name: Some("Bavaria".to_string()),
148 description: Some("State of Bavaria".to_string()),
149 region_type: Some(RegionType::SupplyArea),
150 ..Default::default()
151 };
152
153 let json = serde_json::to_string(®ion).unwrap();
154 let parsed: Region = serde_json::from_str(&json).unwrap();
155 assert_eq!(region, parsed);
156 }
157
158 #[test]
159 fn test_bo4e_object_impl() {
160 assert_eq!(Region::type_name_german(), "Region");
161 assert_eq!(Region::type_name_english(), "Region");
162 }
163}