1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8use super::Checksum;
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
14#[serde(rename_all = "camelCase")]
15pub struct DocumentCreationInformation {
16 pub spdx_version: String,
18
19 pub data_license: String,
21
22 #[serde(rename = "SPDXID")]
24 pub spdx_identifier: String,
25
26 #[serde(rename = "name")]
28 pub document_name: String,
29
30 #[serde(rename = "documentNamespace")]
32 pub spdx_document_namespace: String,
33
34 #[serde(
36 rename = "externalDocumentRefs",
37 skip_serializing_if = "Vec::is_empty",
38 default
39 )]
40 pub external_document_references: Vec<ExternalDocumentReference>,
41
42 pub creation_info: CreationInfo,
43
44 #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
46 pub document_comment: Option<String>,
47
48 #[serde(skip_serializing_if = "Vec::is_empty", default)]
51 pub document_describes: Vec<String>,
52}
53
54impl Default for DocumentCreationInformation {
55 fn default() -> Self {
56 Self {
57 spdx_version: "SPDX-2.2".to_string(),
60 data_license: "CC0-1.0".to_string(),
61 spdx_identifier: "SPDXRef-DOCUMENT".to_string(),
62 document_name: "NOASSERTION".to_string(),
63 spdx_document_namespace: "NOASSERTION".to_string(),
64 external_document_references: Vec::new(),
65 document_comment: None,
66 creation_info: CreationInfo::default(),
67 document_describes: Vec::new(),
68 }
69 }
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
73#[serde(rename_all = "camelCase")]
74pub struct CreationInfo {
75 #[serde(skip_serializing_if = "Option::is_none", default)]
77 pub license_list_version: Option<String>,
78
79 pub creators: Vec<String>,
81
82 pub created: DateTime<Utc>,
84
85 #[serde(skip_serializing_if = "Option::is_none", default)]
87 #[serde(rename = "comment")]
88 pub creator_comment: Option<String>,
89}
90
91impl Default for CreationInfo {
92 fn default() -> Self {
93 Self {
94 license_list_version: None,
95 creators: vec![
96 "Person: Jane Doe ()".into(),
97 "Organization: ExampleCodeInspect ()".into(),
98 "Tool: LicenseFind-1.0".into(),
99 ],
100 created: chrono::offset::Utc::now(),
101 creator_comment: None,
102 }
103 }
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd)]
108pub struct ExternalDocumentReference {
109 #[serde(rename = "externalDocumentId")]
111 pub id_string: String,
112
113 #[serde(rename = "spdxDocument")]
115 pub spdx_document_uri: String,
116
117 pub checksum: Checksum,
120}
121
122impl ExternalDocumentReference {
123 pub const fn new(id_string: String, spdx_document_uri: String, checksum: Checksum) -> Self {
124 Self {
125 id_string,
126 spdx_document_uri,
127 checksum,
128 }
129 }
130}
131
132#[cfg(test)]
133mod test {
134 use std::fs::read_to_string;
135
136 use chrono::{TimeZone, Utc};
137
138 use super::*;
139 use crate::models::{Algorithm, SPDX};
140
141 #[test]
142 fn spdx_version() {
143 let spdx: SPDX = serde_json::from_str(
144 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
145 )
146 .unwrap();
147
148 assert_eq!(
149 spdx.document_creation_information.spdx_version,
150 "SPDX-2.2".to_string()
151 );
152 }
153 #[test]
154 fn data_license() {
155 let spdx: SPDX = serde_json::from_str(
156 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
157 )
158 .unwrap();
159
160 assert_eq!(spdx.document_creation_information.data_license, "CC0-1.0");
161 }
162 #[test]
163 fn spdx_identifier() {
164 let spdx: SPDX = serde_json::from_str(
165 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
166 )
167 .unwrap();
168 assert_eq!(
169 spdx.document_creation_information.spdx_identifier,
170 "SPDXRef-DOCUMENT".to_string()
171 );
172 }
173 #[test]
174 fn document_name() {
175 let spdx: SPDX = serde_json::from_str(
176 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
177 )
178 .unwrap();
179 assert_eq!(
180 spdx.document_creation_information.document_name,
181 "SPDX-Tools-v2.0".to_string()
182 );
183 }
184 #[test]
185 fn spdx_document_namespace() {
186 let spdx: SPDX = serde_json::from_str(
187 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
188 )
189 .unwrap();
190 assert_eq!(
191 spdx.document_creation_information.spdx_document_namespace,
192 "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301"
193 .to_string()
194 );
195 }
196 #[test]
197 fn license_list_version() {
198 let spdx: SPDX = serde_json::from_str(
199 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
200 )
201 .unwrap();
202 assert_eq!(
203 spdx.document_creation_information
204 .creation_info
205 .license_list_version,
206 Some("3.9".to_string())
207 );
208 }
209 #[test]
210 fn creators() {
211 let spdx: SPDX = serde_json::from_str(
212 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
213 )
214 .unwrap();
215 assert!(spdx
216 .document_creation_information
217 .creation_info
218 .creators
219 .contains(&"Tool: LicenseFind-1.0".to_string()));
220 assert!(spdx
221 .document_creation_information
222 .creation_info
223 .creators
224 .contains(&"Organization: ExampleCodeInspect ()".to_string()));
225 assert!(spdx
226 .document_creation_information
227 .creation_info
228 .creators
229 .contains(&"Person: Jane Doe ()".to_string()));
230 }
231 #[test]
232 fn created() {
233 let spdx: SPDX = serde_json::from_str(
234 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
235 )
236 .unwrap();
237 assert_eq!(
238 spdx.document_creation_information.creation_info.created,
239 Utc.with_ymd_and_hms(2010, 1, 29, 18, 30, 22).unwrap()
240 );
241 }
242 #[test]
243 fn creator_comment() {
244 let spdx: SPDX = serde_json::from_str(
245 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
246 )
247 .unwrap();
248 assert_eq!(
249 spdx.document_creation_information
250 .creation_info
251 .creator_comment,
252 Some(
253 r#"This package has been shipped in source and binary form.
254The binaries were created with gcc 4.5.1 and expect to link to
255compatible system run time libraries."#
256 .to_string()
257 )
258 );
259 }
260 #[test]
261 fn document_comment() {
262 let spdx: SPDX = serde_json::from_str(
263 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
264 )
265 .unwrap();
266 assert_eq!(
267 spdx.document_creation_information.document_comment,
268 Some(
269 "This document was created using SPDX 2.0 using licenses from the web site."
270 .to_string()
271 )
272 );
273 }
274
275 #[test]
276 fn external_document_references() {
277 let spdx: SPDX = serde_json::from_str(
278 &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
279 )
280 .unwrap();
281 assert!(spdx
282 .document_creation_information
283 .external_document_references
284 .contains(&ExternalDocumentReference {
285 id_string: "DocumentRef-spdx-tool-1.2".to_string(),
286 checksum: Checksum {
287 algorithm: Algorithm::SHA1,
288 value: "d6a770ba38583ed4bb4525bd96e50461655d2759".to_string()
289 },
290 spdx_document_uri:
291 "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
292 .to_string()
293 }));
294 }
295}