summaryrefslogtreecommitdiffstats
path: root/vendor/spdx-rs/src/parsers/tag_value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/spdx-rs/src/parsers/tag_value.rs')
-rw-r--r--vendor/spdx-rs/src/parsers/tag_value.rs669
1 files changed, 669 insertions, 0 deletions
diff --git a/vendor/spdx-rs/src/parsers/tag_value.rs b/vendor/spdx-rs/src/parsers/tag_value.rs
new file mode 100644
index 000000000..0c8fdb4e3
--- /dev/null
+++ b/vendor/spdx-rs/src/parsers/tag_value.rs
@@ -0,0 +1,669 @@
+// SPDX-FileCopyrightText: 2021 HH Partners
+//
+// SPDX-License-Identifier: MIT
+
+use std::{num::ParseIntError, str::FromStr};
+
+use nom::{
+ branch::alt,
+ bytes::complete::{tag, take_until, take_while},
+ character::complete::{alphanumeric0, char, digit1, multispace0, not_line_ending},
+ combinator::{map, map_res, opt},
+ error::{ParseError, VerboseError},
+ multi::many0,
+ sequence::{delimited, preceded, separated_pair, tuple},
+ AsChar, IResult,
+};
+
+use crate::models::{
+ Algorithm, AnnotationType, Checksum, ExternalDocumentReference, ExternalPackageReference,
+ ExternalPackageReferenceCategory, FileType, PackageVerificationCode, Relationship,
+ RelationshipType,
+};
+
+#[derive(Debug, Clone, PartialEq)]
+#[allow(clippy::upper_case_acronyms)]
+pub(super) enum Atom {
+ // Document Creation Information
+ SpdxVersion(String),
+ DataLicense(String),
+ SPDXID(String),
+ DocumentName(String),
+ DocumentNamespace(String),
+ ExternalDocumentRef(ExternalDocumentReference),
+ LicenseListVersion(String),
+ Creator(String),
+ Created(String),
+ CreatorComment(String),
+ DocumentComment(String),
+
+ // Package Information
+ PackageName(String),
+ PackageVersion(String),
+ PackageFileName(String),
+ PackageSupplier(String),
+ PackageOriginator(String),
+ PackageDownloadLocation(String),
+ FilesAnalyzed(String),
+ PackageVerificationCode(PackageVerificationCode),
+ PackageChecksum(Checksum),
+ PackageHomePage(String),
+ PackageSourceInfo(String),
+ PackageLicenseConcluded(String),
+ PackageLicenseInfoFromFiles(String),
+ PackageLicenseDeclared(String),
+ PackageLicenseComments(String),
+ PackageCopyrightText(String),
+ PackageSummary(String),
+ PackageDescription(String),
+ PackageComment(String),
+ ExternalRef(ExternalPackageReference),
+ ExternalRefComment(String),
+ PackageAttributionText(String),
+
+ // File Information
+ FileName(String),
+ FileType(FileType),
+ FileChecksum(Checksum),
+ LicenseConcluded(String),
+ LicenseInfoInFile(String),
+ LicenseComments(String),
+ FileCopyrightText(String),
+ FileComment(String),
+ FileNotice(String),
+ FileContributor(String),
+ FileAttributionText(String),
+
+ // Snippet Information
+ SnippetSPDXID(String),
+ SnippetFromFileSPDXID(String),
+ SnippetByteRange((i32, i32)),
+ SnippetLineRange((i32, i32)),
+ SnippetLicenseConcluded(String),
+ LicenseInfoInSnippet(String),
+ SnippetLicenseComments(String),
+ SnippetCopyrightText(String),
+ SnippetComment(String),
+ SnippetName(String),
+ SnippetAttributionText(String),
+
+ // Other Licensing Information Detected
+ LicenseID(String),
+ ExtractedText(String),
+ LicenseName(String),
+ LicenseCrossReference(String),
+ LicenseComment(String),
+
+ // Relationship
+ Relationship(Relationship),
+ RelationshipComment(String),
+
+ // Annotation
+ Annotator(String),
+ AnnotationDate(String),
+ AnnotationType(AnnotationType),
+ SPDXREF(String),
+ AnnotationComment(String),
+
+ /// Comment in the document. Not part of the final SPDX.
+ TVComment(String),
+}
+
+pub(super) fn atoms(i: &str) -> IResult<&str, Vec<Atom>, VerboseError<&str>> {
+ many0(alt((ws(tv_comment), ws(tag_value_to_atom))))(i)
+}
+
+fn tag_value_to_atom(i: &str) -> IResult<&str, Atom, VerboseError<&str>> {
+ let (i, key_value) = tag_value(i)?;
+ match key_value.0 {
+ // Document Creation Information
+ "SPDXVersion" => Ok((i, Atom::SpdxVersion(key_value.1.to_string()))),
+ "DataLicense" => Ok((i, Atom::DataLicense(key_value.1.to_string()))),
+ "SPDXID" => Ok((i, Atom::SPDXID(key_value.1.to_string()))),
+ "DocumentName" => Ok((i, Atom::DocumentName(key_value.1.to_string()))),
+ "DocumentNamespace" => Ok((i, Atom::DocumentNamespace(key_value.1.to_string()))),
+ "ExternalDocumentRef" => {
+ let (_, value) = external_document_reference(key_value.1)?;
+ Ok((i, Atom::ExternalDocumentRef(value)))
+ }
+ "LicenseListVersion" => Ok((i, Atom::LicenseListVersion(key_value.1.to_string()))),
+ "Creator" => Ok((i, Atom::Creator(key_value.1.to_string()))),
+ "Created" => Ok((i, Atom::Created(key_value.1.to_string()))),
+ "CreatorComment" => Ok((i, Atom::CreatorComment(key_value.1.to_string()))),
+ "DocumentComment" => Ok((i, Atom::DocumentComment(key_value.1.to_string()))),
+
+ // Package Information
+ "PackageName" => Ok((i, Atom::PackageName(key_value.1.to_string()))),
+ "PackageVersion" => Ok((i, Atom::PackageVersion(key_value.1.to_string()))),
+ "PackageFileName" => Ok((i, Atom::PackageFileName(key_value.1.to_string()))),
+ "PackageSupplier" => Ok((i, Atom::PackageSupplier(key_value.1.to_string()))),
+ "PackageOriginator" => Ok((i, Atom::PackageOriginator(key_value.1.to_string()))),
+ "PackageDownloadLocation" => {
+ Ok((i, Atom::PackageDownloadLocation(key_value.1.to_string())))
+ }
+ "FilesAnalyzed" => Ok((i, Atom::FilesAnalyzed(key_value.1.to_string()))),
+ "PackageVerificationCode" => {
+ let (_, value) = package_verification_code(key_value.1)?;
+ Ok((i, Atom::PackageVerificationCode(value)))
+ }
+ "PackageChecksum" => Ok((i, Atom::PackageChecksum(checksum(key_value.1)?.1))),
+ "PackageHomePage" => Ok((i, Atom::PackageHomePage(key_value.1.to_string()))),
+ "PackageSourceInfo" => Ok((i, Atom::PackageSourceInfo(key_value.1.to_string()))),
+ "PackageLicenseConcluded" => {
+ Ok((i, Atom::PackageLicenseConcluded(key_value.1.to_string())))
+ }
+ "PackageLicenseInfoFromFiles" => Ok((
+ i,
+ Atom::PackageLicenseInfoFromFiles(key_value.1.to_string()),
+ )),
+ "PackageLicenseDeclared" => Ok((i, Atom::PackageLicenseDeclared(key_value.1.to_string()))),
+ "PackageLicenseComments" => Ok((i, Atom::PackageLicenseComments(key_value.1.to_string()))),
+ "PackageCopyrightText" => Ok((i, Atom::PackageCopyrightText(key_value.1.to_string()))),
+ "PackageSummary" => Ok((i, Atom::PackageSummary(key_value.1.to_string()))),
+ "PackageDescription" => Ok((i, Atom::PackageDescription(key_value.1.to_string()))),
+ "PackageComment" => Ok((i, Atom::PackageComment(key_value.1.to_string()))),
+ "ExternalRef" => Ok((
+ i,
+ Atom::ExternalRef(external_package_reference(key_value.1)?.1),
+ )),
+ "ExternalRefComment" => Ok((i, Atom::ExternalRefComment(key_value.1.to_string()))),
+ "PackageAttributionText" => Ok((i, Atom::PackageAttributionText(key_value.1.to_string()))),
+
+ // File Information
+ "FileName" => Ok((i, Atom::FileName(key_value.1.to_string()))),
+ "FileType" => Ok((i, Atom::FileType(file_type(key_value.1)?.1))),
+ "FileChecksum" => Ok((i, Atom::FileChecksum(checksum(key_value.1)?.1))),
+ "LicenseConcluded" => Ok((i, Atom::LicenseConcluded(key_value.1.to_string()))),
+ "LicenseInfoInFile" => Ok((i, Atom::LicenseInfoInFile(key_value.1.to_string()))),
+ "LicenseComments" => Ok((i, Atom::LicenseComments(key_value.1.to_string()))),
+ "FileCopyrightText" => Ok((i, Atom::FileCopyrightText(key_value.1.to_string()))),
+ "FileComment" => Ok((i, Atom::FileComment(key_value.1.to_string()))),
+ "FileNotice" => Ok((i, Atom::FileNotice(key_value.1.to_string()))),
+ "FileContributor" => Ok((i, Atom::FileContributor(key_value.1.to_string()))),
+ "FileAttributionText" => Ok((i, Atom::FileAttributionText(key_value.1.to_string()))),
+
+ // Snippet Information
+ "SnippetSPDXID" => Ok((i, Atom::SnippetSPDXID(key_value.1.to_string()))),
+ "SnippetFromFileSPDXID" => Ok((i, Atom::SnippetFromFileSPDXID(key_value.1.to_string()))),
+ "SnippetByteRange" => Ok((i, Atom::SnippetByteRange(range(key_value.1)?.1))),
+ "SnippetLineRange" => Ok((i, Atom::SnippetLineRange(range(key_value.1)?.1))),
+ "SnippetLicenseConcluded" => {
+ Ok((i, Atom::SnippetLicenseConcluded(key_value.1.to_string())))
+ }
+ "LicenseInfoInSnippet" => Ok((i, Atom::LicenseInfoInSnippet(key_value.1.to_string()))),
+ "SnippetLicenseComments" => Ok((i, Atom::SnippetLicenseComments(key_value.1.to_string()))),
+ "SnippetCopyrightText" => Ok((i, Atom::SnippetCopyrightText(key_value.1.to_string()))),
+ "SnippetComment" => Ok((i, Atom::SnippetComment(key_value.1.to_string()))),
+ "SnippetName" => Ok((i, Atom::SnippetName(key_value.1.to_string()))),
+ "SnippetAttributionText" => Ok((i, Atom::SnippetAttributionText(key_value.1.to_string()))),
+
+ // Other Licensing Information Detected
+ "LicenseID" => Ok((i, Atom::LicenseID(key_value.1.to_string()))),
+ "ExtractedText" => Ok((i, Atom::ExtractedText(key_value.1.to_string()))),
+ "LicenseName" => Ok((i, Atom::LicenseName(key_value.1.to_string()))),
+ "LicenseCrossReference" => Ok((i, Atom::LicenseCrossReference(key_value.1.to_string()))),
+ "LicenseComment" => Ok((i, Atom::LicenseComment(key_value.1.to_string()))),
+
+ // Relationship
+ "Relationship" => Ok((i, Atom::Relationship(relationship(key_value.1)?.1))),
+ "RelationshipComment" => Ok((i, Atom::RelationshipComment(key_value.1.to_string()))),
+
+ // Annotation
+ "Annotator" => Ok((i, Atom::Annotator(key_value.1.to_string()))),
+ "AnnotationDate" => Ok((i, Atom::AnnotationDate(key_value.1.to_string()))),
+ "AnnotationType" => Ok((i, Atom::AnnotationType(annotation_type(key_value.1)?.1))),
+ "SPDXREF" => Ok((i, Atom::SPDXREF(key_value.1.to_string()))),
+ "AnnotationComment" => Ok((i, Atom::AnnotationComment(key_value.1.to_string()))),
+ v => {
+ dbg!(v);
+ unimplemented!()
+ }
+ }
+}
+
+fn external_document_reference(
+ i: &str,
+) -> IResult<&str, ExternalDocumentReference, VerboseError<&str>> {
+ map(
+ tuple((
+ document_ref,
+ ws(take_while(|c: char| !c.is_whitespace())),
+ ws(checksum),
+ )),
+ |(id_string, spdx_document_uri, checksum)| {
+ ExternalDocumentReference::new(
+ id_string.to_string(),
+ spdx_document_uri.to_string(),
+ checksum,
+ )
+ },
+ )(i)
+}
+
+fn annotation_type(i: &str) -> IResult<&str, AnnotationType, VerboseError<&str>> {
+ match ws(not_line_ending)(i) {
+ Ok((i, value)) => match value {
+ "REVIEW" => Ok((i, AnnotationType::Review)),
+ "OTHER" => Ok((i, AnnotationType::Other)),
+ // Proper error
+ _ => todo!(),
+ },
+ Err(err) => Err(err),
+ }
+}
+
+fn file_type(i: &str) -> IResult<&str, FileType, VerboseError<&str>> {
+ match ws(not_line_ending)(i) {
+ Ok((i, value)) => match value {
+ "SOURCE" => Ok((i, FileType::Source)),
+ "BINARY" => Ok((i, FileType::Binary)),
+ "ARCHIVE" => Ok((i, FileType::Archive)),
+ "APPLICATION" => Ok((i, FileType::Application)),
+ "AUDIO" => Ok((i, FileType::Audio)),
+ "IMAGE" => Ok((i, FileType::Image)),
+ "TEXT" => Ok((i, FileType::Text)),
+ "VIDEO" => Ok((i, FileType::Video)),
+ "DOCUMENTATION" => Ok((i, FileType::Documentation)),
+ "SPDX" => Ok((i, FileType::SPDX)),
+ "OTHER" => Ok((i, FileType::Other)),
+ // Proper error
+ _ => todo!(),
+ },
+ Err(err) => Err(err),
+ }
+}
+
+fn document_ref<'a>(i: &'a str) -> IResult<&'a str, &str, VerboseError<&'a str>> {
+ preceded(tag("DocumentRef-"), ws(idstring))(i)
+}
+
+fn relationship(i: &str) -> IResult<&str, Relationship, VerboseError<&str>> {
+ map(
+ tuple((
+ ws(take_while(|c: char| !c.is_whitespace())),
+ ws(take_while(|c: char| !c.is_whitespace())),
+ ws(not_line_ending),
+ )),
+ |(item1, relationship_type, item2)| {
+ let relationship_type = relationship_type.to_uppercase();
+ let relationship_type = match relationship_type.as_str() {
+ "DESCRIBES" => RelationshipType::Describes,
+ "DESCRIBED_BY" => RelationshipType::DescribedBy,
+ "CONTAINS" => RelationshipType::Contains,
+ "CONTAINED_BY" => RelationshipType::ContainedBy,
+ "DEPENDS_ON" => RelationshipType::DependsOn,
+ "DEPENDENCY_OF" => RelationshipType::DependencyOf,
+ "DEPENDENCY_MANIFEST_OF" => RelationshipType::DependencyManifestOf,
+ "BUILD_DEPENDENCY_OF" => RelationshipType::BuildDependencyOf,
+ "DEV_DEPENDENCY_OF" => RelationshipType::DevDependencyOf,
+ "OPTIONAL_DEPENDENCY_OF" => RelationshipType::OptionalDependencyOf,
+ "PROVIDED_DEPENDENCY_OF" => RelationshipType::ProvidedDependencyOf,
+ "TEST_DEPENDENCY_OF" => RelationshipType::TestDependencyOf,
+ "RUNTIME_DEPENDENCY_OF" => RelationshipType::RuntimeDependencyOf,
+ "EXAMPLE_OF" => RelationshipType::ExampleOf,
+ "GENERATES" => RelationshipType::Generates,
+ "GENERATED_FROM" => RelationshipType::GeneratedFrom,
+ "ANCESTOR_OF" => RelationshipType::AncestorOf,
+ "DESCENDANT_OF" => RelationshipType::DescendantOf,
+ "VARIANT_OF" => RelationshipType::VariantOf,
+ "DISTRIBUTION_ARTIFACT" => RelationshipType::DistributionArtifact,
+ "PATCH_FOR" => RelationshipType::PatchFor,
+ "PATCH_APPLIED" => RelationshipType::PatchApplied,
+ "COPY_OF" => RelationshipType::CopyOf,
+ "FILE_ADDED" => RelationshipType::FileAdded,
+ "FILE_DELETED" => RelationshipType::FileDeleted,
+ "FILE_MODIFIED" => RelationshipType::FileModified,
+ "EXPANDED_FROM_ARCHIVE" => RelationshipType::ExpandedFromArchive,
+ "DYNAMIC_LINK" => RelationshipType::DynamicLink,
+ "STATIC_LINK" => RelationshipType::StaticLink,
+ "DATA_FILE_OF" => RelationshipType::DataFileOf,
+ "TEST_CASE_OF" => RelationshipType::TestCaseOf,
+ "BUILD_TOOL_OF" => RelationshipType::BuildToolOf,
+ "DEV_TOOL_OF" => RelationshipType::DevToolOf,
+ "TEST_OF" => RelationshipType::TestOf,
+ "TEST_TOOL_OF" => RelationshipType::TestToolOf,
+ "DOCUMENTATION_OF" => RelationshipType::DocumentationOf,
+ "OPTIONAL_COMPONENT_OF" => RelationshipType::OptionalComponentOf,
+ "METAFILE_OF" => RelationshipType::MetafileOf,
+ "PACKAGE_OF" => RelationshipType::PackageOf,
+ "AMENDS" => RelationshipType::Amends,
+ "PREREQUISITE_FOR" => RelationshipType::PrerequisiteFor,
+ "HAS_PREREQUISITE" => RelationshipType::HasPrerequisite,
+ "OTHER" => RelationshipType::Other,
+ // TODO: Proper error.
+ _ => {
+ dbg!(relationship_type);
+ todo!()
+ }
+ };
+ Relationship::new(item1, item2, relationship_type, None)
+ },
+ )(i)
+}
+
+fn external_package_reference(
+ i: &str,
+) -> IResult<&str, ExternalPackageReference, VerboseError<&str>> {
+ map(
+ tuple((
+ ws(take_while(|c: char| !c.is_whitespace())),
+ ws(take_while(|c: char| !c.is_whitespace())),
+ ws(not_line_ending),
+ )),
+ |(category, ref_type, locator)| {
+ let category = match category {
+ "SECURITY" => ExternalPackageReferenceCategory::Security,
+ "PACKAGE-MANAGER" => ExternalPackageReferenceCategory::PackageManager,
+ "PERSISTENT-ID" => ExternalPackageReferenceCategory::PersistentID,
+ "OTHER" => ExternalPackageReferenceCategory::Other,
+ // TODO: Proper error handling
+ _ => todo!(),
+ };
+ ExternalPackageReference::new(category, ref_type.to_string(), locator.to_string(), None)
+ },
+ )(i)
+}
+
+fn package_verification_code(
+ i: &str,
+) -> IResult<&str, PackageVerificationCode, VerboseError<&str>> {
+ map(
+ alt((
+ separated_pair(
+ ws(take_until("(excludes:")),
+ ws(tag("(excludes:")),
+ opt(take_until(")")),
+ ),
+ map(ws(not_line_ending), |v| (v, None)),
+ )),
+ |(value, exclude)| {
+ #[allow(clippy::option_if_let_else)]
+ let excludes = if let Some(exclude) = exclude {
+ vec![exclude.to_string()]
+ } else {
+ Vec::new()
+ };
+ PackageVerificationCode::new(value.to_string(), excludes)
+ },
+ )(i)
+}
+
+fn range(i: &str) -> IResult<&str, (i32, i32), VerboseError<&str>> {
+ map_res::<_, _, _, _, ParseIntError, _, _>(
+ separated_pair(digit1, char(':'), digit1),
+ |(left, right)| Ok((i32::from_str(left)?, i32::from_str(right)?)),
+ )(i)
+}
+
+fn idstring<'a>(i: &'a str) -> IResult<&'a str, &str, VerboseError<&'a str>> {
+ take_while(|c: char| c.is_alphanum() || c == '.' || c == '-' || c == '+')(i)
+}
+
+fn checksum(i: &str) -> IResult<&str, Checksum, VerboseError<&str>> {
+ map(
+ separated_pair(ws(take_until(":")), char(':'), ws(not_line_ending)),
+ |(algorithm, value)| {
+ let checksum_algorithm = match algorithm {
+ "SHA1" => Algorithm::SHA1,
+ "SHA224" => Algorithm::SHA224,
+ "SHA256" => Algorithm::SHA256,
+ "SHA384" => Algorithm::SHA384,
+ "SHA512" => Algorithm::SHA512,
+ "MD2" => Algorithm::MD2,
+ "MD4" => Algorithm::MD4,
+ "MD5" => Algorithm::MD5,
+ "MD6" => Algorithm::MD6,
+ // TODO: Use proper error.
+ _ => todo!(),
+ };
+ Checksum::new(checksum_algorithm, value)
+ },
+ )(i)
+}
+
+fn tv_comment(i: &str) -> IResult<&str, Atom, VerboseError<&str>> {
+ map(preceded(ws(tag("#")), ws(not_line_ending)), |v| {
+ Atom::TVComment(v.to_string())
+ })(i)
+}
+
+fn tag_value<'a>(i: &'a str) -> IResult<&'a str, (&str, &str), VerboseError<&'a str>> {
+ separated_pair(
+ ws(alphanumeric0),
+ tag(":"),
+ alt((ws(multiline_text), ws(not_line_ending))),
+ )(i)
+}
+
+fn multiline_text<'a>(i: &'a str) -> IResult<&'a str, &str, VerboseError<&'a str>> {
+ delimited(tag("<text>"), take_until("</text>"), tag("</text>"))(i)
+}
+
+/// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and
+/// trailing whitespace, returning the output of `inner`.
+fn ws<'a, F, O, E: ParseError<&'a str>>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
+where
+ F: Fn(&'a str) -> IResult<&'a str, O, E> + 'a,
+{
+ delimited(multispace0, inner, multispace0)
+}
+
+#[cfg(test)]
+mod tests {
+ use std::fs::read_to_string;
+
+ use crate::{
+ models::{Algorithm, AnnotationType, ExternalPackageReferenceCategory, Relationship},
+ parsers::tag_value::{
+ annotation_type, checksum, document_ref, external_document_reference,
+ external_package_reference, package_verification_code, range, relationship,
+ },
+ };
+
+ use super::{atoms, tag_value, tag_value_to_atom, Atom};
+
+ #[test]
+ fn version_can_be_parsed() {
+ let (_, value) = tag_value_to_atom("SPDXVersion: SPDX-1.2").unwrap();
+ assert_eq!(value, Atom::SpdxVersion("SPDX-1.2".to_string()));
+ }
+
+ #[test]
+ fn range_can_be_parsed() {
+ let (_, value) = range("310:420").unwrap();
+ assert_eq!(value, (310, 420));
+ }
+
+ #[test]
+ fn annotation_type_can_be_parsed() {
+ let (_, value) = annotation_type("REVIEW").unwrap();
+ assert_eq!(value, AnnotationType::Review);
+ let (_, value) = annotation_type("OTHER").unwrap();
+ assert_eq!(value, AnnotationType::Other);
+ }
+
+ #[test]
+ fn relationship_can_be_parsed() {
+ let (_, value) = relationship("SPDXRef-JenaLib CONTAINS SPDXRef-Package").unwrap();
+ let expected = Relationship::new(
+ "SPDXRef-JenaLib",
+ "SPDXRef-Package",
+ crate::models::RelationshipType::Contains,
+ None,
+ );
+ assert_eq!(value, expected);
+ }
+
+ #[test]
+ fn data_license_can_be_parsed() {
+ let (_, value) = tag_value_to_atom("DataLicense: CC0-1.0").unwrap();
+ assert_eq!(value, Atom::DataLicense("CC0-1.0".to_string()));
+ }
+
+ #[test]
+ fn package_verification_code_can_be_parsed() {
+ let (_, value) = package_verification_code(
+ "d6a770ba38583ed4bb4525bd96e50461655d2758(excludes: ./package.spdx)",
+ )
+ .unwrap();
+ assert_eq!(value.value, "d6a770ba38583ed4bb4525bd96e50461655d2758");
+ assert_eq!(value.excludes, vec!["./package.spdx"]);
+ }
+
+ #[test]
+ fn package_verification_code_without_excludes_can_be_parsed() {
+ let (_, value) =
+ package_verification_code("d6a770ba38583ed4bb4525bd96e50461655d2758").unwrap();
+ assert_eq!(value.value, "d6a770ba38583ed4bb4525bd96e50461655d2758");
+ let expected: Vec<String> = Vec::new();
+ assert_eq!(value.excludes, expected);
+ }
+
+ #[test]
+ fn external_package_ref_can_be_parsed() {
+ let (_, value) = external_package_reference(
+ "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*",
+ )
+ .unwrap();
+ assert_eq!(
+ value.reference_category,
+ ExternalPackageReferenceCategory::Security
+ );
+ assert_eq!(value.reference_type, "cpe23Type");
+ assert_eq!(
+ value.reference_locator,
+ "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
+ );
+ }
+
+ #[test]
+ fn external_document_reference_can_be_parsed() {
+ let (_, value) = external_document_reference("DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759").unwrap();
+ assert_eq!(value.id_string, "spdx-tool-1.2");
+ assert_eq!(
+ value.spdx_document_uri,
+ "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
+ );
+ assert_eq!(value.checksum.algorithm, Algorithm::SHA1);
+ assert_eq!(
+ value.checksum.value,
+ "d6a770ba38583ed4bb4525bd96e50461655d2759"
+ );
+ }
+
+ #[test]
+ fn document_ref_can_be_parsed() {
+ let (_, value) = document_ref("DocumentRef-spdx-tool-1.2").unwrap();
+ assert_eq!(value, "spdx-tool-1.2");
+ }
+
+ #[test]
+ fn checksum_can_be_parsed() {
+ let (_, value) = checksum("SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759").unwrap();
+ assert_eq!(value.algorithm, Algorithm::SHA1);
+ assert_eq!(value.value, "d6a770ba38583ed4bb4525bd96e50461655d2759");
+ }
+
+ #[test]
+ fn document_comment_can_be_parsed() {
+ let (_, value) = tag_value_to_atom("DocumentComment: <text>Sample Comment</text>").unwrap();
+ assert_eq!(value, Atom::DocumentComment("Sample Comment".to_string()));
+ }
+
+ #[test]
+ fn multiline_document_comment_can_be_parsed() {
+ let (_, value) = tag_value_to_atom(
+ "DocumentComment: <text>Sample
+Comment</text>",
+ )
+ .unwrap();
+ assert_eq!(value, Atom::DocumentComment("Sample\nComment".to_string()));
+ }
+
+ #[test]
+ fn multiple_key_values_can_be_parsed() {
+ let input = "SPDXVersion: SPDX-1.2
+ DataLicense: CC0-1.0
+ DocumentComment: <text>Sample Comment</text>";
+
+ let (_, value) = atoms(input).unwrap();
+ assert_eq!(
+ value,
+ vec![
+ Atom::SpdxVersion("SPDX-1.2".to_string()),
+ Atom::DataLicense("CC0-1.0".to_string()),
+ Atom::DocumentComment("Sample Comment".to_string())
+ ]
+ );
+ }
+
+ #[test]
+ fn multiple_key_values_with_comment_can_be_parsed() {
+ let input = "SPDXVersion: SPDX-1.2
+ # A comment
+ DataLicense: CC0-1.0
+ DocumentComment: <text>Sample Comment</text>";
+
+ let (_, value) = atoms(input).unwrap();
+ assert_eq!(
+ value,
+ vec![
+ Atom::SpdxVersion("SPDX-1.2".to_string()),
+ Atom::TVComment("A comment".to_string()),
+ Atom::DataLicense("CC0-1.0".to_string()),
+ Atom::DocumentComment("Sample Comment".to_string())
+ ]
+ );
+ }
+
+ #[test]
+ fn multiple_key_values_with_space_can_be_parsed() {
+ let input = "SPDXVersion: SPDX-1.2
+
+ DataLicense: CC0-1.0
+ DocumentComment: <text>Sample Comment</text>";
+
+ let (_, value) = atoms(input).unwrap();
+ assert_eq!(
+ value,
+ vec![
+ Atom::SpdxVersion("SPDX-1.2".to_string()),
+ Atom::DataLicense("CC0-1.0".to_string()),
+ Atom::DocumentComment("Sample Comment".to_string())
+ ]
+ );
+ }
+
+ #[test]
+ fn key_value_pair_is_detected() {
+ let (_, value) = tag_value("SPDXVersion: SPDX-1.2").unwrap();
+ assert_eq!(value, ("SPDXVersion", "SPDX-1.2"));
+ }
+
+ #[test]
+ fn get_tag_values_from_simple_example_file() {
+ let file = read_to_string("tests/data/SPDXSimpleTag.tag").unwrap();
+ let (remains, result) = atoms(&file).unwrap();
+ assert_eq!(remains.len(), 0);
+ assert!(result.contains(&Atom::SpdxVersion("SPDX-1.2".to_string())));
+ assert!(result.contains(&Atom::PackageName("Test".to_string())));
+ assert!(result.contains(&Atom::PackageDescription("A package.".to_string())));
+ }
+
+ #[test]
+ fn get_tag_values_from_example_file() {
+ let file = read_to_string("tests/data/SPDXTagExample-v2.2.spdx").unwrap();
+ let (remains, result) = atoms(&file).unwrap();
+ assert_eq!(remains.len(), 0);
+ assert!(result.contains(&Atom::SpdxVersion("SPDX-2.2".to_string())));
+ assert!(result.contains(&Atom::LicenseListVersion("3.9".to_string())));
+ assert!(result.contains(&Atom::PackageLicenseDeclared("MPL-1.0".to_string())));
+ }
+
+ #[test]
+ fn relationship_case() {
+ relationship("SPDXRef-DOCUMENT DESCRIBES SPDXRef-File").expect("Caps is expected");
+ relationship("SPDXRef-DOCUMENT describes SPDXRef-File")
+ .expect("At least reuse-tool emits lowercase");
+ }
+}