1use 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}