summaryrefslogtreecommitdiffstats
path: root/vendor/spdx-rs/src/models
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/spdx-rs/src/models')
-rw-r--r--vendor/spdx-rs/src/models/annotation.rs114
-rw-r--r--vendor/spdx-rs/src/models/checksum.rs46
-rw-r--r--vendor/spdx-rs/src/models/document_creation_information.rs295
-rw-r--r--vendor/spdx-rs/src/models/file_information.rs313
-rw-r--r--vendor/spdx-rs/src/models/mod.rs24
-rw-r--r--vendor/spdx-rs/src/models/other_licensing_information_detected.rs97
-rw-r--r--vendor/spdx-rs/src/models/package_information.rs555
-rw-r--r--vendor/spdx-rs/src/models/relationship.rs138
-rw-r--r--vendor/spdx-rs/src/models/snippet.rs237
-rw-r--r--vendor/spdx-rs/src/models/spdx_document.rs330
10 files changed, 2149 insertions, 0 deletions
diff --git a/vendor/spdx-rs/src/models/annotation.rs b/vendor/spdx-rs/src/models/annotation.rs
new file mode 100644
index 000000000..f5396aa1d
--- /dev/null
+++ b/vendor/spdx-rs/src/models/annotation.rs
@@ -0,0 +1,114 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+
+/// <https://spdx.github.io/spdx-spec/8-annotations/>
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct Annotation {
+ /// <https://spdx.github.io/spdx-spec/8-annotations/#81-annotator>
+ pub annotator: String,
+
+ /// <https://spdx.github.io/spdx-spec/8-annotations/#82-annotation-date>
+ pub annotation_date: DateTime<Utc>,
+
+ /// <https://spdx.github.io/spdx-spec/8-annotations/#83-annotation-type>
+ pub annotation_type: AnnotationType,
+
+ /// <https://spdx.github.io/spdx-spec/8-annotations/#84-spdx-identifier-reference>
+ // TODO: According to the spec this is mandatory, but the example file doesn't
+ // have it.
+ pub spdx_identifier_reference: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/8-annotations/#85-annotation-comment>
+ #[serde(rename = "comment")]
+ pub annotation_comment: String,
+}
+
+impl Annotation {
+ pub fn new(
+ annotator: String,
+ annotation_date: DateTime<Utc>,
+ annotation_type: AnnotationType,
+ spdx_identifier_reference: Option<String>,
+ annotation_comment: String,
+ ) -> Self {
+ Self {
+ annotator,
+ annotation_date,
+ annotation_type,
+ spdx_identifier_reference,
+ annotation_comment,
+ }
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/8-annotations/#83-annotation-type>
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum AnnotationType {
+ Review,
+ Other,
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use chrono::TimeZone;
+
+ use crate::models::SPDX;
+
+ use super::*;
+
+ #[test]
+ fn annotator() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx_file.annotations[0].annotator,
+ "Person: Jane Doe ()".to_string()
+ );
+ }
+
+ #[test]
+ fn annotation_date() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx_file.annotations[0].annotation_date,
+ Utc.ymd(2010, 1, 29).and_hms(18, 30, 22)
+ );
+ }
+
+ #[test]
+ fn annotation_type() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx_file.annotations[0].annotation_type,
+ AnnotationType::Other
+ );
+ }
+
+ #[test]
+ fn annotation_comment() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx_file.annotations[0].annotation_comment,
+ "Document level annotation"
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/checksum.rs b/vendor/spdx-rs/src/models/checksum.rs
new file mode 100644
index 000000000..bd91f4c7a
--- /dev/null
+++ b/vendor/spdx-rs/src/models/checksum.rs
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+
+/// Representation of SPDX's
+/// [Package Checksum](https://spdx.github.io/spdx-spec/3-package-information/#310-package-checksum)
+/// and
+/// [File Checksum](https://spdx.github.io/spdx-spec/4-file-information/#44-file-checksum).
+/// According to the spec, SHA1 is mandatory but we don't currently enforce that.
+#[derive(Debug, Serialize, Deserialize, PartialEq, PartialOrd, Clone)]
+pub struct Checksum {
+ /// Algorithm used to calculate the checksum
+ pub algorithm: Algorithm,
+
+ /// The checksum value.
+ #[serde(rename = "checksumValue")]
+ pub value: String,
+}
+
+impl Checksum {
+ /// Create new checksum.
+ pub fn new(algorithm: Algorithm, value: &str) -> Self {
+ Self {
+ algorithm,
+ value: value.to_lowercase(),
+ }
+ }
+}
+
+/// Possible algorithms to be used for SPDX's
+/// [package checksum](https://spdx.github.io/spdx-spec/3-package-information/#310-package-checksum)
+/// and [file checksum](https://spdx.github.io/spdx-spec/4-file-information/#44-file-checksum).
+#[derive(Debug, Serialize, Deserialize, PartialEq, PartialOrd, Clone, Copy)]
+pub enum Algorithm {
+ SHA1,
+ SHA224,
+ SHA256,
+ SHA384,
+ SHA512,
+ MD2,
+ MD4,
+ MD5,
+ MD6,
+}
diff --git a/vendor/spdx-rs/src/models/document_creation_information.rs b/vendor/spdx-rs/src/models/document_creation_information.rs
new file mode 100644
index 000000000..610803354
--- /dev/null
+++ b/vendor/spdx-rs/src/models/document_creation_information.rs
@@ -0,0 +1,295 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+
+use super::Checksum;
+
+/// ## Document Creation Information
+///
+/// SPDX's [Document Creation Information](https://spdx.github.io/spdx-spec/2-document-creation-information/)
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct DocumentCreationInformation {
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#21-spdx-version>
+ pub spdx_version: String,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#22-data-license>
+ pub data_license: String,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#23-spdx-identifier>
+ #[serde(rename = "SPDXID")]
+ pub spdx_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#24-document-name>
+ #[serde(rename = "name")]
+ pub document_name: String,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#25-spdx-document-namespace>
+ #[serde(rename = "documentNamespace")]
+ pub spdx_document_namespace: String,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#26-external-document-references>
+ #[serde(
+ rename = "externalDocumentRefs",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub external_document_references: Vec<ExternalDocumentReference>,
+
+ pub creation_info: CreationInfo,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#211-document-comment>
+ #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
+ pub document_comment: Option<String>,
+
+ /// Doesn't seem to be in spec, but the example contains it.
+ /// <https://github.com/spdx/spdx-spec/issues/395>
+ #[serde(skip_serializing_if = "Vec::is_empty", default)]
+ pub document_describes: Vec<String>,
+}
+
+impl Default for DocumentCreationInformation {
+ fn default() -> Self {
+ Self {
+ // Current version is 2.2. Might need to support more verisons
+ // in the future.
+ spdx_version: "SPDX-2.2".to_string(),
+ data_license: "CC0-1.0".to_string(),
+ spdx_identifier: "SPDXRef-DOCUMENT".to_string(),
+ document_name: "NOASSERTION".to_string(),
+ spdx_document_namespace: "NOASSERTION".to_string(),
+ external_document_references: Vec::new(),
+ document_comment: None,
+ creation_info: CreationInfo::default(),
+ document_describes: Vec::new(),
+ }
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct CreationInfo {
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#27-license-list-version>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ pub license_list_version: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#28-creator>
+ pub creators: Vec<String>,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#29-created>
+ pub created: DateTime<Utc>,
+
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/#210-creator-comment>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ #[serde(rename = "comment")]
+ pub creator_comment: Option<String>,
+}
+
+impl Default for CreationInfo {
+ fn default() -> Self {
+ Self {
+ license_list_version: None,
+ creators: vec![
+ "Person: Jane Doe ()".into(),
+ "Organization: ExampleCodeInspect ()".into(),
+ "Tool: LicenseFind-1.0".into(),
+ ],
+ created: chrono::offset::Utc::now(),
+ creator_comment: None,
+ }
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/2-document-creation-information/#26-external-document-references>
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
+pub struct ExternalDocumentReference {
+ /// Unique ID string of the reference.
+ #[serde(rename = "externalDocumentId")]
+ pub id_string: String,
+
+ /// Unique ID for the external document.
+ #[serde(rename = "spdxDocument")]
+ pub spdx_document_uri: String,
+
+ /// Checksum of the external document following the checksum format defined
+ /// in <https://spdx.github.io/spdx-spec/4-file-information/#44-file-checksum.>
+ pub checksum: Checksum,
+}
+
+impl ExternalDocumentReference {
+ pub const fn new(id_string: String, spdx_document_uri: String, checksum: Checksum) -> Self {
+ Self {
+ id_string,
+ spdx_document_uri,
+ checksum,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use chrono::{TimeZone, Utc};
+
+ use super::*;
+ use crate::models::{Algorithm, SPDX};
+
+ #[test]
+ fn spdx_version() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(
+ spdx.document_creation_information.spdx_version,
+ "SPDX-2.2".to_string()
+ );
+ }
+ #[test]
+ fn data_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(spdx.document_creation_information.data_license, "CC0-1.0");
+ }
+ #[test]
+ fn spdx_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information.spdx_identifier,
+ "SPDXRef-DOCUMENT".to_string()
+ );
+ }
+ #[test]
+ fn document_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information.document_name,
+ "SPDX-Tools-v2.0".to_string()
+ );
+ }
+ #[test]
+ fn spdx_document_namespace() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information.spdx_document_namespace,
+ "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301"
+ .to_string()
+ );
+ }
+ #[test]
+ fn license_list_version() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information
+ .creation_info
+ .license_list_version,
+ Some("3.9".to_string())
+ );
+ }
+ #[test]
+ fn creators() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(spdx
+ .document_creation_information
+ .creation_info
+ .creators
+ .contains(&"Tool: LicenseFind-1.0".to_string()));
+ assert!(spdx
+ .document_creation_information
+ .creation_info
+ .creators
+ .contains(&"Organization: ExampleCodeInspect ()".to_string()));
+ assert!(spdx
+ .document_creation_information
+ .creation_info
+ .creators
+ .contains(&"Person: Jane Doe ()".to_string()));
+ }
+ #[test]
+ fn created() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information.creation_info.created,
+ Utc.ymd(2010, 1, 29).and_hms(18, 30, 22)
+ );
+ }
+ #[test]
+ fn creator_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information
+ .creation_info
+ .creator_comment,
+ Some(
+ r#"This package has been shipped in source and binary form.
+The binaries were created with gcc 4.5.1 and expect to link to
+compatible system run time libraries."#
+ .to_string()
+ )
+ );
+ }
+ #[test]
+ fn document_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.document_creation_information.document_comment,
+ Some(
+ "This document was created using SPDX 2.0 using licenses from the web site."
+ .to_string()
+ )
+ );
+ }
+
+ #[test]
+ fn external_document_references() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(spdx
+ .document_creation_information
+ .external_document_references
+ .contains(&ExternalDocumentReference {
+ id_string: "DocumentRef-spdx-tool-1.2".to_string(),
+ checksum: Checksum {
+ algorithm: Algorithm::SHA1,
+ value: "d6a770ba38583ed4bb4525bd96e50461655d2759".to_string()
+ },
+ spdx_document_uri:
+ "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
+ .to_string()
+ }));
+ }
+}
diff --git a/vendor/spdx-rs/src/models/file_information.rs b/vendor/spdx-rs/src/models/file_information.rs
new file mode 100644
index 000000000..f2db6e030
--- /dev/null
+++ b/vendor/spdx-rs/src/models/file_information.rs
@@ -0,0 +1,313 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+use spdx_expression::{SimpleExpression, SpdxExpression};
+
+use super::{Algorithm, Checksum};
+
+/// ## File Information
+///
+/// SPDX's [File Information](https://spdx.github.io/spdx-spec/4-file-information/)
+#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct FileInformation {
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#41-file-name>
+ pub file_name: String,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#42-file-spdx-identifier>
+ #[serde(rename = "SPDXID")]
+ pub file_spdx_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#43-file-type>
+ #[serde(rename = "fileTypes", skip_serializing_if = "Vec::is_empty", default)]
+ pub file_type: Vec<FileType>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#44-file-checksum>
+ #[serde(rename = "checksums")]
+ pub file_checksum: Vec<Checksum>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#45-concluded-license>
+ #[serde(rename = "licenseConcluded")]
+ pub concluded_license: SpdxExpression,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#46-license-information-in-file>
+ #[serde(rename = "licenseInfoInFiles")]
+ pub license_information_in_file: Vec<SimpleExpression>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#47-comments-on-license>
+ #[serde(
+ rename = "licenseComments",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub comments_on_license: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#48-copyright-text>
+ pub copyright_text: String,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#412-file-comment>
+ #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
+ pub file_comment: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#413-file-notice>
+ #[serde(
+ rename = "noticeText",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub file_notice: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#414-file-contributor>
+ #[serde(
+ rename = "fileContributors",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub file_contributor: Vec<String>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/#415-file-attribution-text>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ pub file_attribution_text: Option<Vec<String>>,
+ // TODO: Snippet Information.
+}
+
+impl Default for FileInformation {
+ fn default() -> Self {
+ Self {
+ file_name: "NOASSERTION".to_string(),
+ file_spdx_identifier: "NOASSERTION".to_string(),
+ file_type: Vec::new(),
+ file_checksum: Vec::new(),
+ concluded_license: SpdxExpression::parse("NOASSERTION").expect("will always succeed"),
+ license_information_in_file: Vec::new(),
+ comments_on_license: None,
+ copyright_text: "NOASSERTION".to_string(),
+ file_comment: None,
+ file_notice: None,
+ file_contributor: Vec::new(),
+ file_attribution_text: None,
+ }
+ }
+}
+
+impl FileInformation {
+ /// Create new file.
+ pub fn new(name: &str, id: &mut i32) -> Self {
+ *id += 1;
+ Self {
+ file_name: name.to_string(),
+ file_spdx_identifier: format!("SPDXRef-{}", id),
+ ..Self::default()
+ }
+ }
+
+ /// Check if hash equals.
+ pub fn equal_by_hash(&self, algorithm: Algorithm, value: &str) -> bool {
+ let checksum = self
+ .file_checksum
+ .iter()
+ .find(|&checksum| checksum.algorithm == algorithm);
+
+ checksum.map_or(false, |checksum| {
+ checksum.value.to_ascii_lowercase() == value.to_ascii_lowercase()
+ })
+ }
+
+ /// Get checksum
+ pub fn checksum(&self, algorithm: Algorithm) -> Option<&str> {
+ let checksum = self
+ .file_checksum
+ .iter()
+ .find(|&checksum| checksum.algorithm == algorithm);
+
+ checksum.map(|checksum| checksum.value.as_str())
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/4-file-information/#43-file-type>
+#[derive(Debug, Serialize, Deserialize, PartialEq, PartialOrd, Clone, Copy)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum FileType {
+ Source,
+ Binary,
+ Archive,
+ Application,
+ Audio,
+ Image,
+ Text,
+ Video,
+ Documentation,
+ SPDX,
+ Other,
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use super::*;
+ use crate::models::{Checksum, FileType, SPDX};
+
+ #[test]
+ fn checksum_equality() {
+ let mut id = 1;
+ let mut file_sha256 = FileInformation::new("sha256", &mut id);
+ file_sha256
+ .file_checksum
+ .push(Checksum::new(Algorithm::SHA256, "test"));
+
+ assert!(file_sha256.equal_by_hash(Algorithm::SHA256, "test"));
+ assert!(!file_sha256.equal_by_hash(Algorithm::SHA256, "no_test"));
+
+ let mut file_md5 = FileInformation::new("md5", &mut id);
+ file_md5
+ .file_checksum
+ .push(Checksum::new(Algorithm::MD5, "test"));
+ assert!(file_md5.equal_by_hash(Algorithm::MD5, "test"));
+ assert!(!file_md5.equal_by_hash(Algorithm::MD5, "no_test"));
+ assert!(!file_md5.equal_by_hash(Algorithm::SHA1, "test"));
+ }
+
+ #[test]
+ fn get_checksum() {
+ let mut id = 1;
+ let mut file_sha256 = FileInformation::new("sha256", &mut id);
+ file_sha256
+ .file_checksum
+ .push(Checksum::new(Algorithm::SHA256, "test"));
+
+ assert_eq!(file_sha256.checksum(Algorithm::SHA256), Some("test"));
+ assert_eq!(file_sha256.checksum(Algorithm::MD2), None);
+
+ let mut file_md5 = FileInformation::new("md5", &mut id);
+ file_md5
+ .file_checksum
+ .push(Checksum::new(Algorithm::MD5, "test"));
+
+ assert_eq!(file_md5.checksum(Algorithm::MD5), Some("test"));
+ }
+
+ #[test]
+ fn file_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].file_name,
+ "./src/org/spdx/parser/DOAPProject.java"
+ );
+ }
+ #[test]
+ fn file_spdx_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].file_spdx_identifier,
+ "SPDXRef-DoapSource"
+ );
+ }
+ #[test]
+ fn file_type() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(spdx.file_information[0].file_type, vec![FileType::Source]);
+ }
+ #[test]
+ fn file_checksum() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].file_checksum,
+ vec![Checksum {
+ algorithm: Algorithm::SHA1,
+ value: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12".to_string()
+ }]
+ );
+ }
+ #[test]
+ fn concluded_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].concluded_license,
+ SpdxExpression::parse("Apache-2.0").unwrap()
+ );
+ }
+ #[test]
+ fn license_information_in_file() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].license_information_in_file,
+ vec![SimpleExpression::parse("Apache-2.0").unwrap()]
+ );
+ }
+ #[test]
+ fn comments_on_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[2].comments_on_license,
+ Some("This license is used by Jena".to_string())
+ );
+ }
+ #[test]
+ fn copyright_text() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[0].copyright_text,
+ "Copyright 2010, 2011 Source Auditor Inc.".to_string()
+ );
+ }
+ #[test]
+ fn file_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[1].file_comment,
+ Some("This file is used by Jena".to_string())
+ );
+ }
+ #[test]
+ fn file_notice() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[1].file_notice,
+ Some("Apache Commons Lang\nCopyright 2001-2011 The Apache Software Foundation\n\nThis product includes software developed by\nThe Apache Software Foundation (http://www.apache.org/).\n\nThis product includes software from the Spring Framework,\nunder the Apache License 2.0 (see: StringUtils.containsWhitespace())".to_string())
+ );
+ }
+ #[test]
+ fn file_contributor() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.file_information[1].file_contributor,
+ vec!["Apache Software Foundation".to_string()]
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/mod.rs b/vendor/spdx-rs/src/models/mod.rs
new file mode 100644
index 000000000..2eed75db2
--- /dev/null
+++ b/vendor/spdx-rs/src/models/mod.rs
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: 2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+mod annotation;
+mod checksum;
+mod document_creation_information;
+mod file_information;
+mod other_licensing_information_detected;
+mod package_information;
+mod relationship;
+mod snippet;
+mod spdx_document;
+
+pub use annotation::*;
+pub use checksum::*;
+pub use document_creation_information::*;
+pub use file_information::*;
+pub use other_licensing_information_detected::*;
+pub use package_information::*;
+pub use relationship::*;
+pub use snippet::*;
+pub use spdx_document::*;
+pub use spdx_expression::*;
diff --git a/vendor/spdx-rs/src/models/other_licensing_information_detected.rs b/vendor/spdx-rs/src/models/other_licensing_information_detected.rs
new file mode 100644
index 000000000..30bd1d318
--- /dev/null
+++ b/vendor/spdx-rs/src/models/other_licensing_information_detected.rs
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+
+/// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/>
+#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct OtherLicensingInformationDetected {
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/#61-license-identifier>
+ #[serde(rename = "licenseId")]
+ pub license_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/#62-extracted-text>
+ pub extracted_text: String,
+
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/#63-license-name>
+ #[serde(rename = "name")]
+ #[serde(default = "default_noassertion")]
+ pub license_name: String,
+
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/#64-license-cross-reference>
+ #[serde(rename = "seeAlsos", skip_serializing_if = "Vec::is_empty", default)]
+ pub license_cross_reference: Vec<String>,
+
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/#65-license-comment>
+ #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
+ pub license_comment: Option<String>,
+}
+
+fn default_noassertion() -> String {
+ "NOASSERTION".into()
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use crate::models::SPDX;
+
+ #[test]
+ fn license_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.other_licensing_information_detected[0].license_identifier,
+ "LicenseRef-Beerware-4.2".to_string()
+ );
+ }
+ #[test]
+ fn extracted_text() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(spdx.other_licensing_information_detected[0].extracted_text, "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote this file. As long as you retain this notice you\ncan do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp </\nLicenseName: Beer-Ware License (Version 42)\nLicenseCrossReference: http://people.freebsd.org/~phk/\nLicenseComment: \nThe beerware license has a couple of other standard variants.");
+ }
+ #[test]
+ fn license_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.other_licensing_information_detected[2].license_name,
+ "CyberNeko License".to_string()
+ );
+ }
+ #[test]
+ fn license_cross_reference() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.other_licensing_information_detected[2].license_cross_reference,
+ vec![
+ "http://people.apache.org/~andyc/neko/LICENSE".to_string(),
+ "http://justasample.url.com".to_string()
+ ]
+ );
+ }
+ #[test]
+ fn license_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.other_licensing_information_detected[2].license_comment,
+ Some("This is tye CyperNeko License".to_string())
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/package_information.rs b/vendor/spdx-rs/src/models/package_information.rs
new file mode 100644
index 000000000..1cfd938f8
--- /dev/null
+++ b/vendor/spdx-rs/src/models/package_information.rs
@@ -0,0 +1,555 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+use spdx_expression::SpdxExpression;
+
+use super::Annotation;
+
+use super::{Checksum, FileInformation};
+
+/// ## Package Information
+///
+/// SPDX's [Package Information](https://spdx.github.io/spdx-spec/3-package-information/).
+#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub struct PackageInformation {
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#31-package-name>
+ #[serde(rename = "name")]
+ pub package_name: String,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#32-package-spdx-identifier>
+ #[serde(rename = "SPDXID")]
+ pub package_spdx_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#33-package-version>
+ #[serde(
+ rename = "versionInfo",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub package_version: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#34-package-file-name>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ pub package_file_name: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#35-package-supplier>
+ #[serde(rename = "supplier", skip_serializing_if = "Option::is_none", default)]
+ pub package_supplier: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#36-package-originator>
+ #[serde(
+ rename = "originator",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub package_originator: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#37-package-download-location>
+ #[serde(rename = "downloadLocation")]
+ pub package_download_location: String,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#38-files-analyzed>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ pub files_analyzed: Option<bool>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#39-package-verification-code>
+ #[serde(skip_serializing_if = "Option::is_none", default)]
+ pub package_verification_code: Option<PackageVerificationCode>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#310-package-checksum>
+ #[serde(rename = "checksums", skip_serializing_if = "Vec::is_empty", default)]
+ pub package_checksum: Vec<Checksum>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#311-package-home-page>
+ #[serde(rename = "homepage", skip_serializing_if = "Option::is_none", default)]
+ pub package_home_page: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#312-source-information>
+ #[serde(
+ rename = "sourceInfo",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub source_information: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#313-concluded-license>
+ #[serde(rename = "licenseConcluded")]
+ pub concluded_license: SpdxExpression,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#314-all-licenses-information-from-files>
+ #[serde(
+ rename = "licenseInfoFromFiles",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub all_licenses_information_from_files: Vec<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#315-declared-license>
+ #[serde(rename = "licenseDeclared")]
+ pub declared_license: SpdxExpression,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#316-comments-on-license>
+ #[serde(
+ rename = "licenseComments",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub comments_on_license: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#317-copyright-text>
+ pub copyright_text: String,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#318-package-summary-description>
+ #[serde(rename = "summary", skip_serializing_if = "Option::is_none", default)]
+ pub package_summary_description: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#319-package-detailed-description>
+ #[serde(
+ rename = "description",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub package_detailed_description: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#320-package-comment>
+ #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
+ pub package_comment: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#321-external-reference>
+ #[serde(
+ rename = "externalRefs",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub external_reference: Vec<ExternalPackageReference>,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/#323-package-attribution-text>
+ #[serde(
+ rename = "attributionTexts",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub package_attribution_text: Vec<String>,
+
+ /// List of "files in the package". Not sure which relationship type this maps to.
+ /// Info: <https://github.com/spdx/spdx-spec/issues/487>
+ // Valid SPDX?
+ #[serde(rename = "hasFiles", skip_serializing_if = "Vec::is_empty", default)]
+ pub files: Vec<String>,
+
+ #[serde(skip_serializing_if = "Vec::is_empty", default)]
+ pub annotations: Vec<Annotation>,
+}
+
+impl Default for PackageInformation {
+ fn default() -> Self {
+ Self {
+ package_name: "NOASSERTION".to_string(),
+ package_spdx_identifier: "NOASSERTION".to_string(),
+ package_version: None,
+ package_file_name: None,
+ package_supplier: None,
+ package_originator: None,
+ package_download_location: "NOASSERTION".to_string(),
+ files_analyzed: None,
+ package_verification_code: None,
+ package_checksum: Vec::new(),
+ package_home_page: None,
+ source_information: None,
+ concluded_license: SpdxExpression::parse("NONE").expect("will always succeed"),
+ all_licenses_information_from_files: Vec::new(),
+ declared_license: SpdxExpression::parse("NONE").expect("will always succeed"),
+ comments_on_license: None,
+ copyright_text: "NOASSERTION".to_string(),
+ package_summary_description: None,
+ package_detailed_description: None,
+ package_comment: None,
+ external_reference: Vec::new(),
+ package_attribution_text: Vec::new(),
+ files: Vec::new(),
+ annotations: Vec::new(),
+ }
+ }
+}
+
+impl PackageInformation {
+ /// Create new package.
+ pub fn new(name: &str, id: &mut i32) -> Self {
+ *id += 1;
+ Self {
+ package_name: name.to_string(),
+ package_spdx_identifier: format!("SPDXRef-{}", id),
+ ..Self::default()
+ }
+ }
+
+ /// Find all files of the package.
+ pub fn find_files_for_package<'a>(
+ &'a self,
+ files: &'a [FileInformation],
+ ) -> Vec<&'a FileInformation> {
+ self.files
+ .iter()
+ .filter_map(|file| {
+ files
+ .iter()
+ .find(|file_information| &file_information.file_spdx_identifier == file)
+ })
+ .collect()
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/3-package-information/#39-package-verification-code>
+#[derive(Debug, Serialize, Deserialize, PartialEq, PartialOrd, Clone)]
+pub struct PackageVerificationCode {
+ /// Value of the verification code.
+ #[serde(rename = "packageVerificationCodeValue")]
+ pub value: String,
+
+ /// Files that were excluded when calculating the verification code.
+ #[serde(
+ rename = "packageVerificationCodeExcludedFiles",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub excludes: Vec<String>,
+}
+
+impl PackageVerificationCode {
+ pub fn new(value: String, excludes: Vec<String>) -> Self {
+ Self { value, excludes }
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/3-package-information/#321-external-reference>
+#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct ExternalPackageReference {
+ pub reference_category: ExternalPackageReferenceCategory,
+ pub reference_type: String,
+ pub reference_locator: String,
+ #[serde(rename = "comment")]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
+ pub reference_comment: Option<String>,
+}
+
+impl ExternalPackageReference {
+ pub const fn new(
+ reference_category: ExternalPackageReferenceCategory,
+ reference_type: String,
+ reference_locator: String,
+ reference_comment: Option<String>,
+ ) -> Self {
+ Self {
+ reference_category,
+ reference_type,
+ reference_locator,
+ reference_comment,
+ }
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/3-package-information/#321-external-reference>
+#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone)]
+#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
+pub enum ExternalPackageReferenceCategory {
+ Security,
+ PackageManager,
+ PersistentID,
+ Other,
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use crate::models::{Algorithm, SPDX};
+
+ use super::*;
+
+ #[test]
+ fn all_packages_are_deserialized() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(spdx.package_information.len(), 4);
+ }
+ #[test]
+ fn package_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_name,
+ "glibc".to_string()
+ );
+ }
+ #[test]
+ fn package_spdx_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_spdx_identifier,
+ "SPDXRef-Package".to_string()
+ );
+ }
+ #[test]
+ fn package_version() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_version,
+ Some("2.11.1".to_string())
+ );
+ }
+ #[test]
+ fn package_file_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_file_name,
+ Some("glibc-2.11.1.tar.gz".to_string())
+ );
+ }
+ #[test]
+ fn package_supplier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_supplier,
+ Some("Person: Jane Doe (jane.doe@example.com)".to_string())
+ );
+ }
+ #[test]
+ fn package_originator() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_originator,
+ Some("Organization: ExampleCodeInspect (contact@example.com)".to_string())
+ );
+ }
+ #[test]
+ fn package_download_location() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_download_location,
+ "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz".to_string()
+ );
+ }
+ #[test]
+ fn files_analyzed() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(spdx.package_information[0].files_analyzed, Some(true));
+ }
+ #[test]
+ fn package_verification_code() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_verification_code,
+ Some(PackageVerificationCode {
+ value: "d6a770ba38583ed4bb4525bd96e50461655d2758".to_string(),
+ excludes: vec!["./package.spdx".to_string()]
+ })
+ );
+ }
+ #[test]
+ fn package_chekcsum() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(spdx.package_information[0]
+ .package_checksum
+ .contains(&Checksum::new(
+ Algorithm::SHA1,
+ "85ed0817af83a24ad8da68c2b5094de69833983c"
+ )));
+ assert!(spdx.package_information[0]
+ .package_checksum
+ .contains(&Checksum::new(
+ Algorithm::MD5,
+ "624c1abb3664f4b35547e7c73864ad24"
+ )));
+ assert!(spdx.package_information[0]
+ .package_checksum
+ .contains(&Checksum::new(
+ Algorithm::SHA256,
+ "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"
+ )));
+ }
+ #[test]
+ fn package_home_page() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_home_page,
+ Some("http://ftp.gnu.org/gnu/glibc".to_string())
+ );
+ }
+ #[test]
+ fn source_information() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].source_information,
+ Some("uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.".to_string())
+ );
+ }
+ #[test]
+ fn concluded_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].concluded_license,
+ SpdxExpression::parse("(LGPL-2.0-only OR LicenseRef-3)").unwrap()
+ );
+ }
+ #[test]
+ fn all_licenses_information_from_files() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(spdx.package_information[0]
+ .all_licenses_information_from_files
+ .contains(&"GPL-2.0-only".to_string()));
+ assert!(spdx.package_information[0]
+ .all_licenses_information_from_files
+ .contains(&"LicenseRef-2".to_string()));
+ assert!(spdx.package_information[0]
+ .all_licenses_information_from_files
+ .contains(&"LicenseRef-1".to_string()));
+ }
+ #[test]
+ fn declared_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].declared_license,
+ SpdxExpression::parse("(LGPL-2.0-only AND LicenseRef-3)").unwrap()
+ );
+ }
+ #[test]
+ fn comments_on_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].comments_on_license,
+ Some("The license for this project changed with the release of version x.y. The version of the project included here post-dates the license change.".to_string())
+ );
+ }
+ #[test]
+ fn copyright_text() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].copyright_text,
+ "Copyright 2008-2010 John Smith".to_string()
+ );
+ }
+ #[test]
+ fn package_summary_description() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_summary_description,
+ Some("GNU C library.".to_string())
+ );
+ }
+ #[test]
+ fn package_detailed_description() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[0].package_detailed_description,
+ Some("The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.".to_string())
+ );
+ }
+ #[test]
+ fn package_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.package_information[1].package_comment,
+ Some("This package was converted from a DOAP Project by the same name".to_string())
+ );
+ }
+ #[test]
+ fn external_reference() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(
+ spdx.package_information[0].external_reference.contains(&ExternalPackageReference {
+ reference_comment: Some("This is the external ref for Acme".to_string()),
+ reference_category: ExternalPackageReferenceCategory::Other,
+ reference_locator: "acmecorp/acmenator/4.1.3-alpha".to_string(),
+ reference_type: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge".to_string()
+ })
+ );
+ assert!(spdx.package_information[0].external_reference.contains(
+ &ExternalPackageReference {
+ reference_comment: None,
+ reference_category: ExternalPackageReferenceCategory::Security,
+ reference_locator:
+ "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*".to_string(),
+ reference_type: "http://spdx.org/rdf/references/cpe23Type".to_string()
+ }
+ ));
+ }
+ #[test]
+ fn package_attribution_text() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert!(
+ spdx.package_information[0].package_attribution_text.contains(&"The GNU C Library is free software. See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed. License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.".to_string())
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/relationship.rs b/vendor/spdx-rs/src/models/relationship.rs
new file mode 100644
index 000000000..6430a796f
--- /dev/null
+++ b/vendor/spdx-rs/src/models/relationship.rs
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+use strum_macros::AsRefStr;
+
+/// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#71-relationship>
+#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Eq, Hash)]
+#[serde(rename_all = "camelCase")]
+pub struct Relationship {
+ /// SPDX ID of the element.
+ pub spdx_element_id: String,
+
+ /// SPDX ID of the related element.
+ pub related_spdx_element: String,
+
+ /// Type of the relationship.
+ pub relationship_type: RelationshipType,
+
+ /// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#72-relationship-comment>
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
+ pub comment: Option<String>,
+}
+
+impl Relationship {
+ /// Create a new relationship.
+ pub fn new(
+ spdx_element_id: &str,
+ related_spdx_element: &str,
+ relationship_type: RelationshipType,
+ comment: Option<String>,
+ ) -> Self {
+ Self {
+ spdx_element_id: spdx_element_id.to_string(),
+ related_spdx_element: related_spdx_element.to_string(),
+ relationship_type,
+ comment,
+ }
+ }
+}
+
+/// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/#71-relationship>
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, AsRefStr, Eq, Hash)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum RelationshipType {
+ Describes,
+ DescribedBy,
+ Contains,
+ ContainedBy,
+ DependsOn,
+ DependencyOf,
+ DependencyManifestOf,
+ BuildDependencyOf,
+ DevDependencyOf,
+ OptionalDependencyOf,
+ ProvidedDependencyOf,
+ TestDependencyOf,
+ RuntimeDependencyOf,
+ ExampleOf,
+ Generates,
+ GeneratedFrom,
+ AncestorOf,
+ DescendantOf,
+ VariantOf,
+ DistributionArtifact,
+ PatchFor,
+ PatchApplied,
+ CopyOf,
+ FileAdded,
+ FileDeleted,
+ FileModified,
+ ExpandedFromArchive,
+ DynamicLink,
+ StaticLink,
+ DataFileOf,
+ TestCaseOf,
+ BuildToolOf,
+ DevToolOf,
+ TestOf,
+ TestToolOf,
+ DocumentationOf,
+ OptionalComponentOf,
+ MetafileOf,
+ PackageOf,
+ Amends,
+ PrerequisiteFor,
+ HasPrerequisite,
+ Other,
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use crate::models::SPDX;
+
+ use super::*;
+
+ #[test]
+ fn spdx_element_id() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.relationships[0].spdx_element_id,
+ "SPDXRef-DOCUMENT".to_string()
+ );
+ }
+ #[test]
+ fn related_spdx_element() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.relationships[0].related_spdx_element,
+ "SPDXRef-Package".to_string()
+ );
+ }
+ #[test]
+ fn relationship_type() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.relationships[0].relationship_type,
+ RelationshipType::Contains
+ );
+ assert_eq!(
+ spdx.relationships[2].relationship_type,
+ RelationshipType::CopyOf
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/snippet.rs b/vendor/spdx-rs/src/models/snippet.rs
new file mode 100644
index 000000000..e4a644ac5
--- /dev/null
+++ b/vendor/spdx-rs/src/models/snippet.rs
@@ -0,0 +1,237 @@
+// SPDX-FileCopyrightText: 2020-2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use serde::{Deserialize, Serialize};
+use spdx_expression::SpdxExpression;
+
+/// <https://spdx.github.io/spdx-spec/5-snippet-information/>
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
+pub struct Snippet {
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#51-snippet-spdx-identifier>
+ #[serde(rename = "SPDXID")]
+ pub snippet_spdx_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#52-snippet-from-file-spdx-identifier>
+ #[serde(rename = "snippetFromFile")]
+ pub snippet_from_file_spdx_identifier: String,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#53-snippet-byte-range>
+ pub ranges: Vec<Range>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#55-snippet-concluded-license>
+ #[serde(rename = "licenseConcluded")]
+ pub snippet_concluded_license: SpdxExpression,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#56-license-information-in-snippet>
+ #[serde(
+ rename = "licenseInfoInSnippets",
+ skip_serializing_if = "Vec::is_empty",
+ default
+ )]
+ pub license_information_in_snippet: Vec<String>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#57-snippet-comments-on-license>
+ #[serde(
+ rename = "licenseComments",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub snippet_comments_on_license: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#58-snippet-copyright-text>
+ #[serde(rename = "copyrightText")]
+ pub snippet_copyright_text: String,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#59-snippet-comment>
+ #[serde(rename = "comment", skip_serializing_if = "Option::is_none", default)]
+ pub snippet_comment: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#510-snippet-name>
+ #[serde(rename = "name", skip_serializing_if = "Option::is_none", default)]
+ pub snippet_name: Option<String>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/#511-snippet-attribution-text>
+ #[serde(
+ rename = "attributionText",
+ skip_serializing_if = "Option::is_none",
+ default
+ )]
+ pub snippet_attribution_text: Option<String>,
+}
+
+/// <https://spdx.github.io/spdx-spec/5-snippet-information/#53-snippet-byte-range>
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct Range {
+ pub start_pointer: Pointer,
+ pub end_pointer: Pointer,
+}
+
+impl Range {
+ pub fn new(start_pointer: Pointer, end_pointer: Pointer) -> Self {
+ Self {
+ start_pointer,
+ end_pointer,
+ }
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
+#[serde(untagged)]
+pub enum Pointer {
+ Byte {
+ reference: Option<String>,
+ offset: i32,
+ },
+ Line {
+ reference: Option<String>,
+ #[serde(rename = "lineNumber")]
+ line_number: i32,
+ },
+}
+
+impl Pointer {
+ /// Create a new [`Pointer::Byte`].
+ pub fn new_byte(reference: Option<String>, offset: i32) -> Self {
+ Self::Byte { reference, offset }
+ }
+
+ /// Create a new [`Pointer::Line`].
+ pub fn new_line(reference: Option<String>, line_number: i32) -> Self {
+ Self::Line {
+ reference,
+ line_number,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::read_to_string;
+
+ use crate::models::SPDX;
+
+ use super::*;
+
+ #[test]
+ fn snippet_spdx_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_spdx_identifier,
+ "SPDXRef-Snippet".to_string()
+ );
+ }
+ #[test]
+ fn snippet_from_file_spdx_identifier() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_from_file_spdx_identifier,
+ "SPDXRef-DoapSource".to_string()
+ );
+ }
+ #[test]
+ fn ranges() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].ranges,
+ vec![
+ Range {
+ end_pointer: Pointer::Line {
+ line_number: 23,
+ reference: Some("SPDXRef-DoapSource".to_string()),
+ },
+ start_pointer: Pointer::Line {
+ line_number: 5,
+ reference: Some("SPDXRef-DoapSource".to_string()),
+ },
+ },
+ Range {
+ end_pointer: Pointer::Byte {
+ offset: 420,
+ reference: Some("SPDXRef-DoapSource".to_string()),
+ },
+ start_pointer: Pointer::Byte {
+ offset: 310,
+ reference: Some("SPDXRef-DoapSource".to_string()),
+ },
+ },
+ ]
+ );
+ }
+ #[test]
+ fn snippet_concluded_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_concluded_license,
+ SpdxExpression::parse("GPL-2.0-only").unwrap()
+ );
+ }
+ #[test]
+ fn license_information_in_snippet() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].license_information_in_snippet,
+ vec!["GPL-2.0-only".to_string()]
+ );
+ }
+ #[test]
+ fn snippet_comments_on_license() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_comments_on_license,
+ Some("The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.".to_string())
+ );
+ }
+ #[test]
+ fn snippet_copyright_text() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_copyright_text,
+ "Copyright 2008-2010 John Smith".to_string()
+ );
+ }
+ #[test]
+ fn snippet_comment() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_comment,
+ Some("This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.".to_string())
+ );
+ }
+ #[test]
+ fn snippet_name() {
+ let spdx: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ assert_eq!(
+ spdx.snippet_information[0].snippet_name,
+ Some("from linux kernel".to_string())
+ );
+ }
+}
diff --git a/vendor/spdx-rs/src/models/spdx_document.rs b/vendor/spdx-rs/src/models/spdx_document.rs
new file mode 100644
index 000000000..d7db1009a
--- /dev/null
+++ b/vendor/spdx-rs/src/models/spdx_document.rs
@@ -0,0 +1,330 @@
+// SPDX-FileCopyrightText: 2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use std::collections::HashSet;
+
+use log::info;
+use serde::{Deserialize, Serialize};
+use uuid::Uuid;
+
+use super::{
+ Algorithm, Annotation, DocumentCreationInformation, FileInformation,
+ OtherLicensingInformationDetected, PackageInformation, Relationship, Snippet,
+};
+
+/// A representation of an [SPDX Document]
+///
+/// This is the main struct of this crate. The struct implements [`Serialize`] and [`Deserialize`]
+/// to allow it to be serialized into and deserialized from any data format supported by [Serde].
+///
+/// # SPDX specification version
+///
+/// The crate has been developed around SPDX version 2.2.1. Fields deprecated in 2.2.1, like
+/// [review information] are not supported. The plan is to support newer versions as they are
+/// released.
+///
+/// # Data formats
+///
+/// The crate has been developed for usage with JSON SPDX documents. The naming of the fields should
+/// conform to the spec for at least JSON. Other formats, like YAML may work, but no guarantees are
+/// made.
+///
+/// The crate also allows for deserializing the struct from SPDX documents in [tag-value format]
+/// with [`crate::parsers::spdx_from_tag_value`].
+///
+/// [SPDX Document]: https://spdx.github.io/spdx-spec/composition-of-an-SPDX-document/
+/// [Serde]: https://serde.rs
+/// [review information]: https://spdx.github.io/spdx-spec/review-information-deprecated/
+/// [tag-value format]: https://spdx.github.io/spdx-spec/conformance/
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub struct SPDX {
+ /// <https://spdx.github.io/spdx-spec/2-document-creation-information/>
+ #[serde(flatten)]
+ pub document_creation_information: DocumentCreationInformation,
+
+ /// <https://spdx.github.io/spdx-spec/3-package-information/>
+ #[serde(rename = "packages")]
+ #[serde(default)]
+ pub package_information: Vec<PackageInformation>,
+
+ /// <https://spdx.github.io/spdx-spec/6-other-licensing-information-detected/>
+ #[serde(rename = "hasExtractedLicensingInfos")]
+ #[serde(default)]
+ pub other_licensing_information_detected: Vec<OtherLicensingInformationDetected>,
+
+ /// <https://spdx.github.io/spdx-spec/4-file-information/>
+ #[serde(rename = "files")]
+ #[serde(default)]
+ pub file_information: Vec<FileInformation>,
+
+ /// <https://spdx.github.io/spdx-spec/5-snippet-information/>
+ #[serde(rename = "snippets")]
+ #[serde(default)]
+ pub snippet_information: Vec<Snippet>,
+
+ /// <https://spdx.github.io/spdx-spec/7-relationships-between-SPDX-elements/>
+ #[serde(default)]
+ pub relationships: Vec<Relationship>,
+
+ /// <https://spdx.github.io/spdx-spec/8-annotations/>
+ #[serde(default)]
+ pub annotations: Vec<Annotation>,
+
+ /// Counter for creating SPDXRefs. Is not part of the spec, so don't serialize.
+ #[serde(skip)]
+ pub spdx_ref_counter: i32,
+}
+
+impl SPDX {
+ /// Create new SPDX struct.
+ pub fn new(name: &str) -> Self {
+ info!("Creating SPDX.");
+
+ Self {
+ document_creation_information: DocumentCreationInformation {
+ document_name: name.to_string(),
+ spdx_document_namespace: format!(
+ "http://spdx.org/spdxdocs/{}-{}",
+ name,
+ Uuid::new_v4()
+ ),
+ ..DocumentCreationInformation::default()
+ },
+ package_information: Vec::new(),
+ other_licensing_information_detected: Vec::new(),
+ file_information: Vec::new(),
+ relationships: Vec::new(),
+ spdx_ref_counter: 0,
+ annotations: Vec::new(),
+ snippet_information: Vec::new(),
+ }
+ }
+
+ /// Get unique hashes for all files the SPDX.
+ pub fn get_unique_hashes(&self, algorithm: Algorithm) -> HashSet<String> {
+ info!("Getting unique hashes for files in SPDX.");
+
+ let mut unique_hashes: HashSet<String> = HashSet::new();
+
+ for file_information in &self.file_information {
+ if let Some(checksum) = file_information.checksum(algorithm) {
+ unique_hashes.insert(checksum.to_string());
+ }
+ }
+
+ unique_hashes
+ }
+
+ /// Find related files of the package with the provided id.
+ pub fn get_files_for_package(
+ &self,
+ package_spdx_id: &str,
+ ) -> Vec<(&FileInformation, &Relationship)> {
+ info!("Finding related files for package {}.", &package_spdx_id);
+
+ let relationships = self
+ .relationships
+ .iter()
+ .filter(|relationship| relationship.spdx_element_id == package_spdx_id);
+
+ let mut result: Vec<(&FileInformation, &Relationship)> = Vec::new();
+
+ for relationship in relationships {
+ let file = self
+ .file_information
+ .iter()
+ .find(|file| file.file_spdx_identifier == relationship.related_spdx_element);
+ if let Some(file) = file {
+ result.push((file, relationship));
+ };
+ }
+
+ result
+ }
+
+ /// Get all license identifiers from the SPDX.
+ ///
+ /// # Errors
+ ///
+ /// Returns [`SpdxError`] if parsing of the expressions fails.
+ pub fn get_license_ids(&self) -> HashSet<String> {
+ info!("Getting all license identifiers from SPDX.");
+
+ let mut license_ids = HashSet::new();
+
+ for file in &self.file_information {
+ for license in &file.concluded_license.identifiers() {
+ if license != "NOASSERTION" && license != "NONE" {
+ license_ids.insert(license.clone());
+ }
+ }
+ }
+
+ license_ids
+ }
+
+ /// Get all relationships where the given SPDX ID is the SPDX element id.
+ pub fn relationships_for_spdx_id(&self, spdx_id: &str) -> Vec<&Relationship> {
+ self.relationships
+ .iter()
+ .filter(|relationship| relationship.spdx_element_id == spdx_id)
+ .collect()
+ }
+
+ /// Get all relationships where the given SPDX ID is the related SPDX element id.
+ pub fn relationships_for_related_spdx_id(&self, spdx_id: &str) -> Vec<&Relationship> {
+ self.relationships
+ .iter()
+ .filter(|relationship| relationship.related_spdx_element == spdx_id)
+ .collect()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::{fs::read_to_string, iter::FromIterator};
+
+ use spdx_expression::SpdxExpression;
+
+ use crate::models::RelationshipType;
+
+ use super::*;
+
+ #[test]
+ fn deserialize_simple_spdx() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ assert_eq!(
+ spdx_file.document_creation_information.document_name,
+ "SPDX-Tools-v2.0".to_string()
+ );
+ }
+
+ #[test]
+ fn find_related_files_for_package() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ let package_1_files = spdx_file.get_files_for_package("SPDXRef-Package");
+
+ assert_eq!(package_1_files.len(), 1);
+
+ let file = package_1_files
+ .iter()
+ .find(|package_and_relationship| {
+ package_and_relationship.0.file_name == *"./lib-source/jena-2.6.3-sources.jar"
+ })
+ .expect("Should always be found");
+
+ assert_eq!(file.0.file_spdx_identifier, "SPDXRef-JenaLib");
+ assert_eq!(file.1.relationship_type, RelationshipType::Contains);
+
+ assert_eq!(
+ file.0.concluded_license,
+ SpdxExpression::parse("LicenseRef-1").unwrap()
+ );
+ }
+
+ #[test]
+ fn get_all_licenses_from_spdx() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ let actual = spdx_file.get_license_ids();
+
+ let expected = HashSet::from_iter([
+ "Apache-2.0".into(),
+ "LicenseRef-1".into(),
+ "LGPL-2.0-only".into(),
+ "LicenseRef-2".into(),
+ ]);
+
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn get_relationships_for_spdx_id() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ let relationships = spdx_file.relationships_for_spdx_id("SPDXRef-Package");
+ let relationship_1 = Relationship {
+ spdx_element_id: "SPDXRef-Package".into(),
+ related_spdx_element: "SPDXRef-Saxon".into(),
+ relationship_type: RelationshipType::DynamicLink,
+ comment: None,
+ };
+ let relationship_2 = Relationship {
+ spdx_element_id: "SPDXRef-Package".into(),
+ related_spdx_element: "SPDXRef-JenaLib".into(),
+ relationship_type: RelationshipType::Contains,
+ comment: None,
+ };
+ let expected_relationships = vec![&relationship_1, &relationship_2];
+
+ assert_eq!(relationships, expected_relationships);
+ }
+
+ #[test]
+ fn get_relationships_for_related_spdx_id() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+
+ let relationships = spdx_file.relationships_for_related_spdx_id("SPDXRef-Package");
+ let relationship_1 = Relationship {
+ spdx_element_id: "SPDXRef-DOCUMENT".into(),
+ related_spdx_element: "SPDXRef-Package".into(),
+ relationship_type: RelationshipType::Contains,
+ comment: None,
+ };
+ let relationship_2 = Relationship {
+ spdx_element_id: "SPDXRef-DOCUMENT".into(),
+ related_spdx_element: "SPDXRef-Package".into(),
+ relationship_type: RelationshipType::Describes,
+ comment: None,
+ };
+ let relationship_3 = Relationship {
+ spdx_element_id: "SPDXRef-JenaLib".into(),
+ related_spdx_element: "SPDXRef-Package".into(),
+ relationship_type: RelationshipType::Contains,
+ comment: None,
+ };
+ let expected_relationships = vec![&relationship_1, &relationship_2, &relationship_3];
+
+ assert_eq!(relationships, expected_relationships);
+ }
+
+ #[test]
+ fn get_unique_hashes_for_files() {
+ let spdx_file: SPDX = serde_json::from_str(
+ &read_to_string("tests/data/SPDXJSONExample-v2.2.spdx.json").unwrap(),
+ )
+ .unwrap();
+ let hashes = spdx_file.get_unique_hashes(Algorithm::SHA1);
+
+ let expected = [
+ "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12".to_string(),
+ "c2b4e1c67a2d28fced849ee1bb76e7391b93f125".to_string(),
+ "3ab4e1c67a2d28fced849ee1bb76e7391b93f125".to_string(),
+ "d6a770ba38583ed4bb4525bd96e50461655d2758".to_string(),
+ ]
+ .iter()
+ .cloned()
+ .collect::<HashSet<_>>();
+
+ assert_eq!(hashes, expected);
+ }
+}