spdx_rs/models/
document_creation_information.rs

1// SPDX-FileCopyrightText: 2020-2021 HH Partners
2//
3// SPDX-License-Identifier: MIT
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8use super::Checksum;
9
10/// ## Document Creation Information
11///
12/// SPDX's [Document Creation Information](https://spdx.github.io/spdx-spec/2-document-creation-information/)
13#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
14#[serde(rename_all = "camelCase")]
15pub struct DocumentCreationInformation {
16    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#21-spdx-version>
17    pub spdx_version: String,
18
19    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#22-data-license>
20    pub data_license: String,
21
22    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#23-spdx-identifier>
23    #[serde(rename = "SPDXID")]
24    pub spdx_identifier: String,
25
26    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#24-document-name>
27    #[serde(rename = "name")]
28    pub document_name: String,
29
30    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#25-spdx-document-namespace>
31    #[serde(rename = "documentNamespace")]
32    pub spdx_document_namespace: String,
33
34    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#26-external-document-references>
35    #[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    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#211-document-comment>
45    #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
46    pub document_comment: Option<String>,
47
48    /// Doesn't seem to be in spec, but the example contains it.
49    /// <https://github.com/spdx/spdx-spec/issues/395>
50    #[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            // Current version is 2.2. Might need to support more verisons
58            // in the future.
59            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    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#27-license-list-version>
76    #[serde(skip_serializing_if = "Option::is_none", default)]
77    pub license_list_version: Option<String>,
78
79    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#28-creator>
80    pub creators: Vec<String>,
81
82    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#29-created>
83    pub created: DateTime<Utc>,
84
85    /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#210-creator-comment>
86    #[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/// <https://spdx.github.io/spdx-spec/2-document-creation-information/#26-external-document-references>
107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd)]
108pub struct ExternalDocumentReference {
109    /// Unique ID string of the reference.
110    #[serde(rename = "externalDocumentId")]
111    pub id_string: String,
112
113    /// Unique ID for the external document.
114    #[serde(rename = "spdxDocument")]
115    pub spdx_document_uri: String,
116
117    /// Checksum of the external document following the checksum format defined
118    /// in <https://spdx.github.io/spdx-spec/4-file-information/#44-file-checksum.>
119    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}