Skip to main content

haste_fhir_model/
lib.rs

1pub mod r4;
2
3#[cfg(test)]
4mod tests {
5    use super::*;
6    use crate::r4::{
7        datetime::Date,
8        generated::resources::{ClientApplication, Practitioner, Resource},
9    };
10    use haste_reflect::MetaValue;
11    use r4::generated::{resources::Patient, types::Address};
12    use serde_json;
13
14    #[test]
15    fn test_enum_with_extension() {
16        let term_ = r4::generated::terminology::AdministrativeGender::Male(Some(
17            r4::generated::types::Element {
18                id: Some("test".to_string()),
19                ..r4::generated::types::Element::default()
20            },
21        ));
22        assert_eq!(term_.fhir_type(), "code");
23        let k = term_
24            .get_field("value")
25            .unwrap()
26            .as_any()
27            .downcast_ref::<String>()
28            .unwrap();
29        assert_eq!(k, &"male");
30    }
31
32    // #[test]
33    // fn test_serializing_string_html() {
34    //     let k = r#""<div xmlns=\"http://www.w3.org/1999/xhtml\">\n      <p>Dr Adam Careful is a Referring Practitioner for Acme Hospital from 1-Jan 2012 to 31-Mar\n        2012</p>\n    </div>""#;
35    //     let parsed_str_serde =
36    //         serde_json::to_string(&serde_json::from_str::<serde_json::Value>(k).unwrap()).unwrap();
37
38    //     assert_eq!(
39    //         parsed_str_serde,
40    //         haste_fhir_serialization_json::to_string(
41    //             &haste_fhir_serialization_json::from_str::<String>(k).unwrap()
42    //         )
43    //         .unwrap()
44    //     );
45    // }
46
47    #[test]
48    fn enum_resource_type_variant() {
49        let resource = serde_json::from_str::<Resource>(
50            r#"{
51            "resourceType": "Patient",
52            "address": [
53                {
54                    "use": "home",
55                    "line": ["123 Main St"],
56                    "_line": [{"id": "hello-world"}],
57                    "city": "Anytown",
58                    "_city": {
59                        "id": "city-id"
60                    },
61                    "state": "CA",
62                    "postalCode": "12345"
63                }]
64            
65            }"#,
66        );
67
68        assert!(matches!(resource, Ok(Resource::Patient(Patient { .. }))));
69
70        let resource = serde_json::from_str::<Resource>(
71            r#"{
72  "resourceType": "Practitioner",
73  "id": "example",
74  "text": {
75    "status": "generated",
76    "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n      <p>Dr Adam Careful is a Referring Practitioner for Acme Hospital from 1-Jan 2012 to 31-Mar\n        2012</p>\n    </div>"
77  },
78  "identifier": [
79    {
80      "system": "http://www.acme.org/practitioners",
81      "value": "23"
82    }
83  ],
84  "active": true,
85  "name": [
86    {
87      "family": "Careful",
88      "given": [
89        "Adam"
90      ],
91      "prefix": [
92        "Dr"
93      ]
94    }
95  ],
96  "address": [
97    {
98      "use": "home",
99      "line": [
100        "534 Erewhon St"
101      ],
102      "city": "PleasantVille",
103      "state": "Vic",
104      "postalCode": "3999"
105    }
106  ],
107  "qualification": [
108    {
109      "identifier": [
110        {
111          "system": "http://example.org/UniversityIdentifier",
112          "value": "12345"
113        }
114      ],
115      "code": {
116        "coding": [
117          {
118            "system": "http://terminology.hl7.org/CodeSystem/v2-0360/2.7",
119            "code": "BS",
120            "display": "Bachelor of Science"
121          }
122        ],
123        "text": "Bachelor of Science"
124      },
125      "period": {
126        "start": "1995"
127      },
128      "issuer": {
129        "display": "Example University"
130      }
131    }
132  ]
133}"#,
134        );
135
136        assert!(matches!(
137            resource,
138            Ok(Resource::Practitioner(Practitioner { .. }))
139        ));
140
141        assert_eq!(
142            "{\"resourceType\":\"Practitioner\",\"id\":\"example\",\"text\":{\"status\":\"generated\",\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">\\n      <p>Dr Adam Careful is a Referring Practitioner for Acme Hospital from 1-Jan 2012 to 31-Mar\\n        2012</p>\\n    </div>\"},\"identifier\":[{\"system\":\"http://www.acme.org/practitioners\",\"value\":\"23\"}],\"active\":true,\"name\":[{\"family\":\"Careful\",\"given\":[\"Adam\"],\"prefix\":[\"Dr\"]}],\"address\":[{\"use\":\"home\",\"line\":[\"534 Erewhon St\"],\"city\":\"PleasantVille\",\"state\":\"Vic\",\"postalCode\":\"3999\"}],\"qualification\":[{\"identifier\":[{\"system\":\"http://example.org/UniversityIdentifier\",\"value\":\"12345\"}],\"code\":{\"coding\":[{\"system\":\"http://terminology.hl7.org/CodeSystem/v2-0360/2.7\",\"code\":\"BS\",\"display\":\"Bachelor of Science\"}],\"text\":\"Bachelor of Science\"},\"period\":{\"start\":\"1995\"},\"issuer\":{\"display\":\"Example University\"}}]}",
143            serde_json::to_string(resource.as_ref().unwrap()).unwrap(),
144        );
145    }
146
147    #[test]
148    fn test_valid_address_with_extensions() {
149        let address_string = r#"
150        {
151            "use": "home",
152            "line": ["123 Main St"],
153            "_line": [{"id": "hello-world"}],
154            "city": "Anytown",
155            "_city": {
156                "id": "city-id"
157            },
158            "state": "CA",
159            "postalCode": "12345"
160        }
161        "#;
162        let address: Address = serde_json::from_str::<Address>(address_string).unwrap();
163
164        let address_use: Option<String> = address.use_.unwrap().as_ref().into();
165        assert_eq!(address_use.unwrap(), "home".to_string());
166        assert_eq!(
167            address.line.as_ref().unwrap()[0].value.as_ref().unwrap(),
168            &"123 Main St".to_string()
169        );
170        assert_eq!(
171            address.line.as_ref().unwrap()[0].id.as_ref().unwrap(),
172            &"hello-world".to_string()
173        );
174        assert_eq!(
175            address.city.as_ref().unwrap().value.as_ref().unwrap(),
176            &"Anytown".to_string()
177        );
178        assert_eq!(address.state.unwrap().value.unwrap(), "CA".to_string());
179        assert_eq!(
180            address.postalCode.unwrap().value.unwrap(),
181            "12345".to_string()
182        );
183        assert_eq!(
184            address.city.as_ref().unwrap().id.as_ref().unwrap(),
185            &"city-id".to_string()
186        );
187    }
188
189    #[test]
190    fn test_invalid_address_with_extensions() {
191        let address_string = r#"
192        {
193            "line": ["123 Main St"],
194            "_line": {"id": "hello-world"}
195        }
196        "#;
197        let address = serde_json::from_str::<Address>(address_string);
198        assert!(address.is_err());
199
200        let address_string = r#"
201        {
202            "city": "Anytown",
203            "_city": 5
204        }
205        "#;
206        let address = serde_json::from_str::<Address>(address_string);
207        assert!(address.is_err());
208    }
209
210    #[test]
211    fn test_invalid_fields() {
212        let address_string = r#"
213        {
214            "line": ["123 Main St"],
215            "_line": [{"id": "hello-world"}],
216            "bad_field": "This should not be here"
217        }
218        "#;
219
220        let address = serde_json::from_str::<Address>(address_string);
221
222        assert!(matches!(address, Err(_)));
223    }
224
225    #[test]
226    fn test_serialization_bundle() {
227        let bundle_string = r#"
228        {
229  "resourceType": "Bundle",
230  "id": "bundle-example",
231  "meta": {
232    "lastUpdated": "2014-08-18T01:43:30Z"
233  },
234  "type": "searchset",
235  "total": 3,
236  "link": [
237    {
238      "relation": "self",
239      "url": "https://example.com/base/MedicationRequest?patient=347&_include=MedicationRequest.medication&_count=2"
240    },
241    {
242      "relation": "next",
243      "url": "https://example.com/base/MedicationRequest?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2"
244    }
245  ],
246  "entry": [
247    {
248      "fullUrl": "https://example.com/base/MedicationRequest/3123",
249      "resource": {
250        "resourceType": "MedicationRequest",
251        "id": "3123",
252        "text": {
253          "status": "generated",
254          "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: 3123</p><p><b>status</b>: unknown</p><p><b>intent</b>: order</p><p><b>medication</b>: <a>Medication/example</a></p><p><b>subject</b>: <a>Patient/347</a></p></div>"
255        },
256        "status": "unknown",
257        "intent": "order",
258        "medicationReference": {
259          "reference": "Medication/example"
260        },
261        "subject": {
262          "reference": "Patient/347"
263        }
264      },
265      "search": {
266        "mode": "match",
267        "score": 1
268      }
269    },
270    {
271      "fullUrl": "https://example.com/base/Medication/example",
272      "resource": {
273        "resourceType": "Medication",
274        "id": "example",
275        "text": {
276          "status": "generated",
277          "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: example</p></div>"
278        }
279      },
280      "search": {
281        "mode": "include"
282      }
283    }
284  ]
285}
286        "#;
287
288        let bundle =
289            serde_json::from_str::<r4::generated::resources::Bundle>(bundle_string).unwrap();
290
291        assert!(matches!(
292            bundle.entry.as_ref().unwrap()[0]
293                .resource
294                .as_ref()
295                .unwrap()
296                .fhir_type(),
297            "MedicationRequest"
298        ));
299    }
300
301    #[test]
302    fn test_patient_resource() {
303        let patient_string = r#"
304        {
305            "resourceType": "Patient",
306            "address": [
307                {
308                    "use": "home",
309                    "line": ["123 Main St"],
310                    "_line": [{"id": "hello-world"}],
311                    "city": "Anytown",
312                    "_city": {
313                        "id": "city-id"
314                    },
315                    "state": "CA",
316                    "postalCode": "12345"
317                },
318                {
319                    "use": "home",
320                    "line": ["123 Main St"],
321                    "_line": [{"id": "hello-world"}],
322                    "city": "Anytown",
323                    "_city": {
324                        "id": "city-id"
325                    },
326                    "state": "CA",
327                    "postalCode": "12345"
328                },
329                {
330                    "use": "home",
331                    "line": ["123 Main St"],
332                    "_line": [{"id": "hello-world"}],
333                    "city": "Anytown",
334                    "_city": {
335                        "id": "city-id"
336                    },
337                    "state": "CA",
338                    "postalCode": "12345"
339                },
340                {
341                    "use": "home",
342                    "line": ["123 Main St"],
343                    "_line": [{"id": "hello-world"}],
344                    "city": "Anytown",
345                    "_city": {
346                        "id": "city-id"
347                    },
348                    "state": "CA",
349                    "postalCode": "12345"
350                },
351                {
352                    "use": "home",
353                    "line": ["123 Main St"],
354                    "_line": [{"id": "hello-world"}],
355                    "city": "Anytown",
356                    "_city": {
357                        "id": "city-id"
358                    },
359                    "state": "CA",
360                    "postalCode": "12345"
361                }
362
363            ]
364        }
365        "#
366        .trim();
367
368        let patient = serde_json::from_str::<Patient>(patient_string);
369
370        assert!(matches!(patient, Ok(Patient { .. })));
371        assert_eq!(patient.as_ref().unwrap().address.as_ref().unwrap().len(), 5);
372
373        assert_eq!(
374            patient.as_ref().unwrap().address.as_ref().unwrap()[0]
375                .city
376                .as_ref()
377                .unwrap()
378                .value
379                .as_ref()
380                .unwrap(),
381            "Anytown"
382        );
383
384        let k = "{\"resourceType\":\"Patient\",\"address\":[{\"use\":\"home\",\"_line\":[{\"id\":\"hello-world\"}],\"line\":[\"123 Main St\"],\"city\":\"Anytown\",\"_city\":{\"id\":\"city-id\"},\"state\":\"CA\",\"postalCode\":\"12345\"},{\"use\":\"home\",\"_line\":[{\"id\":\"hello-world\"}],\"line\":[\"123 Main St\"],\"city\":\"Anytown\",\"_city\":{\"id\":\"city-id\"},\"state\":\"CA\",\"postalCode\":\"12345\"},{\"use\":\"home\",\"_line\":[{\"id\":\"hello-world\"}],\"line\":[\"123 Main St\"],\"city\":\"Anytown\",\"_city\":{\"id\":\"city-id\"},\"state\":\"CA\",\"postalCode\":\"12345\"},{\"use\":\"home\",\"_line\":[{\"id\":\"hello-world\"}],\"line\":[\"123 Main St\"],\"city\":\"Anytown\",\"_city\":{\"id\":\"city-id\"},\"state\":\"CA\",\"postalCode\":\"12345\"},{\"use\":\"home\",\"_line\":[{\"id\":\"hello-world\"}],\"line\":[\"123 Main St\"],\"city\":\"Anytown\",\"_city\":{\"id\":\"city-id\"},\"state\":\"CA\",\"postalCode\":\"12345\"}]}";
385
386        assert_eq!(k, serde_json::to_string(patient.as_ref().unwrap()).unwrap());
387
388        let patient2 = serde_json::from_str::<Patient>(k).unwrap();
389        assert_eq!(serde_json::to_string(&patient2).unwrap(), k);
390    }
391
392    #[test]
393    fn null_extension_many() {
394        let patient_string = r#"
395        {
396            "resourceType": "Patient",
397            "name": [
398                {
399                    "family": "Doe",
400                    "given": ["John", "A."],
401                    "_given": [null, {"id": "given-2"}],
402                    "prefix": ["Mr."]
403                }
404            ]
405        }"#;
406
407        let patient = serde_json::from_str::<Patient>(patient_string).unwrap();
408
409        assert_eq!(
410            patient.name.as_ref().unwrap()[0].given.as_ref().unwrap()[0]
411                .value
412                .as_ref()
413                .unwrap(),
414            "John"
415        );
416
417        assert_eq!(
418            patient.name.as_ref().unwrap()[0].given.as_ref().unwrap()[0]
419                .id
420                .is_none(),
421            true,
422        );
423
424        assert_eq!(
425            patient.name.as_ref().unwrap()[0].given.as_ref().unwrap()[1]
426                .id
427                .as_ref()
428                .unwrap(),
429            "given-2",
430        );
431
432        assert_eq!(
433            serde_json::to_string(&patient).unwrap(),
434            "{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"Doe\",\"_given\":[null,{\"id\":\"given-2\"}],\"given\":[\"John\",\"A.\"],\"prefix\":[\"Mr.\"]}]}"
435        );
436    }
437
438    #[test]
439    fn test_with_nulls_array_primitives() {
440        let patient_string = r#"{
441        "resourceType": "Patient",
442        "name": [
443          {
444            "family": "Doe",
445            "_given": [
446              null,
447              {
448                "id": "given-2"
449              }
450            ],
451            "given": [
452              "John",
453              null
454            ],
455            "prefix": [
456              "Mr."
457            ]
458          }
459        ]}"#;
460
461        let patient = serde_json::from_str::<Patient>(patient_string).unwrap();
462        assert_eq!(
463            serde_json::to_string(&patient).unwrap(),
464            "{\"resourceType\":\"Patient\",\"name\":[{\"family\":\"Doe\",\"_given\":[null,{\"id\":\"given-2\"}],\"given\":[\"John\",null],\"prefix\":[\"Mr.\"]}]}"
465        );
466    }
467
468    #[test]
469    fn test_serde_terminology() {
470        use crate::r4::generated::terminology::AdministrativeGender;
471
472        let admin_gender = serde_json::from_str::<AdministrativeGender>("\"male\"");
473
474        assert!(matches!(admin_gender, Ok(AdministrativeGender::Male(None))));
475    }
476
477    #[test]
478    fn test_serde_primitve() {
479        use crate::r4::generated::types::{
480            FHIRBoolean, FHIRDate, FHIRDecimal, FHIRInteger, FHIRPositiveInt, FHIRString,
481        };
482
483        let date = serde_json::from_str::<FHIRDate>("\"2020-01-01\"");
484
485        assert!(matches!(
486            date,
487            Ok(FHIRDate {
488                value: Some(Date::YearMonthDay(2020, 1, 1)),
489                id: None,
490                extension: None
491            })
492        ));
493
494        let date = serde_json::from_str::<FHIRDate>("\"bad\"");
495
496        assert!(matches!(date, Err(_)));
497
498        let fhir_string = serde_json::from_str::<FHIRString>("\"hello\"");
499
500        assert!(matches!(
501            fhir_string,
502            Ok(FHIRString {
503                value: Some(_),
504                id: None,
505                extension: None
506            })
507        ));
508
509        let fhir_boolean = serde_json::from_str::<FHIRBoolean>("true");
510
511        assert!(matches!(
512            fhir_boolean,
513            Ok(FHIRBoolean {
514                value: Some(true),
515                id: None,
516                extension: None
517            })
518        ));
519
520        let fhir_boolean = serde_json::from_str::<FHIRBoolean>("false");
521
522        assert!(matches!(
523            fhir_boolean,
524            Ok(FHIRBoolean {
525                value: Some(false),
526                id: None,
527                extension: None
528            })
529        ));
530
531        let fhir_integer = serde_json::from_str::<FHIRInteger>("42");
532        assert!(matches!(
533            fhir_integer,
534            Ok(FHIRInteger {
535                value: Some(42),
536                id: None,
537                extension: None
538            })
539        ));
540
541        let fhir_positive_int = serde_json::from_str::<FHIRPositiveInt>("42");
542
543        assert!(matches!(
544            fhir_positive_int,
545            Ok(FHIRPositiveInt {
546                value: Some(42),
547                id: None,
548                extension: None
549            })
550        ));
551
552        let invalid_fhir_positive_int = serde_json::from_str::<FHIRPositiveInt>("42.5");
553        assert!(matches!(invalid_fhir_positive_int, Err(_)));
554
555        let invalid_positive_int = serde_json::from_str::<FHIRPositiveInt>("-1");
556        assert!(matches!(invalid_positive_int, Err(_)));
557
558        let fhir_decimal = serde_json::from_str::<FHIRDecimal>("3.14");
559        assert!(matches!(
560            fhir_decimal,
561            Ok(FHIRDecimal {
562                value: Some(3.14),
563                id: None,
564                extension: None
565            })
566        ));
567    }
568
569    #[test]
570    fn test_cardinality() {
571        let client_application_string = r#"{
572	    "id": "cli",
573        "resourceType": "ClientApplication",
574        "name": "CLI",
575        "grantType": ["authorization_code"],
576        "responseTypes": "token",
577        "secret": "testing",
578        "redirectUri": [
579          "http://localhost:8080/1", 
580          "http://localhost:8080/2", 
581          "http://localhost:8080/3", 
582          "http://localhost:8080/4", 
583          "http://localhost:8080/5"],
584        "scope": "openid system/*.*"
585      }"#;
586
587        let client_app = serde_json::from_str::<ClientApplication>(&client_application_string);
588
589        assert!(client_app.is_ok());
590
591        let client_application_string = r#"{
592	    "id": "cli",
593        "resourceType": "ClientApplication",
594        "name": "CLI",
595        "grantType": ["authorization_code"],
596        "responseTypes": "token",
597        "secret": "testing",
598        "redirectUri": [
599          "http://localhost:8080/1", 
600          "http://localhost:8080/2", 
601          "http://localhost:8080/3", 
602          "http://localhost:8080/4", 
603          "http://localhost:8080/5", 
604          "http://localhost:8080/6"],
605        "scope": "openid system/*.*"
606      }"#;
607
608        let client_app = serde_json::from_str::<ClientApplication>(&client_application_string);
609
610        assert!(client_app.is_err());
611    }
612
613    #[test]
614    fn test_empty_vec() {
615        let patient = r#"{
616            "resourceType": "Patient",
617            "name": []
618        }"#;
619
620        let patient =
621            serde_json::from_str::<Patient>(patient).expect("failed to deserialize patient");
622
623        assert_eq!(patient.name.is_none(), true);
624    }
625
626    #[test]
627    fn test_empty_fields() {
628        let patient = r#"{
629            "id": "",
630            "resourceType": "Patient",
631            "name": [{"family": "", "given": [""], "prefix": [""]}]
632        }"#;
633        let patient = serde_json::from_str::<Patient>(patient).unwrap();
634
635        assert_eq!(patient.name.is_none(), true);
636
637        let patient = r#"{
638            "id": "",
639            "resourceType": "Patient",
640            "name": [{"family": "test", "given": [""], "prefix": [""]}]
641        }"#;
642        let patient = serde_json::from_str::<Patient>(patient).unwrap();
643        let name = patient.name.unwrap()[0].clone();
644
645        assert_eq!(
646            name.family
647                .as_ref()
648                .and_then(|s| s.value.as_ref())
649                .map(|s| s.as_str()),
650            Some("test")
651        );
652        assert_eq!(name.given.is_none(), true);
653        assert_eq!(name.prefix.is_none(), true);
654
655        let patient = r#"{
656            "id": "",
657            "resourceType": "Patient",
658            "name": [{"family": "", "given": [""], "prefix": ["mr"]}]
659        }"#;
660        let patient = serde_json::from_str::<Patient>(patient).unwrap();
661        let name = patient.name.unwrap()[0].clone();
662
663        assert_eq!(
664            name.prefix.clone().unwrap()[0]
665                .value
666                .as_ref()
667                .map(|s| s.as_str()),
668            Some("mr")
669        );
670        assert_eq!(name.family.is_none(), true);
671        assert_eq!(name.given.is_none(), true);
672    }
673}