Skip to main content

oparl_types/
system.rs

1// SPDX-FileCopyrightText: Politik im Blick developers
2// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2
5
6use crate::{
7    BodyListUrl, DateTime, EmailAddress, Name, OParlVersion, SystemUrl, Url,
8    namespace::SystemNamespaceUrl,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct System {
14    pub id: SystemUrl,
15
16    #[serde(rename = "type")]
17    pub namespace: SystemNamespaceUrl,
18
19    pub oparl_version: OParlVersion,
20
21    #[serde(default, skip_serializing_if = "Vec::is_empty")]
22    pub other_oparl_versions: Vec<Url>,
23
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub license: Option<Url>,
26
27    pub body: BodyListUrl,
28
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub name: Option<Name>,
31
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub contact_email: Option<EmailAddress>,
34
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub contact_name: Option<Name>,
37
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub website: Option<Url>,
40
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub vendor: Option<Url>,
43
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub product: Option<Url>,
46
47    pub created: DateTime,
48
49    pub modified: DateTime,
50
51    #[serde(default, skip_serializing_if = "Option::is_none")]
52    pub web: Option<Url>,
53
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub deleted: Option<bool>,
56
57    #[serde(default, flatten)]
58    pub extensions: serde_json::Map<String, serde_json::Value>,
59}
60
61#[cfg(test)]
62mod serde_tests {
63    use pretty_assertions::assert_eq;
64    use serde_json::json;
65    use time::macros::datetime;
66
67    use super::System;
68    use crate::{OParlVersion, namespace::SystemNamespaceUrl};
69
70    fn example_system() -> System {
71        System {
72            id: "https://oparl.example.org/"
73                .parse()
74                .expect("value must be parseable as id"),
75            namespace: SystemNamespaceUrl::Identifier,
76            oparl_version: OParlVersion::Version1_1,
77            other_oparl_versions: vec![
78                "https://oparl2.example.org/"
79                    .parse()
80                    .expect("value must be parseable as url"),
81            ],
82            license: None,
83            body: "https://oparl.example.org/bodies"
84                .parse()
85                .expect("value must be parseable as url"),
86            name: Some(
87                "Beispiel-System"
88                    .parse()
89                    .expect("value must be parseable as name"),
90            ),
91            contact_email: Some(
92                "info@example.org"
93                    .parse()
94                    .expect("value must be parseable as email"),
95            ),
96            contact_name: Some(
97                "Allgemeiner OParl Kontakt"
98                    .parse()
99                    .expect("value must be parseable as name"),
100            ),
101            website: Some(
102                "http://www.example.org/"
103                    .parse()
104                    .expect("value must be parseable as url"),
105            ),
106            vendor: Some(
107                "http://example-software.com/"
108                    .parse()
109                    .expect("value must be parseable as url"),
110            ),
111            product: Some(
112                "http://example-software.com/oparl-server/"
113                    .parse()
114                    .expect("value must be parseable as url"),
115            ),
116            created: datetime!(2011-11-11 11:11:00 +01:00).into(),
117            modified: datetime!(2012-11-11 11:11:00 +01:00).into(),
118            web: None,
119            deleted: None,
120            extensions: serde_json::Map::new(),
121        }
122    }
123
124    fn example_system_json() -> serde_json::Value {
125        json!({
126            "id": "https://oparl.example.org/",
127            "type": "https://schema.oparl.org/1.1/System",
128            "oparlVersion": "https://schema.oparl.org/1.1/",
129            "body": "https://oparl.example.org/bodies",
130            "name": "Beispiel-System",
131            "contactEmail": "info@example.org",
132            "contactName": "Allgemeiner OParl Kontakt",
133            "website": "http://www.example.org/",
134            "vendor": "http://example-software.com/",
135            "product": "http://example-software.com/oparl-server/",
136            "otherOparlVersions": [
137                "https://oparl2.example.org/"
138            ],
139            "created": "2011-11-11T11:11:00+01:00",
140            "modified": "2012-11-11T11:11:00+01:00"
141        })
142    }
143
144    #[test]
145    fn serialize() {
146        assert_eq!(json!(example_system()), example_system_json());
147    }
148
149    #[test]
150    fn serialize_with_extensions() {
151        let extensions = json!({"pib:hello":"world", "pib:status":"new"})
152            .as_object()
153            .cloned()
154            .unwrap();
155
156        let mut example_system = example_system();
157        example_system.extensions = extensions;
158
159        let mut example_system_json = example_system_json();
160        {
161            let extensions = example_system_json.as_object_mut().unwrap();
162            extensions.insert("pib:hello".into(), "world".into());
163            extensions.insert("pib:status".into(), "new".into());
164        }
165
166        assert_eq!(json!(example_system), example_system_json);
167    }
168
169    #[test]
170    fn deserialize_good() {
171        let deserialized: System = serde_json::from_value(example_system_json())
172            .expect("value must be deserializable as System");
173        assert_eq!(deserialized, example_system());
174    }
175
176    #[test]
177    fn deserialize_with_extensions() {
178        let extensions = json!({"pib:hello":"world", "pib:status":"new"})
179            .as_object()
180            .cloned()
181            .unwrap();
182
183        let mut example_system = example_system();
184        example_system.extensions = extensions;
185        let mut example_system_json = example_system_json();
186        {
187            let extensions = example_system_json.as_object_mut().unwrap();
188            extensions.insert("pib:hello".into(), "world".into());
189            extensions.insert("pib:status".into(), "new".into());
190        }
191
192        let deserialized: System = serde_json::from_value(example_system_json)
193            .expect("value must be deserializable as System");
194
195        assert_eq!(deserialized, example_system);
196        assert_eq!(deserialized.extensions.len(), 2);
197        assert_eq!(deserialized.extensions["pib:hello"], "world");
198        assert_eq!(deserialized.extensions["pib:status"], "new");
199    }
200
201    #[test]
202    fn deserialize_bad() {
203        assert!(serde_json::from_value::<System>(json!("xyzabcd")).is_err());
204        assert!(serde_json::from_value::<System>(json!(true)).is_err());
205        assert!(serde_json::from_value::<System>(json!(123)).is_err());
206    }
207}