1#![forbid(unsafe_code)]
3#![allow(unused_variables)]
4#![deny(clippy::all)]
5
6#[macro_use] mod imports; use imports::*;
7
8x!{abbreviation}
9x!{from_str}
10x!{country}
11x!{error}
12x!{impl_serde}
13x!{impl_from}
14x!{world_region}
15
16#[cfg(test)]
17mod world_region_tests {
18 use super::*;
19 use std::str::FromStr;
20
21 #[test]
22 fn test_conversions() {
23 let c = Country::Nigeria;
25 let wr = WorldRegion::try_from(c).expect("should convert");
26 match wr {
27 WorldRegion::Africa(r) => assert_eq!(r, AfricaRegion::Nigeria),
28 _ => panic!("Expected Africa(Nigeria)"),
29 }
30
31 let back: Country = wr.try_into().expect("should convert back");
33 assert_eq!(back, Country::Nigeria);
34 }
35
36 #[test]
37 fn test_abbreviation() {
38 let wr = WorldRegion::Asia(AsiaRegion::China(asia::ChinaRegion::Beijing));
39 assert_eq!(wr.abbreviation(), "CN-BJ");
40 }
41
42 #[test]
43 fn test_abbreviations() {
44 let wr_africa = WorldRegion::Africa(AfricaRegion::Nigeria);
46 assert_eq!(wr_africa.abbreviation(), "NG");
47
48 let wr_asia = WorldRegion::Asia(AsiaRegion::Japan(asia::JapanRegion::Hokkaido));
49 assert_eq!(wr_asia.abbreviation(), "JP-HKD");
50
51 let wr_europe = WorldRegion::Europe(EuropeRegion::France(europe::FranceRegion::IleDeFrance));
52 assert_eq!(wr_europe.abbreviation(), "FR-J");
53
54 let wr_naa = WorldRegion::NorthAmerica(NorthAmericaRegion::Canada(north_america::CanadaRegion::Ontario));
55 assert_eq!(wr_naa.abbreviation(), "ON");
56
57 let wr_saa = WorldRegion::SouthAmerica(SouthAmericaRegion::Brazil(south_america::BrazilRegion::Sudeste));
58 assert_eq!(wr_saa.abbreviation(), "BR-SE");
59
60 let wr_caa = WorldRegion::CentralAmerica(CentralAmericaRegion::CostaRica);
61 assert_eq!(wr_caa.abbreviation(), "CR");
62
63 let wr_aoa = WorldRegion::AustraliaOceaniaAntarctica(australia_oceania_antarctica::AustraliaOceaniaAntarcticaRegion::Fiji);
64 assert_eq!(wr_aoa.abbreviation(), "FJ");
65 }
66
67 #[test]
68 fn test_iso_conversions() {
69 let wr = WorldRegion::Africa(AfricaRegion::Egypt);
71 let alpha2: Iso3166Alpha2 = wr.clone().try_into().expect("Alpha2 conversion");
72 let alpha3: Iso3166Alpha3 = wr.clone().try_into().expect("Alpha3 conversion");
73 let code: CountryCode = wr.try_into().expect("CountryCode conversion");
74
75 assert_eq!(alpha2, Iso3166Alpha2::EG);
76 assert_eq!(alpha3, Iso3166Alpha3::EGY);
77 match code {
78 CountryCode::Alpha2(a2) => assert_eq!(a2, Iso3166Alpha2::EG),
79 _ => panic!("Expected Alpha2 code"),
80 }
81
82 let wr_unsupported = WorldRegion::Asia(AsiaRegion::GccStates);
86 let res: Result<Iso3166Alpha2, _> = wr_unsupported.try_into();
87 assert!(res.is_err(), "GCC States should fail ISO conversion");
88 }
89
90 #[test]
91 fn test_country_conversions() {
92 let c = Country::Nigeria;
94 let wr = WorldRegion::try_from(c).expect("should convert from Nigeria to WorldRegion(Africa)");
95 match wr {
96 WorldRegion::Africa(r) => assert_eq!(r, AfricaRegion::Nigeria),
97 _ => panic!("Expected Africa(Nigeria)"),
98 }
99
100 let back: Country = wr.try_into().expect("should convert back to Country");
102 assert_eq!(back, Country::Nigeria);
103
104 let c_not_rep = Country::VaticanCity; let wr_fail = WorldRegion::try_from(c_not_rep.clone());
108 assert!(wr_fail.is_err(), "VaticanCity not represented should fail");
109
110 }
114
115 #[test]
116 fn test_serialize_deserialize() {
117 let wr_africa = WorldRegion::Africa(AfricaRegion::Kenya);
119 let serialized = serde_json::to_string(&wr_africa).expect("serialize africa");
120 let deserialized: WorldRegion = serde_json::from_str(&serialized).expect("deserialize africa");
121 assert_eq!(wr_africa, deserialized);
122
123 let wr_asia = WorldRegion::Asia(AsiaRegion::China(asia::ChinaRegion::Beijing));
125 let serialized_asia = serde_json::to_string(&wr_asia).expect("serialize asia");
126 let deserialized_asia: WorldRegion = serde_json::from_str(&serialized_asia).expect("deserialize asia");
127 assert_eq!(wr_asia, deserialized_asia);
128
129 let v: serde_json::Value = serde_json::from_str(&serialized_asia).expect("parse json");
131 assert_eq!(v.get("continent").and_then(|x| x.as_str()), Some("Asia"));
132 assert_eq!(v.get("country").and_then(|x| x.as_str()), Some("China"));
133 assert_eq!(v.get("region").and_then(|x| x.as_str()), Some("Beijing"));
134 }
135
136 #[test]
137 fn test_error_handling() {
138 let wr_unsupported = WorldRegion::Africa(AfricaRegion::SaintHelenaAscensionTristanDaCunha);
141 let country_res: Result<Country, _> = wr_unsupported.try_into();
142 assert!(country_res.is_err(), "Should fail for combined region");
143
144 }
147
148 #[test]
149 fn test_variant_names_consistency() {
150 let africa_test = Country::Ethiopia;
152 let wr_africa = WorldRegion::try_from(africa_test.clone()).expect("Ethiopia -> AfricaRegion");
153 let back_africa: Country = wr_africa.try_into().expect("AfricaRegion -> Ethiopia");
154 assert_eq!(back_africa, africa_test);
155
156 let asia_test = Country::Japan;
157 let wr_asia = WorldRegion::try_from(asia_test.clone()).expect("Japan -> AsiaRegion");
158 let back_asia: Country = wr_asia.try_into().expect("AsiaRegion -> Japan");
159 assert_eq!(back_asia, asia_test);
160
161 let europe_test = Country::France;
162 let wr_europe = WorldRegion::try_from(europe_test.clone()).expect("France -> EuropeRegion");
163 let back_europe: Country = wr_europe.try_into().expect("EuropeRegion -> France");
164 assert_eq!(back_europe, europe_test);
165
166 let na_test = Country::Canada;
170 let wr_na = WorldRegion::try_from(na_test.clone()).expect("Canada -> NorthAmericaRegion");
171 let back_na: Country = wr_na.try_into().expect("NorthAmericaRegion -> Canada");
172 assert_eq!(back_na, na_test);
173
174 let sa_test = Country::Argentina;
175 let wr_sa = WorldRegion::try_from(sa_test.clone()).expect("Argentina -> SouthAmericaRegion");
176 let back_sa: Country = wr_sa.try_into().expect("SouthAmericaRegion -> Argentina");
177 assert_eq!(back_sa, sa_test);
178
179 let ca_test = Country::Panama;
180 let wr_ca = WorldRegion::try_from(ca_test.clone()).expect("Panama -> CentralAmericaRegion");
181 let back_ca: Country = wr_ca.try_into().expect("CentralAmericaRegion -> Panama");
182 assert_eq!(back_ca, ca_test);
183
184 let aoa_test = Country::Fiji;
185 let wr_aoa = WorldRegion::try_from(aoa_test.clone()).expect("Fiji -> AustraliaOceaniaAntarcticaRegion");
186 let back_aoa: Country = wr_aoa.try_into().expect("AustraliaOceaniaAntarcticaRegion -> Fiji");
187 assert_eq!(back_aoa, aoa_test);
188 }
189
190 #[test]
191 fn test_from_str_and_variant_matching() {
192 let asia_region = AsiaRegion::from_str("Beijing").ok();
195 assert!(asia_region.is_some());
196 let wr = WorldRegion::Asia(asia_region.unwrap());
197 let serialized = serde_json::to_string(&wr).expect("serialize");
198 let deserialized: WorldRegion = serde_json::from_str(&serialized).expect("deserialize");
199 assert_eq!(wr, deserialized);
200 }
201
202 #[test]
203 fn test_unified_iso_conversion_failure() {
204 let wr_canary = WorldRegion::Africa(AfricaRegion::CanaryIslands);
207 let res: Result<Iso3166Alpha2, _> = wr_canary.try_into();
208 assert!(res.is_err(), "Canary Islands should fail ISO conversion");
209 }
210}
211
212#[cfg(test)]
213mod exhaustive_world_region_tests {
214 use super::*;
215 use std::str::FromStr;
216
217 #[test]
218 fn test_all_continents_country_to_world_region() {
219 let test_cases = vec![
221 (Country::Nigeria , "Africa") ,
222 (Country::Egypt , "Africa") ,
223 (Country::China , "Asia") ,
224 (Country::Japan , "Asia") ,
225 (Country::France , "Europe") ,
226 (Country::Germany , "Europe") ,
227 (Country::Canada , "North America") ,
228 (Country::USA , "North America") ,
229 (Country::Argentina , "South America") ,
230 (Country::Brazil , "South America") ,
231 (Country::CostaRica , "Central America") ,
232 (Country::Panama , "Central America") ,
233 (Country::Fiji , "Australia/Oceania/Antarctica") ,
234 (Country::Australia , "Australia/Oceania/Antarctica") ,
235 ];
236
237 for (country, expected_continent) in test_cases {
238 let wr = WorldRegion::try_from(country.clone())
239 .unwrap_or_else(|_| panic!("Could not map {:?} to WorldRegion", country));
240 let serialized = serde_json::to_string(&wr).expect("serialize");
242 let v: serde_json::Value = serde_json::from_str(&serialized).expect("json parse");
243 let cont = v.get("continent").and_then(|x| x.as_str()).unwrap();
244 assert_eq!(cont, expected_continent, "Continent mismatch for {:?}", country);
245
246 let back_country: Country = wr.try_into().expect("Should convert back to Country");
248 assert_eq!(back_country, country, "Round-trip country mismatch");
249 }
250 }
251
252 #[test]
253 fn test_iso_code_success() {
254 let wr = WorldRegion::Europe(EuropeRegion::France(FranceRegion::IleDeFrance));
256 let alpha2: Iso3166Alpha2 = wr.try_into().expect("Alpha2 conversion failed");
257 let alpha3: Iso3166Alpha3 = wr.try_into().expect("Alpha3 conversion failed");
258 let code: CountryCode = wr.try_into().expect("CountryCode conversion failed");
259
260 assert_eq!(alpha2, Iso3166Alpha2::FR);
261 assert_eq!(alpha3, Iso3166Alpha3::FRA);
262 match code {
263 CountryCode::Alpha2(a2) => assert_eq!(a2, Iso3166Alpha2::FR),
264 _ => panic!("Expected Alpha2 code"),
265 }
266 }
267
268 #[test]
269 fn test_iso_code_failure() {
270 let wr_unsupported = WorldRegion::Asia(AsiaRegion::GccStates);
273 let res: Result<Iso3166Alpha2, _> = wr_unsupported.try_into();
274 assert!(res.is_err(), "GCC States should fail ISO conversion");
275 }
276
277 #[test]
278 fn test_not_represented_country() {
279 let c = Country::VaticanCity; let res = WorldRegion::try_from(c.clone());
282 match res {
283 Err(WorldRegionConversionError::NotRepresented { country }) => {
284 assert_eq!(country, c, "Expected NotRepresented error for {:?}", c);
285 }
286 _ => panic!("Expected NotRepresented error for {:?}", c),
287 }
288 }
289
290 #[test]
291 fn test_unsupported_region_to_country() {
292 let wr_unsupported = WorldRegion::Africa(AfricaRegion::SaintHelenaAscensionTristanDaCunha);
294 let res: Result<Country, _> = wr_unsupported.try_into();
295 match res {
296 Err(WorldRegionConversionError::Africa(_)) => {
297 }
299 _ => panic!("Expected Africa(...) error for unsupported region"),
300 }
301 }
302
303 #[test]
304 fn test_serialize_deserialize_non_subdivided() {
305 let wr = WorldRegion::CentralAmerica(CentralAmericaRegion::CostaRica);
307 let serialized = serde_json::to_string(&wr).expect("serialize");
308 let deserialized: WorldRegion = serde_json::from_str(&serialized).expect("deserialize");
309 assert_eq!(wr, deserialized);
310 }
311
312 #[test]
313 fn test_serialize_deserialize_subdivided() {
314 let wr = WorldRegion::NorthAmerica(NorthAmericaRegion::Canada(north_america::CanadaRegion::Ontario));
316 let serialized = serde_json::to_string(&wr).expect("serialize");
317 let deserialized: WorldRegion = serde_json::from_str(&serialized).expect("deserialize");
318 assert_eq!(wr, deserialized);
319
320 let v: serde_json::Value = serde_json::from_str(&serialized).expect("parse json");
322 assert_eq!(v.get("continent").and_then(|x| x.as_str()), Some("North America"));
323 assert_eq!(v.get("country").and_then(|x| x.as_str()), Some("Canada"));
324 assert_eq!(v.get("region").and_then(|x| x.as_str()), Some("Ontario"));
325 }
326
327 #[test]
328 fn test_abbreviation_across_continents() {
329 let pairs = vec![
330 (WorldRegion::Africa(AfricaRegion::Nigeria), "NG"),
331 (WorldRegion::Asia(AsiaRegion::Japan(asia::JapanRegion::Hokkaido)), "JP-HKD"),
332 (WorldRegion::Europe(EuropeRegion::Germany(GermanyRegion::Berlin)), "DE-BE"),
333 (WorldRegion::NorthAmerica(NorthAmericaRegion::UnitedStates(usa::USRegion::UnitedState(usa::UnitedState::California))), "CA"),
334 (WorldRegion::SouthAmerica(SouthAmericaRegion::Brazil(south_america::BrazilRegion::Sudeste)), "BR-SE"),
335 (WorldRegion::CentralAmerica(CentralAmericaRegion::Panama), "PA"),
336 (WorldRegion::AustraliaOceaniaAntarctica(australia_oceania_antarctica::AustraliaOceaniaAntarcticaRegion::Fiji), "FJ"),
337 ];
338
339 for (wr, expected_abbr) in pairs {
340 assert_eq!(wr.abbreviation(), expected_abbr, "Abbreviation mismatch for {:?}", wr);
341 }
342 }
343
344 #[test]
345 fn test_string_parsing_case_insensitivity() {
346 let wr_str = r#"Ile-De-France"#;
349 let wr = WorldRegion::from_str(wr_str).expect("deserialize");
350 if let WorldRegion::Europe(EuropeRegion::France(fr)) = wr {
351 assert_eq!(fr, FranceRegion::IleDeFrance);
352 } else {
353 panic!("Expected Europe(France(IleDeFrance))");
354 }
355
356 let wr_str_alt = r#"iLe-De-FrAnCe"#;
358 let wr_alt = WorldRegion::from_str(wr_str_alt).expect("case-insensitive deserialize");
359 assert_eq!(wr, wr_alt);
360 }
361
362 #[test]
363 fn test_round_trip_all_example_continents() {
364 let examples = vec![
366 WorldRegion::Africa(AfricaRegion::Kenya),
367 WorldRegion::Asia(AsiaRegion::China(asia::ChinaRegion::Beijing)),
368 WorldRegion::Europe(EuropeRegion::Italy(europe::ItalyRegion::Centro)),
369 WorldRegion::NorthAmerica(NorthAmericaRegion::Canada(north_america::CanadaRegion::Ontario)),
370 WorldRegion::SouthAmerica(SouthAmericaRegion::Brazil(south_america::BrazilRegion::Sul)),
371 WorldRegion::CentralAmerica(CentralAmericaRegion::Guatemala),
372 WorldRegion::AustraliaOceaniaAntarctica(australia_oceania_antarctica::AustraliaOceaniaAntarcticaRegion::NewZealand),
373 ];
374
375 for wr in examples {
376 let serialized = serde_json::to_string(&wr).expect("serialize");
377 let deserialized: WorldRegion = serde_json::from_str(&serialized).expect("deserialize");
378 assert_eq!(wr, deserialized, "Round-trip mismatch for {:?}", wr);
379 }
380 }
381
382 #[test]
383 fn test_fictional_error() {
384 let fictional_wr = WorldRegion::from_str("Atlantis");
385 assert!(fictional_wr.is_err());
386 }
387
388 #[test]
389 fn test_feature_flag_abbreviation() {
390 #[cfg(feature = "serde_abbreviation")]
399 {
400 let wr = WorldRegion::Europe(EuropeRegion::Spain(spain::SpainRegion::Madrid));
401 let s = serde_json::to_string(&wr).expect("serialize");
402 assert_eq!(s, "\"ES\"");
404 }
405 }
406}