finance_query_core/models/
indices.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum Region {
7    #[serde(rename = "US")]
8    UnitedStates,
9    #[serde(rename = "NA")]
10    NorthAmerica,
11    #[serde(rename = "SA")]
12    SouthAmerica,
13    #[serde(rename = "EU")]
14    Europe,
15    #[serde(rename = "AS")]
16    Asia,
17    #[serde(rename = "AF")]
18    Africa,
19    #[serde(rename = "ME")]
20    MiddleEast,
21    #[serde(rename = "OCE")]
22    Oceania,
23    #[serde(rename = "global")]
24    Global,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
28#[serde(rename_all = "snake_case")]
29pub enum Index {
30    // United States
31    #[serde(rename = "snp")]
32    Gspc, // S&P 500
33    #[serde(rename = "djia")]
34    Dji, // Dow Jones Industrial Average
35    #[serde(rename = "nasdaq")]
36    Ixic, // NASDAQ Composite
37    #[serde(rename = "nyse-composite")]
38    Nya, // NYSE Composite
39    #[serde(rename = "nyse-amex")]
40    Xax, // NYSE American Composite
41    #[serde(rename = "rut")]
42    Rut, // Russell 2000
43    #[serde(rename = "vix")]
44    Vix, // CBOE Volatility Index
45
46    // North America (excluding US)
47    #[serde(rename = "tsx-composite")]
48    Gsptse, // Toronto Stock Exchange
49
50    // South America
51    #[serde(rename = "ibovespa")]
52    Bvsp, // Brazil Bovespa
53    #[serde(rename = "ipc-mexico")]
54    Mxx, // Mexican IPC
55    #[serde(rename = "ipsa")]
56    Ipsa, // Chile IPSA
57    #[serde(rename = "merval")]
58    Merv, // Argentina Merval
59    #[serde(rename = "ivbx")]
60    Ivbx, // Brazil IVBX
61    #[serde(rename = "ibrx-50")]
62    Ibrx50, // Brazil IBrX-50
63
64
65    // Europe
66    #[serde(rename = "ftse-100")]
67    Ftse, // FTSE 100
68    #[serde(rename = "dax")]
69    Gdaxi, // German DAX
70    #[serde(rename = "cac-40")]
71    Fchi, // French CAC 40
72    #[serde(rename = "euro-stoxx-50")]
73    Stoxx50e, // Euro Stoxx 50
74    #[serde(rename = "euronext-100")]
75    N100, // Euronext 100
76    #[serde(rename = "bel-20")]
77    Bfx, // Belgian BEL 20
78    #[serde(rename = "moex")]
79    MoexMe, // Moscow Exchange
80    #[serde(rename = "aex")]
81    Aex, // Amsterdam Exchange
82    #[serde(rename = "ibex-35")]
83    Ibex, // Spanish IBEX 35
84    #[serde(rename = "ftse-mib")]
85    Ftsemib, // Italian FTSE MIB
86    #[serde(rename = "smi")]
87    Ssmi, // Swiss Market Index
88    #[serde(rename = "psi")]
89    Psi, // Portuguese PSI
90    #[serde(rename = "atx")]
91    Atx, // Austrian ATX
92    #[serde(rename = "omxs30")]
93    Omxs30, // Stockholm OMX 30
94    #[serde(rename = "omxc25")]
95    Omxc25, // Copenhagen OMX 25
96    #[serde(rename = "wig20")]
97    Wig20, // Warsaw WIG 20
98    #[serde(rename = "budapest-se")]
99    Bux, // Budapest Stock Exchange
100    #[serde(rename = "moex-russia")]
101    Imoex, // Moscow Exchange Russia
102    #[serde(rename = "rtsi")]
103    Rtsi, // Russian Trading System
104
105    // Asia
106    #[serde(rename = "hang-seng")]
107    Hsi, // Hong Kong Hang Seng
108    #[serde(rename = "sti")]
109    Sti, // Singapore Straits Times
110    #[serde(rename = "sensex")]
111    Bsesn, // BSE Sensex (India)
112    #[serde(rename = "idx-composite")]
113    Jkse, // Jakarta Composite
114    #[serde(rename = "ftse-bursa")]
115    Klse, // FTSE Bursa Malaysia
116    #[serde(rename = "kospi")]
117    Ks11, // Korea KOSPI
118    #[serde(rename = "twse")]
119    Twii, // Taiwan TAIEX
120    #[serde(rename = "nikkei-225")]
121    N225, // Nikkei 225
122    #[serde(rename = "shanghai")]
123    Shanghai, // Shanghai Composite
124    #[serde(rename = "szse-component")]
125    Szse, // Shenzhen Component
126    #[serde(rename = "set")]
127    Set, // Thailand SET
128    #[serde(rename = "nifty-50")]
129    Nsei, // NSE Nifty 50 (India)
130    #[serde(rename = "nifty-200")]
131    Cnx200, // NSE Nifty 200
132    #[serde(rename = "psei-composite")]
133    Psei, // Philippines PSEi Composite
134    #[serde(rename = "china-a50")]
135    ChinaA50, // FTSE China A50
136    #[serde(rename = "dj-shanghai")]
137    Djsh, // Dow Jones Shanghai
138    #[serde(rename = "india-vix")]
139    Indiavix, // India VIX
140
141    // Africa
142    #[serde(rename = "egx-30")]
143    Case30, // Egypt EGX 30
144    #[serde(rename = "jse-40")]
145    Jn0uJo, // FTSE JSE Top 40- USD Net TRI
146    #[serde(rename = "ftse-jse")]
147    Ftsejse, // FTSE/JSE SA Financials Index
148    #[serde(rename = "afr-40")]
149    Afr40, // All Africa 40 Rand Index
150    #[serde(rename = "raf-40")]
151    Raf40, // RAFI 40 Index
152    #[serde(rename = "sa-40")]
153    Sa40, // South Africa Top 40
154    #[serde(rename = "alt-15")]
155    Alt15, // Alternative 15
156
157    // Middle East
158    #[serde(rename = "ta-125")]
159    Ta125Ta, // Tel Aviv 125
160    #[serde(rename = "ta-35")]
161    Ta35, // Tel Aviv 35
162    #[serde(rename = "tadawul-all-share")]
163    Tasi, // Tadawul All Share
164    #[serde(rename = "tamayuz")]
165    Tamayuz, // Egyptian Tamayuz
166    #[serde(rename = "bist-100")]
167    Bist100, // Borsa Istanbul 100
168
169    // Oceania
170    #[serde(rename = "asx-200")]
171    Axjo, // ASX 200 (Australia)
172    #[serde(rename = "all-ordinaries")]
173    Aord, // All Ordinaries (Australia)
174    #[serde(rename = "nzx-50")]
175    Nz50, // NZX 50 (New Zealand)
176
177    // Global/Currency
178    #[serde(rename = "usd")]
179    DxYNyb, // US Dollar Index
180    #[serde(rename = "msci-europe")]
181    UsdStrd, // MSCI Europe USD
182    #[serde(rename = "gbp")]
183    Xdb, // British Pound
184    #[serde(rename = "euro")]
185    Xde, // Euro
186    #[serde(rename = "yen")]
187    Xdn, // Japanese Yen
188    #[serde(rename = "australian")]
189    Xda, // Australian Dollar
190    #[serde(rename = "msci-world")]
191    MsciWorld, // MSCI World Index
192    #[serde(rename = "cboe-uk-100")]
193    Buk100p, // CBOE UK 100
194}
195
196
197impl Index {
198    pub fn as_str(&self) -> &'static str {
199        match self {
200            Index::Gspc => "snp",
201            Index::Dji => "djia",
202            Index::Ixic => "nasdaq",
203            Index::Nya => "nyse-composite",
204            Index::Xax => "nyse-amex",
205            Index::Rut => "rut",
206            Index::Vix => "vix",
207            Index::Gsptse => "tsx-composite",
208            Index::Bvsp => "ibovespa",
209            Index::Mxx => "ipc-mexico",
210            Index::Ipsa => "ipsa",
211            Index::Merv => "merval",
212            Index::Ivbx => "ivbx",
213            Index::Ibrx50 => "ibrx-50",
214            Index::Ftse => "ftse-100",
215            Index::Gdaxi => "dax",
216            Index::Fchi => "cac-40",
217            Index::Stoxx50e => "euro-stoxx-50",
218            Index::N100 => "euronext-100",
219            Index::Bfx => "bel-20",
220            Index::MoexMe => "moex",
221            Index::Aex => "aex",
222            Index::Ibex => "ibex-35",
223            Index::Ftsemib => "ftse-mib",
224            Index::Ssmi => "smi",
225            Index::Psi => "psi",
226            Index::Atx => "atx",
227            Index::Omxs30 => "omxs30",
228            Index::Omxc25 => "omxc25",
229            Index::Wig20 => "wig20",
230            Index::Bux => "budapest-se",
231            Index::Imoex => "moex-russia",
232            Index::Rtsi => "rtsi",
233            Index::Hsi => "hang-seng",
234            Index::Sti => "sti",
235            Index::Bsesn => "sensex",
236            Index::Jkse => "idx-composite",
237            Index::Klse => "ftse-bursa",
238            Index::Ks11 => "kospi",
239            Index::Twii => "twse",
240            Index::N225 => "nikkei-225",
241            Index::Shanghai => "shanghai",
242            Index::Szse => "szse-component",
243            Index::Set => "set",
244            Index::Nsei => "nifty-50",
245            Index::Cnx200 => "nifty-200",
246            Index::Psei => "psei-composite",
247            Index::ChinaA50 => "china-a50",
248            Index::Djsh => "dj-shanghai",
249            Index::Indiavix => "india-vix",
250            Index::Case30 => "egx-30",
251            Index::Jn0uJo => "jse-40",
252            Index::Ftsejse => "ftse-jse",
253            Index::Afr40 => "afr-40",
254            Index::Raf40 => "raf-40",
255            Index::Sa40 => "sa-40",
256            Index::Alt15 => "alt-15",
257            Index::Ta125Ta => "ta-125",
258            Index::Ta35 => "ta-35",
259            Index::Tasi => "tadawul-all-share",
260            Index::Tamayuz => "tamayuz",
261            Index::Bist100 => "bist-100",
262            Index::Axjo => "asx-200",
263            Index::Aord => "all-ordinaries",
264            Index::Nz50 => "nzx-50",
265            Index::DxYNyb => "usd",
266            Index::UsdStrd => "msci-europe",
267            Index::Xdb => "gbp",
268            Index::Xde => "euro",
269            Index::Xdn => "yen",
270            Index::Xda => "australian",
271            Index::MsciWorld => "msci-world",
272            Index::Buk100p => "cboe-uk-100",
273        }
274    }
275
276
277    pub fn parse(s: &str) -> Option<Self> {
278        match s {
279            "snp" => Some(Index::Gspc),
280            "djia" => Some(Index::Dji),
281            "nasdaq" => Some(Index::Ixic),
282            "nyse-composite" => Some(Index::Nya),
283            "nyse-amex" => Some(Index::Xax),
284            "rut" => Some(Index::Rut),
285            "vix" => Some(Index::Vix),
286            "tsx-composite" => Some(Index::Gsptse),
287            "ibovespa" => Some(Index::Bvsp),
288            "ipc-mexico" => Some(Index::Mxx),
289            "ipsa" => Some(Index::Ipsa),
290            "merval" => Some(Index::Merv),
291            "ivbx" => Some(Index::Ivbx),
292            "ibrx-50" => Some(Index::Ibrx50),
293            "ftse-100" => Some(Index::Ftse),
294            "dax" => Some(Index::Gdaxi),
295            "cac-40" => Some(Index::Fchi),
296            "euro-stoxx-50" => Some(Index::Stoxx50e),
297            "euronext-100" => Some(Index::N100),
298            "bel-20" => Some(Index::Bfx),
299            "moex" => Some(Index::MoexMe),
300            "aex" => Some(Index::Aex),
301            "ibex-35" => Some(Index::Ibex),
302            "ftse-mib" => Some(Index::Ftsemib),
303            "smi" => Some(Index::Ssmi),
304            "psi" => Some(Index::Psi),
305            "atx" => Some(Index::Atx),
306            "omxs30" => Some(Index::Omxs30),
307            "omxc25" => Some(Index::Omxc25),
308            "wig20" => Some(Index::Wig20),
309            "budapest-se" => Some(Index::Bux),
310            "moex-russia" => Some(Index::Imoex),
311            "rtsi" => Some(Index::Rtsi),
312            "hang-seng" => Some(Index::Hsi),
313            "sti" => Some(Index::Sti),
314            "sensex" => Some(Index::Bsesn),
315            "idx-composite" => Some(Index::Jkse),
316            "ftse-bursa" => Some(Index::Klse),
317            "kospi" => Some(Index::Ks11),
318            "twse" => Some(Index::Twii),
319            "nikkei-225" => Some(Index::N225),
320            "shanghai" => Some(Index::Shanghai),
321            "szse-component" => Some(Index::Szse),
322            "set" => Some(Index::Set),
323            "nifty-50" => Some(Index::Nsei),
324            "nifty-200" => Some(Index::Cnx200),
325            "psei-composite" => Some(Index::Psei),
326            "china-a50" => Some(Index::ChinaA50),
327            "dj-shanghai" => Some(Index::Djsh),
328            "india-vix" => Some(Index::Indiavix),
329            "egx-30" => Some(Index::Case30),
330            "jse-40" => Some(Index::Jn0uJo),
331            "ftse-jse" => Some(Index::Ftsejse),
332            "afr-40" => Some(Index::Afr40),
333            "raf-40" => Some(Index::Raf40),
334            "sa-40" => Some(Index::Sa40),
335            "alt-15" => Some(Index::Alt15),
336            "ta-125" => Some(Index::Ta125Ta),
337            "ta-35" => Some(Index::Ta35),
338            "tadawul-all-share" => Some(Index::Tasi),
339            "tamayuz" => Some(Index::Tamayuz),
340            "bist-100" => Some(Index::Bist100),
341            "asx-200" => Some(Index::Axjo),
342            "all-ordinaries" => Some(Index::Aord),
343            "nzx-50" => Some(Index::Nz50),
344            "usd" => Some(Index::DxYNyb),
345            "msci-europe" => Some(Index::UsdStrd),
346            "gbp" => Some(Index::Xdb),
347            "euro" => Some(Index::Xde),
348            "yen" => Some(Index::Xdn),
349            "australian" => Some(Index::Xda),
350            "msci-world" => Some(Index::MsciWorld),
351            "cboe-uk-100" => Some(Index::Buk100p),
352            _ => None,
353        }
354    }
355
356    pub fn all() -> Vec<Index> {
357        vec![
358            Index::Gspc, Index::Dji, Index::Ixic, Index::Nya, Index::Xax, Index::Rut, Index::Vix,
359            Index::Gsptse,
360            Index::Bvsp, Index::Mxx, Index::Ipsa, Index::Merv, Index::Ivbx, Index::Ibrx50,
361            Index::Ftse, Index::Gdaxi, Index::Fchi, Index::Stoxx50e, Index::N100, Index::Bfx,
362            Index::MoexMe, Index::Aex, Index::Ibex, Index::Ftsemib, Index::Ssmi, Index::Psi,
363            Index::Atx, Index::Omxs30, Index::Omxc25, Index::Wig20, Index::Bux, Index::Imoex,
364            Index::Rtsi,
365            Index::Hsi, Index::Sti, Index::Bsesn, Index::Jkse, Index::Klse, Index::Ks11,
366            Index::Twii, Index::N225, Index::Shanghai, Index::Szse, Index::Set, Index::Nsei,
367            Index::Cnx200, Index::Psei, Index::ChinaA50, Index::Djsh, Index::Indiavix,
368            Index::Case30, Index::Jn0uJo, Index::Ftsejse, Index::Afr40, Index::Raf40, Index::Sa40,
369            Index::Alt15,
370            Index::Ta125Ta, Index::Ta35, Index::Tasi, Index::Tamayuz, Index::Bist100,
371            Index::Axjo, Index::Aord, Index::Nz50,
372            Index::DxYNyb, Index::UsdStrd, Index::Xdb, Index::Xde, Index::Xdn, Index::Xda,
373            Index::MsciWorld, Index::Buk100p,
374        ]
375    }
376}
377
378
379pub fn get_index_regions() -> HashMap<Index, Region> {
380    let mut map = HashMap::new();
381    // United States
382    map.insert(Index::Gspc, Region::UnitedStates);
383    map.insert(Index::Dji, Region::UnitedStates);
384    map.insert(Index::Ixic, Region::UnitedStates);
385    map.insert(Index::Nya, Region::UnitedStates);
386    map.insert(Index::Xax, Region::UnitedStates);
387    map.insert(Index::Rut, Region::UnitedStates);
388    map.insert(Index::Vix, Region::UnitedStates);
389    // North America (excluding US)
390    map.insert(Index::Gsptse, Region::NorthAmerica);
391    // South America
392    map.insert(Index::Bvsp, Region::SouthAmerica);
393    map.insert(Index::Mxx, Region::SouthAmerica);
394    map.insert(Index::Ipsa, Region::SouthAmerica);
395    map.insert(Index::Merv, Region::SouthAmerica);
396    map.insert(Index::Ivbx, Region::SouthAmerica);
397    map.insert(Index::Ibrx50, Region::SouthAmerica);
398    // Europe
399    map.insert(Index::Ftse, Region::Europe);
400    map.insert(Index::Gdaxi, Region::Europe);
401    map.insert(Index::Fchi, Region::Europe);
402    map.insert(Index::Stoxx50e, Region::Europe);
403    map.insert(Index::N100, Region::Europe);
404    map.insert(Index::Bfx, Region::Europe);
405    map.insert(Index::MoexMe, Region::Europe);
406    map.insert(Index::Aex, Region::Europe);
407    map.insert(Index::Ibex, Region::Europe);
408    map.insert(Index::Ftsemib, Region::Europe);
409    map.insert(Index::Ssmi, Region::Europe);
410    map.insert(Index::Psi, Region::Europe);
411    map.insert(Index::Atx, Region::Europe);
412    map.insert(Index::Omxs30, Region::Europe);
413    map.insert(Index::Omxc25, Region::Europe);
414    map.insert(Index::Wig20, Region::Europe);
415    map.insert(Index::Bux, Region::Europe);
416    map.insert(Index::Imoex, Region::Europe);
417    map.insert(Index::Rtsi, Region::Europe);
418    // Asia
419    map.insert(Index::Hsi, Region::Asia);
420    map.insert(Index::Sti, Region::Asia);
421    map.insert(Index::Bsesn, Region::Asia);
422    map.insert(Index::Jkse, Region::Asia);
423    map.insert(Index::Klse, Region::Asia);
424    map.insert(Index::Ks11, Region::Asia);
425    map.insert(Index::Twii, Region::Asia);
426    map.insert(Index::N225, Region::Asia);
427    map.insert(Index::Shanghai, Region::Asia);
428    map.insert(Index::Szse, Region::Asia);
429    map.insert(Index::Set, Region::Asia);
430    map.insert(Index::Nsei, Region::Asia);
431    map.insert(Index::Cnx200, Region::Asia);
432    map.insert(Index::Psei, Region::Asia);
433    map.insert(Index::ChinaA50, Region::Asia);
434    map.insert(Index::Djsh, Region::Asia);
435    map.insert(Index::Indiavix, Region::Asia);
436    // Africa
437    map.insert(Index::Case30, Region::Africa);
438    map.insert(Index::Jn0uJo, Region::Africa);
439    map.insert(Index::Ftsejse, Region::Africa);
440    map.insert(Index::Afr40, Region::Africa);
441    map.insert(Index::Sa40, Region::Africa);
442    map.insert(Index::Raf40, Region::Africa);
443    map.insert(Index::Alt15, Region::Africa);
444    // Middle East
445    map.insert(Index::Ta125Ta, Region::MiddleEast);
446    map.insert(Index::Ta35, Region::MiddleEast);
447    map.insert(Index::Tasi, Region::MiddleEast);
448    map.insert(Index::Tamayuz, Region::MiddleEast);
449    map.insert(Index::Bist100, Region::MiddleEast);
450    // Oceania
451    map.insert(Index::Axjo, Region::Oceania);
452    map.insert(Index::Aord, Region::Oceania);
453    map.insert(Index::Nz50, Region::Oceania);
454    // Global/Currency
455    map.insert(Index::DxYNyb, Region::Global);
456    map.insert(Index::UsdStrd, Region::Global);
457    map.insert(Index::Xdb, Region::Global);
458    map.insert(Index::Xde, Region::Global);
459    map.insert(Index::Xdn, Region::Global);
460    map.insert(Index::Xda, Region::Global);
461    map.insert(Index::MsciWorld, Region::Global);
462    map.insert(Index::Buk100p, Region::Global);
463    map
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
467#[serde(rename_all = "snake_case")]
468pub struct MarketIndex {
469    pub name: String,
470    pub value: f64,
471    pub change: String,
472    #[serde(rename = "percentChange")]
473    pub percent_change: String,
474    #[serde(skip_serializing_if = "Option::is_none", rename = "fiveDaysReturn")]
475    pub five_days_return: Option<String>,
476    #[serde(skip_serializing_if = "Option::is_none", rename = "oneMonthReturn")]
477    pub one_month_return: Option<String>,
478    #[serde(skip_serializing_if = "Option::is_none", rename = "threeMonthReturn")]
479    pub three_month_return: Option<String>,
480    #[serde(skip_serializing_if = "Option::is_none", rename = "sixMonthReturn")]
481    pub six_month_return: Option<String>,
482    #[serde(skip_serializing_if = "Option::is_none", rename = "ytdReturn")]
483    pub ytd_return: Option<String>,
484    #[serde(skip_serializing_if = "Option::is_none", rename = "yearReturn")]
485    pub year_return: Option<String>,
486    #[serde(skip_serializing_if = "Option::is_none", rename = "threeYearReturn")]
487    pub three_year_return: Option<String>,
488    #[serde(skip_serializing_if = "Option::is_none", rename = "fiveYearReturn")]
489    pub five_year_return: Option<String>,
490    #[serde(skip_serializing_if = "Option::is_none", rename = "tenYearReturn")]
491    pub ten_year_return: Option<String>,
492    #[serde(skip_serializing_if = "Option::is_none", rename = "maxReturn")]
493    pub max_return: Option<String>,
494}
495
496
497#[cfg(test)]
498mod tests {
499    use super::*;
500    use proptest::prelude::*;
501
502    fn optional_string() -> impl Strategy<Value = Option<String>> {
503        proptest::option::of("[A-Za-z0-9 .%-]{0,20}")
504    }
505
506    // **Feature: crate-extraction, Property 1: Model Serialization Round-Trip**
507    // **Validates: Requirements 2.2**
508    proptest! {
509        #![proptest_config(ProptestConfig::with_cases(100))]
510
511        #[test]
512        fn market_index_roundtrip(
513            name in "[A-Za-z0-9 ]{1,30}",
514            value in 0.01f64..100000.0f64,
515            change in "-?[0-9]{1,5}\\.[0-9]{2}",
516            percent_change in "-?[0-9]{1,3}\\.[0-9]{2}%",
517            five_days_return in optional_string(),
518            one_month_return in optional_string(),
519        ) {
520            let index = MarketIndex {
521                name: name.clone(),
522                value,
523                change: change.clone(),
524                percent_change: percent_change.clone(),
525                five_days_return: five_days_return.clone(),
526                one_month_return: one_month_return.clone(),
527                three_month_return: None,
528                six_month_return: None,
529                ytd_return: None,
530                year_return: None,
531                three_year_return: None,
532                five_year_return: None,
533                ten_year_return: None,
534                max_return: None,
535            };
536
537            let json = serde_json::to_string(&index).unwrap();
538            let parsed: MarketIndex = serde_json::from_str(&json).unwrap();
539
540            prop_assert_eq!(index.name, parsed.name);
541            prop_assert!((index.value - parsed.value).abs() < 1e-10);
542            prop_assert_eq!(index.change, parsed.change);
543            prop_assert_eq!(index.percent_change, parsed.percent_change);
544        }
545
546        #[test]
547        fn region_roundtrip(region in prop_oneof![
548            Just(Region::UnitedStates),
549            Just(Region::NorthAmerica),
550            Just(Region::SouthAmerica),
551            Just(Region::Europe),
552            Just(Region::Asia),
553            Just(Region::Africa),
554            Just(Region::MiddleEast),
555            Just(Region::Oceania),
556            Just(Region::Global),
557        ]) {
558            let json = serde_json::to_string(&region).unwrap();
559            let parsed: Region = serde_json::from_str(&json).unwrap();
560
561            prop_assert_eq!(region, parsed);
562        }
563    }
564}