diff --git a/.github/workflows/check_codestyle.yml b/.github/workflows/check_codestyle.yml index aa05fce9f..89f6a13b5 100644 --- a/.github/workflows/check_codestyle.yml +++ b/.github/workflows/check_codestyle.yml @@ -25,7 +25,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Installation - run: pip install ".[codestyle]" + run: pip install ".[code_style]" - name: Check code with isort run: | isort src tests --check diff --git a/src/common/typing/constructor_type_errors.py b/src/common/typing/constructor_type_errors.py index 52b3a4db8..90c8d8402 100644 --- a/src/common/typing/constructor_type_errors.py +++ b/src/common/typing/constructor_type_errors.py @@ -6,6 +6,7 @@ class ConstructorTypeErrors(TypeError): Helper class that holds a list of error messages. Intended to capture all TypeErrors encountered during a constructor call, instead of raising only the first one. """ + messages: List[str] def __init__(self, messages: List[str]): diff --git a/src/common/typing/dataclass_with_properties.py b/src/common/typing/dataclass_with_properties.py index b53d9eb37..644a1269e 100644 --- a/src/common/typing/dataclass_with_properties.py +++ b/src/common/typing/dataclass_with_properties.py @@ -47,9 +47,10 @@ def get_field_with_better_error_message(self) -> field_type: return get_field(self) except TypeError as err: error_message: str = f"GetterError {self.__class__.__name__}: {err.args[0]}" - # As getters are created dynamically, their argument name is always "the return value". We replace it by the - # actual name so the error message is more helpful. + # As getters are created dynamically, their argument name is always "the return value". + # We replace it by the actual name so the error message is more helpful. raise TypeError( - error_message.replace("the return value", field_name, 1) + f': {getattr(self, f"_{field_name}")}') + error_message.replace("the return value", field_name, 1) + f': {getattr(self, f"_{field_name}")}' + ) return get_field_with_better_error_message diff --git a/src/spdx/clitools/pyspdxtools.py b/src/spdx/clitools/pyspdxtools.py index 44a4a3bac..dece3733f 100644 --- a/src/spdx/clitools/pyspdxtools.py +++ b/src/spdx/clitools/pyspdxtools.py @@ -27,11 +27,17 @@ @click.command() @click.option("--infile", "-i", help="The file containing the document to be validated or converted.") -@click.option("--outfile", "-o", - help="The file to write the converted document to (write a dash for output to stdout or omit for no conversion).") -@click.option("--version", - help='The SPDX version to be used during parsing and validation ("SPDX-2.2" or "SPDX-2.3"). Will be read from the document if not provided.', - default=None) +@click.option( + "--outfile", + "-o", + help="The file to write the converted document to (write a dash for output to stdout or omit for no conversion).", +) +@click.option( + "--version", + help='The SPDX version to be used during parsing and validation ("SPDX-2.2" or "SPDX-2.3"). ' + "Will be read from the document if not provided.", + default=None, +) @click.option("--novalidation", is_flag=True, help="Don't validate the provided document.") def main(infile: str, outfile: str, version: str, novalidation: bool): """ @@ -49,15 +55,16 @@ def main(infile: str, outfile: str, version: str, novalidation: bool): if not version: version = document.creation_info.spdx_version - if not version in ["SPDX-2.2", "SPDX-2.3"]: + if version not in ["SPDX-2.2", "SPDX-2.3"]: logging.error(f"This tool only supports SPDX versions SPDX-2.2 and SPDX-2.3, but got: {version}") sys.exit(1) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document, version) if validation_messages: log_string = "\n".join( - ["The document is invalid. The following issues have been found:"] + - [message.validation_message for message in validation_messages]) + ["The document is invalid. The following issues have been found:"] + + [message.validation_message for message in validation_messages] + ) logging.error(log_string) sys.exit(1) else: @@ -67,16 +74,20 @@ def main(infile: str, outfile: str, version: str, novalidation: bool): write_file(document, outfile, validate=False) except NotImplementedError as err: - logging.error(err.args[0] + - "\nPlease note that this project is currently undergoing a major refactoring and therefore missing " - "a few features which will be added in time (refer to https://github.com/spdx/tools-python/issues " - "for insights into the current status).\n" - "In the meantime, please use the current PyPI release version.") + logging.error( + err.args[0] + + "\nPlease note that this project is currently undergoing a major refactoring and therefore missing " + "a few features which will be added in time (refer to https://github.com/spdx/tools-python/issues " + "for insights into the current status).\n" + "In the meantime, please use the current PyPI release version." + ) sys.exit(1) except SPDXParsingError as err: - log_string = "\n".join(["There have been issues while parsing the provided document:"] + - [message for message in err.get_messages()]) + log_string = "\n".join( + ["There have been issues while parsing the provided document:"] + + [message for message in err.get_messages()] + ) logging.error(log_string) sys.exit(1) diff --git a/src/spdx/datetime_conversions.py b/src/spdx/datetime_conversions.py index 62fafe866..e0a1383bc 100644 --- a/src/spdx/datetime_conversions.py +++ b/src/spdx/datetime_conversions.py @@ -15,12 +15,12 @@ def datetime_from_str(date_str: str) -> datetime: if not isinstance(date_str, str): raise TypeError(f"Could not convert str to datetime, invalid type: {type(date_str).__name__}") - date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match + date = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ") # raises ValueError if format does not match return date + def datetime_to_iso_string(date: datetime) -> str: """ Return an ISO-8601 representation of a datetime object. """ return date.isoformat() + "Z" - diff --git a/src/spdx/document_utils.py b/src/spdx/document_utils.py index 74a49faf9..b212cc77b 100644 --- a/src/spdx/document_utils.py +++ b/src/spdx/document_utils.py @@ -8,13 +8,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import List -from typing import Union +from typing import List, Union from spdx.model.document import Document -from spdx.model.snippet import Snippet -from spdx.model.package import Package from spdx.model.file import File +from spdx.model.package import Package +from spdx.model.snippet import Snippet def get_contained_spdx_element_ids(document: Document) -> List[str]: diff --git a/src/spdx/jsonschema/annotation_converter.py b/src/spdx/jsonschema/annotation_converter.py index c4bf4277e..b06c932da 100644 --- a/src/spdx/jsonschema/annotation_converter.py +++ b/src/spdx/jsonschema/annotation_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.datetime_conversions import datetime_to_iso_string from spdx.jsonschema.annotation_properties import AnnotationProperty @@ -19,8 +19,9 @@ class AnnotationConverter(TypedConverter[Annotation]): - def _get_property_value(self, annotation: Annotation, annotation_property: AnnotationProperty, - document: Document = None) -> Any: + def _get_property_value( + self, annotation: Annotation, annotation_property: AnnotationProperty, document: Document = None + ) -> Any: if annotation_property == AnnotationProperty.ANNOTATION_DATE: return datetime_to_iso_string(annotation.annotation_date) elif annotation_property == AnnotationProperty.ANNOTATION_TYPE: diff --git a/src/spdx/jsonschema/checksum_converter.py b/src/spdx/jsonschema/checksum_converter.py index 6782adba2..edc466311 100644 --- a/src/spdx/jsonschema/checksum_converter.py +++ b/src/spdx/jsonschema/checksum_converter.py @@ -18,15 +18,15 @@ class ChecksumConverter(TypedConverter[Checksum]): - def get_data_model_type(self) -> Type[Checksum]: return Checksum def get_json_type(self) -> Type[JsonProperty]: return ChecksumProperty - def _get_property_value(self, checksum: Checksum, checksum_property: ChecksumProperty, - _document: Document = None) -> str: + def _get_property_value( + self, checksum: Checksum, checksum_property: ChecksumProperty, _document: Document = None + ) -> str: if checksum_property == ChecksumProperty.ALGORITHM: return algorithm_to_json_string(checksum.algorithm) elif checksum_property == ChecksumProperty.CHECKSUM_VALUE: diff --git a/src/spdx/jsonschema/converter.py b/src/spdx/jsonschema/converter.py index 4fddd4e1d..45444dc03 100644 --- a/src/spdx/jsonschema/converter.py +++ b/src/spdx/jsonschema/converter.py @@ -9,11 +9,11 @@ # See the License for the specific language governing permissions and # limitations under the License. from abc import ABC, abstractmethod -from typing import Any, Type, Dict, TypeVar, Generic +from typing import Any, Dict, Generic, Type, TypeVar +from spdx.casing_tools import snake_case_to_camel_case from spdx.jsonschema.json_property import JsonProperty from spdx.model.document import Document -from spdx.casing_tools import snake_case_to_camel_case MISSING_IMPLEMENTATION_MESSAGE = "Must be implemented" @@ -60,7 +60,8 @@ def convert(self, instance: T, document: Document = None) -> Dict: if not isinstance(instance, self.get_data_model_type()): raise TypeError( f"Converter of type {self.__class__} can only convert objects of type " - f"{self.get_data_model_type()}. Received {type(instance)} instead.") + f"{self.get_data_model_type()}. Received {type(instance)} instead." + ) if self.requires_full_document() and not document: raise ValueError(f"Converter of type {self.__class__} requires the full document") diff --git a/src/spdx/jsonschema/creation_info_converter.py b/src/spdx/jsonschema/creation_info_converter.py index c4896659a..96ded13a0 100644 --- a/src/spdx/jsonschema/creation_info_converter.py +++ b/src/spdx/jsonschema/creation_info_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.datetime_conversions import datetime_to_iso_string from spdx.jsonschema.converter import TypedConverter @@ -25,8 +25,9 @@ def get_data_model_type(self) -> Type[CreationInfo]: def get_json_type(self) -> Type[JsonProperty]: return CreationInfoProperty - def _get_property_value(self, creation_info: CreationInfo, creation_info_property: CreationInfoProperty, - _document: Document = None) -> Any: + def _get_property_value( + self, creation_info: CreationInfo, creation_info_property: CreationInfoProperty, _document: Document = None + ) -> Any: if creation_info_property == CreationInfoProperty.CREATED: return datetime_to_iso_string(creation_info.created) elif creation_info_property == CreationInfoProperty.CREATORS: diff --git a/src/spdx/jsonschema/document_converter.py b/src/spdx/jsonschema/document_converter.py index 71a3c76c5..598dceb2d 100644 --- a/src/spdx/jsonschema/document_converter.py +++ b/src/spdx/jsonschema/document_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.document_utils import get_contained_spdx_element_ids from spdx.jsonschema.annotation_converter import AnnotationConverter @@ -24,9 +24,12 @@ from spdx.jsonschema.snippet_converter import SnippetConverter from spdx.model.document import Document from spdx.model.relationship import RelationshipType -from spdx.model.relationship_filters import filter_by_type_and_origin, filter_by_type_and_target, \ - find_package_contains_file_relationships, \ - find_file_contained_by_package_relationships +from spdx.model.relationship_filters import ( + filter_by_type_and_origin, + filter_by_type_and_target, + find_file_contained_by_package_relationships, + find_package_contains_file_relationships, +) class DocumentConverter(TypedConverter[Document]): @@ -60,15 +63,17 @@ def json_property_name(self, document_property: DocumentProperty) -> str: return "SPDXID" return super().json_property_name(document_property) - def _get_property_value(self, document: Document, document_property: DocumentProperty, - _document: Document = None) -> Any: + def _get_property_value( + self, document: Document, document_property: DocumentProperty, _document: Document = None + ) -> Any: if document_property == DocumentProperty.SPDX_ID: return document.creation_info.spdx_id elif document_property == DocumentProperty.ANNOTATIONS: # annotations referencing files, packages or snippets will be added to those elements directly element_ids = get_contained_spdx_element_ids(document) - document_annotations = filter(lambda annotation: annotation.spdx_id not in element_ids, - document.annotations) + document_annotations = filter( + lambda annotation: annotation.spdx_id not in element_ids, document.annotations + ) return [self.annotation_converter.convert(annotation) for annotation in document_annotations] or None elif document_property == DocumentProperty.COMMENT: return document.creation_info.document_comment @@ -77,11 +82,15 @@ def _get_property_value(self, document: Document, document_property: DocumentPro elif document_property == DocumentProperty.DATA_LICENSE: return document.creation_info.data_license elif document_property == DocumentProperty.EXTERNAL_DOCUMENT_REFS: - return [self.external_document_ref_converter.convert(external_document_ref) for - external_document_ref in document.creation_info.external_document_refs] or None + return [ + self.external_document_ref_converter.convert(external_document_ref) + for external_document_ref in document.creation_info.external_document_refs + ] or None elif document_property == DocumentProperty.HAS_EXTRACTED_LICENSING_INFOS: - return [self.extracted_licensing_info_converter.convert(licensing_info) for licensing_info in - document.extracted_licensing_info] or None + return [ + self.extracted_licensing_info_converter.convert(licensing_info) + for licensing_info in document.extracted_licensing_info + ] or None elif document_property == DocumentProperty.NAME: return document.creation_info.name elif document_property == DocumentProperty.SPDX_VERSION: @@ -89,12 +98,18 @@ def _get_property_value(self, document: Document, document_property: DocumentPro elif document_property == DocumentProperty.DOCUMENT_NAMESPACE: return document.creation_info.document_namespace elif document_property == DocumentProperty.DOCUMENT_DESCRIBES: - describes_ids = [relationship.related_spdx_element_id for relationship in - filter_by_type_and_origin(document.relationships, RelationshipType.DESCRIBES, - document.creation_info.spdx_id)] - described_by_ids = [relationship.spdx_element_id for relationship in - filter_by_type_and_target(document.relationships, RelationshipType.DESCRIBED_BY, - document.creation_info.spdx_id)] + describes_ids = [ + relationship.related_spdx_element_id + for relationship in filter_by_type_and_origin( + document.relationships, RelationshipType.DESCRIBES, document.creation_info.spdx_id + ) + ] + described_by_ids = [ + relationship.spdx_element_id + for relationship in filter_by_type_and_target( + document.relationships, RelationshipType.DESCRIBED_BY, document.creation_info.spdx_id + ) + ] return describes_ids + described_by_ids or None elif document_property == DocumentProperty.PACKAGES: return [self.package_converter.convert(package, document) for package in document.packages] or None @@ -103,16 +118,22 @@ def _get_property_value(self, document: Document, document_property: DocumentPro elif document_property == DocumentProperty.SNIPPETS: return [self.snippet_converter.convert(snippet, document) for snippet in document.snippets] or None elif document_property == DocumentProperty.RELATIONSHIPS: - already_covered_relationships = filter_by_type_and_origin(document.relationships, - RelationshipType.DESCRIBES, - document.creation_info.spdx_id) + already_covered_relationships = filter_by_type_and_origin( + document.relationships, RelationshipType.DESCRIBES, document.creation_info.spdx_id + ) already_covered_relationships.extend( - filter_by_type_and_target(document.relationships, RelationshipType.DESCRIBED_BY, - document.creation_info.spdx_id)) + filter_by_type_and_target( + document.relationships, RelationshipType.DESCRIBED_BY, document.creation_info.spdx_id + ) + ) for package in document.packages: already_covered_relationships.extend(find_package_contains_file_relationships(document, package)) already_covered_relationships.extend(find_file_contained_by_package_relationships(document, package)) - relationships_to_ignore = [relationship for relationship in already_covered_relationships if - relationship.comment is None] - return [self.relationship_converter.convert(relationship) for relationship in document.relationships if - relationship not in relationships_to_ignore] or None + relationships_to_ignore = [ + relationship for relationship in already_covered_relationships if relationship.comment is None + ] + return [ + self.relationship_converter.convert(relationship) + for relationship in document.relationships + if relationship not in relationships_to_ignore + ] or None diff --git a/src/spdx/jsonschema/external_document_ref_converter.py b/src/spdx/jsonschema/external_document_ref_converter.py index 023b38136..03dccf795 100644 --- a/src/spdx/jsonschema/external_document_ref_converter.py +++ b/src/spdx/jsonschema/external_document_ref_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.checksum_converter import ChecksumConverter from spdx.jsonschema.converter import TypedConverter @@ -24,9 +24,12 @@ class ExternalDocumentRefConverter(TypedConverter[ExternalDocumentRef]): def __init__(self): self.checksum_converter = ChecksumConverter() - def _get_property_value(self, external_document_ref: ExternalDocumentRef, - external_document_ref_property: ExternalDocumentRefProperty, - _document: Document = None) -> Any: + def _get_property_value( + self, + external_document_ref: ExternalDocumentRef, + external_document_ref_property: ExternalDocumentRefProperty, + _document: Document = None, + ) -> Any: if external_document_ref_property == ExternalDocumentRefProperty.EXTERNAL_DOCUMENT_ID: return external_document_ref.document_ref_id elif external_document_ref_property == ExternalDocumentRefProperty.SPDX_DOCUMENT: diff --git a/src/spdx/jsonschema/external_package_ref_converter.py b/src/spdx/jsonschema/external_package_ref_converter.py index f1374c7c2..5dbbb1e45 100644 --- a/src/spdx/jsonschema/external_package_ref_converter.py +++ b/src/spdx/jsonschema/external_package_ref_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.converter import TypedConverter from spdx.jsonschema.external_package_ref_properties import ExternalPackageRefProperty @@ -18,8 +18,12 @@ class ExternalPackageRefConverter(TypedConverter[ExternalPackageRef]): - def _get_property_value(self, external_ref: ExternalPackageRef, external_ref_property: ExternalPackageRefProperty, - document: Document = None) -> Any: + def _get_property_value( + self, + external_ref: ExternalPackageRef, + external_ref_property: ExternalPackageRefProperty, + document: Document = None, + ) -> Any: if external_ref_property == ExternalPackageRefProperty.COMMENT: return external_ref.comment elif external_ref_property == ExternalPackageRefProperty.REFERENCE_CATEGORY: diff --git a/src/spdx/jsonschema/extracted_licensing_info_converter.py b/src/spdx/jsonschema/extracted_licensing_info_converter.py index 3d198e3d6..9d7ea23c5 100644 --- a/src/spdx/jsonschema/extracted_licensing_info_converter.py +++ b/src/spdx/jsonschema/extracted_licensing_info_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.converter import TypedConverter from spdx.jsonschema.extracted_licensing_info_properties import ExtractedLicensingInfoProperty @@ -19,9 +19,12 @@ class ExtractedLicensingInfoConverter(TypedConverter[ExtractedLicensingInfo]): - def _get_property_value(self, extracted_licensing_info: ExtractedLicensingInfo, - extracted_licensing_info_property: ExtractedLicensingInfoProperty, - document: Document = None) -> Any: + def _get_property_value( + self, + extracted_licensing_info: ExtractedLicensingInfo, + extracted_licensing_info_property: ExtractedLicensingInfoProperty, + document: Document = None, + ) -> Any: if extracted_licensing_info_property == ExtractedLicensingInfoProperty.COMMENT: return extracted_licensing_info.comment elif extracted_licensing_info_property == ExtractedLicensingInfoProperty.EXTRACTED_TEXT: diff --git a/src/spdx/jsonschema/file_converter.py b/src/spdx/jsonschema/file_converter.py index 0d339c890..3b22a6108 100644 --- a/src/spdx/jsonschema/file_converter.py +++ b/src/spdx/jsonschema/file_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.annotation_converter import AnnotationConverter from spdx.jsonschema.checksum_converter import ChecksumConverter diff --git a/src/spdx/jsonschema/json_property.py b/src/spdx/jsonschema/json_property.py index 0f65a77f2..fa0114bac 100644 --- a/src/spdx/jsonschema/json_property.py +++ b/src/spdx/jsonschema/json_property.py @@ -17,4 +17,5 @@ class JsonProperty(Enum): type that can be used in type hints. In general, all the child enums list the properties of the corresponding objects from the json schema. """ + pass diff --git a/src/spdx/jsonschema/optional_utils.py b/src/spdx/jsonschema/optional_utils.py index 14824ed9a..3d5d6746a 100644 --- a/src/spdx/jsonschema/optional_utils.py +++ b/src/spdx/jsonschema/optional_utils.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, TypeVar, Optional +from typing import Callable, Optional, TypeVar T = TypeVar("T") S = TypeVar("S") diff --git a/src/spdx/jsonschema/package_converter.py b/src/spdx/jsonschema/package_converter.py index c595e076f..da70b9720 100644 --- a/src/spdx/jsonschema/package_converter.py +++ b/src/spdx/jsonschema/package_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.datetime_conversions import datetime_to_iso_string from spdx.jsonschema.annotation_converter import AnnotationConverter @@ -22,8 +22,10 @@ from spdx.model.actor import Actor from spdx.model.document import Document from spdx.model.package import Package -from spdx.model.relationship_filters import find_package_contains_file_relationships, \ - find_file_contained_by_package_relationships +from spdx.model.relationship_filters import ( + find_file_contained_by_package_relationships, + find_package_contains_file_relationships, +) class PackageConverter(TypedConverter[Package]): @@ -43,14 +45,18 @@ def json_property_name(self, package_property: PackageProperty) -> str: return "SPDXID" return super().json_property_name(package_property) - def _get_property_value(self, package: Package, package_property: PackageProperty, - document: Document = None) -> Any: + def _get_property_value( + self, package: Package, package_property: PackageProperty, document: Document = None + ) -> Any: if package_property == PackageProperty.SPDX_ID: return package.spdx_id elif package_property == PackageProperty.ANNOTATIONS: - package_annotations = filter(lambda annotation: annotation.spdx_id == package.spdx_id, document.annotations) - return [self.annotation_converter.convert(annotation, document) for annotation in - package_annotations] or None + package_annotations = filter( + lambda annotation: annotation.spdx_id == package.spdx_id, document.annotations + ) + return [ + self.annotation_converter.convert(annotation, document) for annotation in package_annotations + ] or None elif package_property == PackageProperty.ATTRIBUTION_TEXTS: return package.attribution_texts or None elif package_property == PackageProperty.BUILT_DATE: @@ -66,15 +72,21 @@ def _get_property_value(self, package: Package, package_property: PackagePropert elif package_property == PackageProperty.DOWNLOAD_LOCATION: return str(package.download_location) elif package_property == PackageProperty.EXTERNAL_REFS: - return [self.external_package_ref_converter.convert(external_ref) for external_ref in - package.external_references] or None + return [ + self.external_package_ref_converter.convert(external_ref) + for external_ref in package.external_references + ] or None elif package_property == PackageProperty.FILES_ANALYZED: return package.files_analyzed elif package_property == PackageProperty.HAS_FILES: - package_contains_file_ids = [relationship.related_spdx_element_id for relationship in - find_package_contains_file_relationships(document, package)] - file_contained_in_package_ids = [relationship.spdx_element_id for relationship in - find_file_contained_by_package_relationships(document, package)] + package_contains_file_ids = [ + relationship.related_spdx_element_id + for relationship in find_package_contains_file_relationships(document, package) + ] + file_contained_in_package_ids = [ + relationship.spdx_element_id + for relationship in find_file_contained_by_package_relationships(document, package) + ] return package_contains_file_ids + file_contained_in_package_ids or None elif package_property == PackageProperty.HOMEPAGE: return apply_if_present(str, package.homepage) diff --git a/src/spdx/jsonschema/package_verification_code_converter.py b/src/spdx/jsonschema/package_verification_code_converter.py index a45bf1727..df72b9dcd 100644 --- a/src/spdx/jsonschema/package_verification_code_converter.py +++ b/src/spdx/jsonschema/package_verification_code_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.converter import TypedConverter from spdx.jsonschema.json_property import JsonProperty @@ -18,9 +18,12 @@ class PackageVerificationCodeConverter(TypedConverter[PackageVerificationCode]): - def _get_property_value(self, verification_code: PackageVerificationCode, - verification_code_property: PackageVerificationCodeProperty, - document: Document = None) -> Any: + def _get_property_value( + self, + verification_code: PackageVerificationCode, + verification_code_property: PackageVerificationCodeProperty, + document: Document = None, + ) -> Any: if verification_code_property == PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES: return verification_code.excluded_files or None elif verification_code_property == PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE: diff --git a/src/spdx/jsonschema/relationship_converter.py b/src/spdx/jsonschema/relationship_converter.py index f6d8d8d97..b2482f640 100644 --- a/src/spdx/jsonschema/relationship_converter.py +++ b/src/spdx/jsonschema/relationship_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any +from typing import Any, Type from spdx.jsonschema.converter import TypedConverter from spdx.jsonschema.json_property import JsonProperty @@ -18,8 +18,9 @@ class RelationshipConverter(TypedConverter[Relationship]): - def _get_property_value(self, relationship: Relationship, relationship_property: RelationshipProperty, - document: Document = None) -> Any: + def _get_property_value( + self, relationship: Relationship, relationship_property: RelationshipProperty, document: Document = None + ) -> Any: if relationship_property == RelationshipProperty.SPDX_ELEMENT_ID: return relationship.spdx_element_id elif relationship_property == RelationshipProperty.COMMENT: diff --git a/src/spdx/jsonschema/snippet_converter.py b/src/spdx/jsonschema/snippet_converter.py index 30e6ee9cf..d26e20ad5 100644 --- a/src/spdx/jsonschema/snippet_converter.py +++ b/src/spdx/jsonschema/snippet_converter.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Type, Any, Tuple, Dict +from typing import Any, Dict, Tuple, Type from spdx.jsonschema.annotation_converter import AnnotationConverter from spdx.jsonschema.converter import TypedConverter @@ -30,12 +30,15 @@ def json_property_name(self, snippet_property: SnippetProperty) -> str: return "SPDXID" return super().json_property_name(snippet_property) - def _get_property_value(self, snippet: Snippet, snippet_property: SnippetProperty, - document: Document = None) -> Any: + def _get_property_value( + self, snippet: Snippet, snippet_property: SnippetProperty, document: Document = None + ) -> Any: if snippet_property == SnippetProperty.SPDX_ID: return snippet.spdx_id elif snippet_property == SnippetProperty.ANNOTATIONS: - snippet_annotations = filter(lambda annotation: annotation.spdx_id == snippet.spdx_id, document.annotations) + snippet_annotations = filter( + lambda annotation: annotation.spdx_id == snippet.spdx_id, document.annotations + ) return [self.annotation_converter.convert(annotation) for annotation in snippet_annotations] or None elif snippet_property == SnippetProperty.ATTRIBUTION_TEXTS: return snippet.attribution_texts or None @@ -78,8 +81,10 @@ def convert_byte_range_to_dict(byte_range: Tuple[int, int], file_id: str) -> Dic def _convert_range_to_dict(int_range: Tuple[int, int], file_id: str, pointer_property: str) -> Dict: - return {"startPointer": _pointer(file_id, int_range[0], pointer_property), - "endPointer": _pointer(file_id, int_range[1], pointer_property)} + return { + "startPointer": _pointer(file_id, int_range[0], pointer_property), + "endPointer": _pointer(file_id, int_range[1], pointer_property), + } def _pointer(reference: str, target: int, pointer_property: str) -> Dict: diff --git a/src/spdx/model/annotation.py b/src/spdx/model/annotation.py index ad44204ad..2cfe0b212 100644 --- a/src/spdx/model/annotation.py +++ b/src/spdx/model/annotation.py @@ -11,9 +11,9 @@ from datetime import datetime from enum import Enum, auto -from spdx.model.actor import Actor from common.typing.dataclass_with_properties import dataclass_with_properties from common.typing.type_checks import check_types_and_set_values +from spdx.model.actor import Actor class AnnotationType(Enum): @@ -29,6 +29,12 @@ class Annotation: annotation_date: datetime annotation_comment: str - def __init__(self, spdx_id: str, annotation_type: AnnotationType, annotator: Actor, annotation_date: datetime, - annotation_comment: str): + def __init__( + self, + spdx_id: str, + annotation_type: AnnotationType, + annotator: Actor, + annotation_date: datetime, + annotation_comment: str, + ): check_types_and_set_values(self, locals()) diff --git a/src/spdx/model/checksum.py b/src/spdx/model/checksum.py index 94039b42e..4e9249615 100644 --- a/src/spdx/model/checksum.py +++ b/src/spdx/model/checksum.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from enum import auto, Enum +from enum import Enum, auto from common.typing.dataclass_with_properties import dataclass_with_properties from common.typing.type_checks import check_types_and_set_values diff --git a/src/spdx/model/document.py b/src/spdx/model/document.py index c5147ddcb..d727955ec 100644 --- a/src/spdx/model/document.py +++ b/src/spdx/model/document.py @@ -12,16 +12,16 @@ from datetime import datetime from typing import List, Optional +from common.typing.dataclass_with_properties import dataclass_with_properties +from common.typing.type_checks import check_types_and_set_values from spdx.model.actor import Actor from spdx.model.annotation import Annotation -from common.typing.dataclass_with_properties import dataclass_with_properties from spdx.model.external_document_ref import ExternalDocumentRef from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.model.file import File from spdx.model.package import Package from spdx.model.relationship import Relationship from spdx.model.snippet import Snippet -from common.typing.type_checks import check_types_and_set_values from spdx.model.version import Version @@ -39,10 +39,20 @@ class CreationInfo: license_list_version: Optional[Version] = None document_comment: Optional[str] = None - def __init__(self, spdx_version: str, spdx_id: str, name: str, document_namespace: str, creators: List[Actor], - created: datetime, creator_comment: Optional[str] = None, data_license: str = "CC0-1.0", - external_document_refs: List[ExternalDocumentRef] = None, - license_list_version: Optional[Version] = None, document_comment: Optional[str] = None): + def __init__( + self, + spdx_version: str, + spdx_id: str, + name: str, + document_namespace: str, + creators: List[Actor], + created: datetime, + creator_comment: Optional[str] = None, + data_license: str = "CC0-1.0", + external_document_refs: List[ExternalDocumentRef] = None, + license_list_version: Optional[Version] = None, + document_comment: Optional[str] = None, + ): external_document_refs = [] if external_document_refs is None else external_document_refs check_types_and_set_values(self, locals()) @@ -58,10 +68,16 @@ class Document: relationships: List[Relationship] = field(default_factory=list) extracted_licensing_info: List[ExtractedLicensingInfo] = field(default_factory=list) - def __init__(self, creation_info: CreationInfo, packages: List[Package] = None, files: List[File] = None, - snippets: List[Snippet] = None, annotations: List[Annotation] = None, - relationships: List[Relationship] = None, - extracted_licensing_info: List[ExtractedLicensingInfo] = None): + def __init__( + self, + creation_info: CreationInfo, + packages: List[Package] = None, + files: List[File] = None, + snippets: List[Snippet] = None, + annotations: List[Annotation] = None, + relationships: List[Relationship] = None, + extracted_licensing_info: List[ExtractedLicensingInfo] = None, + ): packages = [] if packages is None else packages files = [] if files is None else files snippets = [] if snippets is None else snippets diff --git a/src/spdx/model/external_document_ref.py b/src/spdx/model/external_document_ref.py index 2e33ec470..f99ad545f 100644 --- a/src/spdx/model/external_document_ref.py +++ b/src/spdx/model/external_document_ref.py @@ -9,9 +9,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from spdx.model.checksum import Checksum from common.typing.dataclass_with_properties import dataclass_with_properties from common.typing.type_checks import check_types_and_set_values +from spdx.model.checksum import Checksum @dataclass_with_properties diff --git a/src/spdx/model/extracted_licensing_info.py b/src/spdx/model/extracted_licensing_info.py index a6c9030e3..4d05a079f 100644 --- a/src/spdx/model/extracted_licensing_info.py +++ b/src/spdx/model/extracted_licensing_info.py @@ -9,11 +9,11 @@ # See the License for the specific language governing permissions and # limitations under the License. from dataclasses import field -from typing import Optional, List, Union +from typing import List, Optional, Union -from spdx.model.spdx_no_assertion import SpdxNoAssertion from common.typing.dataclass_with_properties import dataclass_with_properties from common.typing.type_checks import check_types_and_set_values +from spdx.model.spdx_no_assertion import SpdxNoAssertion @dataclass_with_properties @@ -24,8 +24,13 @@ class ExtractedLicensingInfo: cross_references: List[str] = field(default_factory=list) comment: Optional[str] = None - def __init__(self, license_id: Optional[str] = None, extracted_text: Optional[str] = None, - license_name: Optional[Union[str, SpdxNoAssertion]] = None, cross_references: List[str] = None, - comment: Optional[str] = None): + def __init__( + self, + license_id: Optional[str] = None, + extracted_text: Optional[str] = None, + license_name: Optional[Union[str, SpdxNoAssertion]] = None, + cross_references: List[str] = None, + comment: Optional[str] = None, + ): cross_references = [] if cross_references is None else cross_references check_types_and_set_values(self, locals()) diff --git a/src/spdx/model/file.py b/src/spdx/model/file.py index 50b3576d6..6205ff998 100644 --- a/src/spdx/model/file.py +++ b/src/spdx/model/file.py @@ -10,14 +10,15 @@ # limitations under the License. from dataclasses import field from enum import Enum, auto -from typing import Optional, List, Union +from typing import List, Optional, Union -from spdx.model.checksum import Checksum -from common.typing.dataclass_with_properties import dataclass_with_properties from license_expression import LicenseExpression + +from common.typing.dataclass_with_properties import dataclass_with_properties +from common.typing.type_checks import check_types_and_set_values +from spdx.model.checksum import Checksum from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from common.typing.type_checks import check_types_and_set_values class FileType(Enum): @@ -54,13 +55,21 @@ class File: # - artifact of (3 properties): replace by an external package reference and a GENERATED_FROM relationship # between the file and this package - def __init__(self, name: str, spdx_id: str, checksums: List[Checksum], file_types: List[FileType] = None, - license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_info_in_file: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_comment: Optional[str] = None, - copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, - comment: str = None, notice: Optional[str] = None, - contributors: List[str] = None, attribution_texts: List[str] = None): + def __init__( + self, + name: str, + spdx_id: str, + checksums: List[Checksum], + file_types: List[FileType] = None, + license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_info_in_file: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_comment: Optional[str] = None, + copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, + comment: str = None, + notice: Optional[str] = None, + contributors: List[str] = None, + attribution_texts: List[str] = None, + ): file_types = [] if file_types is None else file_types license_info_in_file = [] if license_info_in_file is None else license_info_in_file contributors = [] if contributors is None else contributors diff --git a/src/spdx/model/package.py b/src/spdx/model/package.py index f725718d0..2aa8731b4 100644 --- a/src/spdx/model/package.py +++ b/src/spdx/model/package.py @@ -11,15 +11,16 @@ from dataclasses import field from datetime import datetime from enum import Enum, auto -from typing import Optional, Union, List, Dict +from typing import Dict, List, Optional, Union +from license_expression import LicenseExpression + +from common.typing.dataclass_with_properties import dataclass_with_properties +from common.typing.type_checks import check_types_and_set_values from spdx.model.actor import Actor from spdx.model.checksum import Checksum -from common.typing.dataclass_with_properties import dataclass_with_properties -from license_expression import LicenseExpression from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from common.typing.type_checks import check_types_and_set_values class PackagePurpose(Enum): @@ -58,7 +59,7 @@ class ExternalPackageRefCategory(Enum): ExternalPackageRefCategory.SECURITY: ["cpe22Type", "cpe23Type", "advisory", "fix", "url", "swid"], ExternalPackageRefCategory.PACKAGE_MANAGER: ["maven-central", "npm", "nuget", "bower", "purl"], ExternalPackageRefCategory.PERSISTENT_ID: ["swh", "gitoid"], - ExternalPackageRefCategory.OTHER: [] + ExternalPackageRefCategory.OTHER: [], } @@ -72,8 +73,9 @@ class ExternalPackageRef: locator: str comment: Optional[str] = None - def __init__(self, category: ExternalPackageRefCategory, reference_type: str, locator: str, - comment: Optional[str] = None): + def __init__( + self, category: ExternalPackageRefCategory, reference_type: str, locator: str, comment: Optional[str] = None + ): check_types_and_set_values(self, locals()) @@ -106,22 +108,35 @@ class Package: built_date: Optional[datetime] = None valid_until_date: Optional[datetime] = None - def __init__(self, spdx_id: str, name: str, download_location: Union[str, SpdxNoAssertion, SpdxNone], - version: Optional[str] = None, file_name: Optional[str] = None, - supplier: Optional[Union[Actor, SpdxNoAssertion]] = None, - originator: Optional[Union[Actor, SpdxNoAssertion]] = None, - files_analyzed: bool = True, verification_code: Optional[PackageVerificationCode] = None, - checksums: List[Checksum] = None, homepage: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, - source_info: Optional[str] = None, - license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_info_from_files: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_comment: Optional[str] = None, - copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, - summary: Optional[str] = None, description: Optional[str] = None, comment: Optional[str] = None, - external_references: List[ExternalPackageRef] = None, attribution_texts: List[str] = None, - primary_package_purpose: Optional[PackagePurpose] = None, release_date: Optional[datetime] = None, - built_date: Optional[datetime] = None, valid_until_date: Optional[datetime] = None): + def __init__( + self, + spdx_id: str, + name: str, + download_location: Union[str, SpdxNoAssertion, SpdxNone], + version: Optional[str] = None, + file_name: Optional[str] = None, + supplier: Optional[Union[Actor, SpdxNoAssertion]] = None, + originator: Optional[Union[Actor, SpdxNoAssertion]] = None, + files_analyzed: bool = True, + verification_code: Optional[PackageVerificationCode] = None, + checksums: List[Checksum] = None, + homepage: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, + source_info: Optional[str] = None, + license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_info_from_files: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_comment: Optional[str] = None, + copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + comment: Optional[str] = None, + external_references: List[ExternalPackageRef] = None, + attribution_texts: List[str] = None, + primary_package_purpose: Optional[PackagePurpose] = None, + release_date: Optional[datetime] = None, + built_date: Optional[datetime] = None, + valid_until_date: Optional[datetime] = None, + ): checksums = [] if checksums is None else checksums license_info_from_files = [] if license_info_from_files is None else license_info_from_files external_references = [] if external_references is None else external_references diff --git a/src/spdx/model/relationship.py b/src/spdx/model/relationship.py index 25c9647be..19ecc2d8b 100644 --- a/src/spdx/model/relationship.py +++ b/src/spdx/model/relationship.py @@ -8,13 +8,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from enum import auto, Enum +from enum import Enum, auto from typing import Optional, Union -from spdx.model.spdx_no_assertion import SpdxNoAssertion -from spdx.model.spdx_none import SpdxNone from common.typing.dataclass_with_properties import dataclass_with_properties from common.typing.type_checks import check_types_and_set_values +from spdx.model.spdx_no_assertion import SpdxNoAssertion +from spdx.model.spdx_none import SpdxNone class RelationshipType(Enum): @@ -72,6 +72,11 @@ class Relationship: related_spdx_element_id: Union[str, SpdxNone, SpdxNoAssertion] comment: Optional[str] = None - def __init__(self, spdx_element_id: str, relationship_type: RelationshipType, - related_spdx_element_id: Union[str, SpdxNone, SpdxNoAssertion], comment: Optional[str] = None): + def __init__( + self, + spdx_element_id: str, + relationship_type: RelationshipType, + related_spdx_element_id: Union[str, SpdxNone, SpdxNoAssertion], + comment: Optional[str] = None, + ): check_types_and_set_values(self, locals()) diff --git a/src/spdx/model/relationship_filters.py b/src/spdx/model/relationship_filters.py index f981578e3..394a89479 100644 --- a/src/spdx/model/relationship_filters.py +++ b/src/spdx/model/relationship_filters.py @@ -17,27 +17,43 @@ def find_package_contains_file_relationships(document: Document, package: Package) -> List[Relationship]: file_ids_in_document = [file.spdx_id for file in document.files] - package_contains_relationships = filter_by_type_and_origin(document.relationships, RelationshipType.CONTAINS, - package.spdx_id) - return [relationship for relationship in package_contains_relationships if - relationship.related_spdx_element_id in file_ids_in_document] + package_contains_relationships = filter_by_type_and_origin( + document.relationships, RelationshipType.CONTAINS, package.spdx_id + ) + return [ + relationship + for relationship in package_contains_relationships + if relationship.related_spdx_element_id in file_ids_in_document + ] def find_file_contained_by_package_relationships(document: Document, package: Package) -> List[Relationship]: file_ids_in_document = [file.spdx_id for file in document.files] - contained_by_package_relationships = filter_by_type_and_target(document.relationships, - RelationshipType.CONTAINED_BY, package.spdx_id) - return [relationship for relationship in contained_by_package_relationships if - relationship.spdx_element_id in file_ids_in_document] - - -def filter_by_type_and_target(relationships: List[Relationship], relationship_type: RelationshipType, - target_id: str) -> List[Relationship]: - return [relationship for relationship in relationships if - relationship.relationship_type == relationship_type and relationship.related_spdx_element_id == target_id] - - -def filter_by_type_and_origin(relationships: List[Relationship], relationship_type: RelationshipType, - origin_id: str) -> List[Relationship]: - return [relationship for relationship in relationships if - relationship.relationship_type == relationship_type and relationship.spdx_element_id == origin_id] + contained_by_package_relationships = filter_by_type_and_target( + document.relationships, RelationshipType.CONTAINED_BY, package.spdx_id + ) + return [ + relationship + for relationship in contained_by_package_relationships + if relationship.spdx_element_id in file_ids_in_document + ] + + +def filter_by_type_and_target( + relationships: List[Relationship], relationship_type: RelationshipType, target_id: str +) -> List[Relationship]: + return [ + relationship + for relationship in relationships + if relationship.relationship_type == relationship_type and relationship.related_spdx_element_id == target_id + ] + + +def filter_by_type_and_origin( + relationships: List[Relationship], relationship_type: RelationshipType, origin_id: str +) -> List[Relationship]: + return [ + relationship + for relationship in relationships + if relationship.relationship_type == relationship_type and relationship.spdx_element_id == origin_id + ] diff --git a/src/spdx/model/snippet.py b/src/spdx/model/snippet.py index 1565dba0b..2b12a7fc9 100644 --- a/src/spdx/model/snippet.py +++ b/src/spdx/model/snippet.py @@ -9,13 +9,14 @@ # See the License for the specific language governing permissions and # limitations under the License. from dataclasses import field -from typing import Tuple, Optional, List, Union +from typing import List, Optional, Tuple, Union -from common.typing.dataclass_with_properties import dataclass_with_properties from license_expression import LicenseExpression + +from common.typing.dataclass_with_properties import dataclass_with_properties +from common.typing.type_checks import check_types_and_set_values from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from common.typing.type_checks import check_types_and_set_values @dataclass_with_properties @@ -32,12 +33,20 @@ class Snippet: name: Optional[str] = None attribution_texts: List[str] = field(default_factory=list) - def __init__(self, spdx_id: str, file_spdx_id: str, byte_range: Tuple[int, int], - line_range: Optional[Tuple[int, int]] = None, - license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_info_in_snippet: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, - license_comment: Optional[str] = None, copyright_text: Optional[str] = None, - comment: Optional[str] = None, name: Optional[str] = None, attribution_texts: List[str] = None): + def __init__( + self, + spdx_id: str, + file_spdx_id: str, + byte_range: Tuple[int, int], + line_range: Optional[Tuple[int, int]] = None, + license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_info_in_snippet: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None, + license_comment: Optional[str] = None, + copyright_text: Optional[str] = None, + comment: Optional[str] = None, + name: Optional[str] = None, + attribution_texts: List[str] = None, + ): attribution_texts = [] if attribution_texts is None else attribution_texts license_info_in_snippet = [] if license_info_in_snippet is None else license_info_in_snippet check_types_and_set_values(self, locals()) diff --git a/src/spdx/parser/actor_parser.py b/src/spdx/parser/actor_parser.py index 7d6406eba..3ac5ddb9e 100644 --- a/src/spdx/parser/actor_parser.py +++ b/src/spdx/parser/actor_parser.py @@ -9,7 +9,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import re -from typing import Pattern, Match, Optional +from typing import Match, Optional, Pattern from spdx.model.actor import Actor, ActorType from spdx.parser.error import SPDXParsingError @@ -17,7 +17,6 @@ class ActorParser: - @staticmethod def parse_actor(actor: str) -> Actor: tool_re: Pattern = re.compile(r"^Tool:\s*(.+)", re.UNICODE) @@ -38,14 +37,17 @@ def parse_actor(actor: str) -> Actor: if not name: raise SPDXParsingError([f"No name for Person provided: {actor}."]) email: Optional[str] = ActorParser.get_email_or_none(person_match) - creator = construct_or_raise_parsing_error(Actor, dict(actor_type=ActorType.PERSON, name=name, email=email)) + creator = construct_or_raise_parsing_error( + Actor, dict(actor_type=ActorType.PERSON, name=name, email=email) + ) elif org_match: name: str = org_match.group(1).strip() if not name: raise SPDXParsingError([f"No name for Organization provided: {actor}."]) email: Optional[str] = ActorParser.get_email_or_none(org_match) - creator = construct_or_raise_parsing_error(Actor, - dict(actor_type=ActorType.ORGANIZATION, name=name, email=email)) + creator = construct_or_raise_parsing_error( + Actor, dict(actor_type=ActorType.ORGANIZATION, name=name, email=email) + ) else: raise SPDXParsingError([f"Actor {actor} doesn't match any of person, organization or tool."]) diff --git a/src/spdx/parser/jsonlikedict/annotation_parser.py b/src/spdx/parser/jsonlikedict/annotation_parser.py index f81da9ea4..72338179a 100644 --- a/src/spdx/parser/jsonlikedict/annotation_parser.py +++ b/src/spdx/parser/jsonlikedict/annotation_parser.py @@ -9,16 +9,16 @@ # See the License for the specific language governing permissions and # limitations under the License. from datetime import datetime -from typing import Dict, Optional, List +from typing import Dict, List, Optional +from spdx.datetime_conversions import datetime_from_str from spdx.model.actor import Actor from spdx.model.annotation import Annotation, AnnotationType -from spdx.parser.error import SPDXParsingError from spdx.parser.actor_parser import ActorParser -from spdx.parser.jsonlikedict.dict_parsing_functions import parse_field_or_log_error, append_parsed_field_or_log_error -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages -from spdx.datetime_conversions import datetime_from_str +from spdx.parser.error import SPDXParsingError +from spdx.parser.jsonlikedict.dict_parsing_functions import append_parsed_field_or_log_error, parse_field_or_log_error from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class AnnotationParser: @@ -35,7 +35,8 @@ def parse_all_annotations(self, input_doc_dict: Dict) -> List[Annotation]: reviews: List[Dict] = input_doc_dict.get("revieweds", []) for review in reviews: annotations = append_parsed_field_or_log_error( - self.logger, annotations, review, lambda x: self.parse_review(x, spdx_id=input_doc_dict.get("SPDXID"))) + self.logger, annotations, review, lambda x: self.parse_review(x, spdx_id=input_doc_dict.get("SPDXID")) + ) packages: List[Dict] = input_doc_dict.get("packages", []) self.parse_annotations_from_object(annotations, packages) files: List[Dict] = input_doc_dict.get("files", []) @@ -50,31 +51,44 @@ def parse_annotations_from_object(self, annotations: List[Annotation], element_l for element in element_list: element_spdx_id: Optional[str] = element.get("SPDXID") element_annotations: List[Dict] = element.get("annotations", []) - annotations.extend(parse_field_or_log_error(self.logger, element_annotations, - - lambda y: self.parse_annotation(y, spdx_id=element_spdx_id), - [], True)) + annotations.extend( + parse_field_or_log_error( + self.logger, + element_annotations, + lambda y: self.parse_annotation(y, spdx_id=element_spdx_id), + [], + True, + ) + ) def parse_annotation(self, annotation_dict: Dict, spdx_id: Optional[str] = None) -> Annotation: logger = Logger() spdx_id: Optional[str] = annotation_dict.get("SPDXID") or spdx_id - annotation_type: Optional[AnnotationType] = parse_field_or_log_error(logger, - annotation_dict.get("annotationType"), - self.parse_annotation_type) + annotation_type: Optional[AnnotationType] = parse_field_or_log_error( + logger, annotation_dict.get("annotationType"), self.parse_annotation_type + ) - annotator: Optional[Actor] = parse_field_or_log_error(logger, annotation_dict.get("annotator"), - self.actor_parser.parse_actor) + annotator: Optional[Actor] = parse_field_or_log_error( + logger, annotation_dict.get("annotator"), self.actor_parser.parse_actor + ) - annotation_date: Optional[datetime] = parse_field_or_log_error(logger, annotation_dict.get("annotationDate"), - datetime_from_str) + annotation_date: Optional[datetime] = parse_field_or_log_error( + logger, annotation_dict.get("annotationDate"), datetime_from_str + ) annotation_comment: Optional[str] = annotation_dict.get("comment") raise_parsing_error_if_logger_has_messages(logger, "Annotation") - annotation_dict = construct_or_raise_parsing_error(Annotation, - dict(spdx_id=spdx_id, annotation_type=annotation_type, - annotator=annotator, annotation_date=annotation_date, - annotation_comment=annotation_comment)) + annotation_dict = construct_or_raise_parsing_error( + Annotation, + dict( + spdx_id=spdx_id, + annotation_type=annotation_type, + annotator=annotator, + annotation_date=annotation_date, + annotation_comment=annotation_comment, + ), + ) return annotation_dict @@ -87,18 +101,26 @@ def parse_annotation_type(annotation_type: str) -> AnnotationType: def parse_review(self, review_dict: Dict, spdx_id: str) -> Annotation: logger = Logger() - annotator: Optional[Actor] = parse_field_or_log_error(logger, review_dict.get("reviewer"), - self.actor_parser.parse_actor) + annotator: Optional[Actor] = parse_field_or_log_error( + logger, review_dict.get("reviewer"), self.actor_parser.parse_actor + ) - annotation_date: Optional[datetime] = parse_field_or_log_error(logger, review_dict.get("reviewDate"), - datetime_from_str) + annotation_date: Optional[datetime] = parse_field_or_log_error( + logger, review_dict.get("reviewDate"), datetime_from_str + ) annotation_type = AnnotationType.REVIEW comment: Optional[str] = review_dict.get("comment") raise_parsing_error_if_logger_has_messages(logger, "Annotation from revieweds") - annotation = construct_or_raise_parsing_error(Annotation, - dict(spdx_id=spdx_id, annotation_type=annotation_type, - annotator=annotator, annotation_date=annotation_date, - annotation_comment=comment)) + annotation = construct_or_raise_parsing_error( + Annotation, + dict( + spdx_id=spdx_id, + annotation_type=annotation_type, + annotator=annotator, + annotation_date=annotation_date, + annotation_comment=comment, + ), + ) return annotation diff --git a/src/spdx/parser/jsonlikedict/checksum_parser.py b/src/spdx/parser/jsonlikedict/checksum_parser.py index 5bdb574a5..de09fc4ed 100644 --- a/src/spdx/parser/jsonlikedict/checksum_parser.py +++ b/src/spdx/parser/jsonlikedict/checksum_parser.py @@ -12,8 +12,8 @@ from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.parser.jsonlikedict.dict_parsing_functions import json_str_to_enum_name -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class ChecksumParser: diff --git a/src/spdx/parser/jsonlikedict/creation_info_parser.py b/src/spdx/parser/jsonlikedict/creation_info_parser.py index 992ae8106..835aa6702 100644 --- a/src/spdx/parser/jsonlikedict/creation_info_parser.py +++ b/src/spdx/parser/jsonlikedict/creation_info_parser.py @@ -9,22 +9,24 @@ # See the License for the specific language governing permissions and # limitations under the License. from datetime import datetime -from typing import Dict, Optional, List +from typing import Dict, List, Optional +from spdx.datetime_conversions import datetime_from_str from spdx.model.actor import Actor from spdx.model.checksum import Checksum from spdx.model.document import CreationInfo from spdx.model.external_document_ref import ExternalDocumentRef from spdx.model.version import Version -from spdx.parser.error import SPDXParsingError from spdx.parser.actor_parser import ActorParser +from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.checksum_parser import ChecksumParser -from spdx.parser.jsonlikedict.dict_parsing_functions import append_parsed_field_or_log_error, \ - parse_field_or_log_error, \ - parse_field_or_no_assertion -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages -from spdx.datetime_conversions import datetime_from_str +from spdx.parser.jsonlikedict.dict_parsing_functions import ( + append_parsed_field_or_log_error, + parse_field_or_log_error, + parse_field_or_no_assertion, +) from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class CreationInfoParser: @@ -50,32 +52,42 @@ def parse_creation_info(self, doc_dict: Dict) -> CreationInfo: logger.append("CreationInfo does not exist.") raise SPDXParsingError([f"Error while parsing document {name}: {logger.get_messages()}"]) - creators: List[Actor] = parse_field_or_log_error(logger, creation_info_dict.get("creators"), - self.parse_creators) + creators: List[Actor] = parse_field_or_log_error( + logger, creation_info_dict.get("creators"), self.parse_creators + ) - created: Optional[datetime] = parse_field_or_log_error(logger, creation_info_dict.get("created"), - datetime_from_str) + created: Optional[datetime] = parse_field_or_log_error( + logger, creation_info_dict.get("created"), datetime_from_str + ) creator_comment: Optional[str] = creation_info_dict.get("comment") data_license: Optional[str] = doc_dict.get("dataLicense") - external_document_refs: List[ExternalDocumentRef] = parse_field_or_log_error(logger, doc_dict.get( - "externalDocumentRefs"), self.parse_external_document_refs) - license_list_version: Optional[Version] = parse_field_or_log_error(logger, - creation_info_dict.get("licenseListVersion"), - self.parse_version) + external_document_refs: List[ExternalDocumentRef] = parse_field_or_log_error( + logger, doc_dict.get("externalDocumentRefs"), self.parse_external_document_refs + ) + license_list_version: Optional[Version] = parse_field_or_log_error( + logger, creation_info_dict.get("licenseListVersion"), self.parse_version + ) document_comment: Optional[str] = doc_dict.get("comment") raise_parsing_error_if_logger_has_messages(logger, "Document") - creation_info = construct_or_raise_parsing_error(CreationInfo, - dict(spdx_version=spdx_version, spdx_id=spdx_id, name=name, - document_namespace=document_namespace, - creators=creators, created=created, - license_list_version=license_list_version, - document_comment=document_comment, - creator_comment=creator_comment, - data_license=data_license, - external_document_refs=external_document_refs)) + creation_info = construct_or_raise_parsing_error( + CreationInfo, + dict( + spdx_version=spdx_version, + spdx_id=spdx_id, + name=name, + document_namespace=document_namespace, + creators=creators, + created=created, + license_list_version=license_list_version, + document_comment=document_comment, + creator_comment=creator_comment, + data_license=data_license, + external_document_refs=external_document_refs, + ), + ) return creation_info @@ -83,7 +95,9 @@ def parse_creators(self, creators_list_from_dict: List[str]) -> List[Actor]: logger = Logger() creators = [] for creator_str in creators_list_from_dict: - creators = append_parsed_field_or_log_error(logger, creators, creator_str, lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor)) + creators = append_parsed_field_or_log_error( + logger, creators, creator_str, lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor) + ) raise_parsing_error_if_logger_has_messages(logger) return creators @@ -99,8 +113,9 @@ def parse_external_document_refs(self, external_document_ref_dicts: List[Dict]) logger = Logger() external_document_refs = [] for external_document_ref_dict in external_document_ref_dicts: - external_document_ref: ExternalDocumentRef = parse_field_or_log_error(logger, external_document_ref_dict, - self.parse_external_document_ref) + external_document_ref: ExternalDocumentRef = parse_field_or_log_error( + logger, external_document_ref_dict, self.parse_external_document_ref + ) external_document_refs.append(external_document_ref) @@ -109,16 +124,16 @@ def parse_external_document_refs(self, external_document_ref_dicts: List[Dict]) def parse_external_document_ref(self, external_document_ref_dict: Dict) -> ExternalDocumentRef: logger = Logger() - checksum: Optional[Checksum] = parse_field_or_log_error(logger, external_document_ref_dict.get("checksum"), - self.checksum_parser.parse_checksum) + checksum: Optional[Checksum] = parse_field_or_log_error( + logger, external_document_ref_dict.get("checksum"), self.checksum_parser.parse_checksum + ) external_document_id: Optional[str] = external_document_ref_dict.get("externalDocumentId") document_uri: Optional[str] = external_document_ref_dict.get("spdxDocument") raise_parsing_error_if_logger_has_messages(logger, "ExternalDocumentRef") - external_document_ref: ExternalDocumentRef = construct_or_raise_parsing_error(ExternalDocumentRef, - dict( - document_ref_id=external_document_id, - checksum=checksum, - document_uri=document_uri)) + external_document_ref: ExternalDocumentRef = construct_or_raise_parsing_error( + ExternalDocumentRef, + dict(document_ref_id=external_document_id, checksum=checksum, document_uri=document_uri), + ) return external_document_ref diff --git a/src/spdx/parser/jsonlikedict/dict_parsing_functions.py b/src/spdx/parser/jsonlikedict/dict_parsing_functions.py index 3986cbfc0..4e791f6b4 100644 --- a/src/spdx/parser/jsonlikedict/dict_parsing_functions.py +++ b/src/spdx/parser/jsonlikedict/dict_parsing_functions.py @@ -23,8 +23,13 @@ def json_str_to_enum_name(json_str: str) -> str: return json_str.replace("-", "_").upper() -def parse_field_or_log_error(logger: Logger, field: Any, parsing_method: Callable = lambda x: x, default: Any = None, - field_is_list: bool = False) -> Any: +def parse_field_or_log_error( + logger: Logger, + field: Any, + parsing_method: Callable = lambda x: x, + default: Any = None, + field_is_list: bool = False, +) -> Any: if not field: return default try: @@ -39,8 +44,9 @@ def parse_field_or_log_error(logger: Logger, field: Any, parsing_method: Callabl return default -def append_parsed_field_or_log_error(logger: Logger, list_to_append_to: List[Any], field: Any, - method_to_parse: Callable) -> List[Any]: +def append_parsed_field_or_log_error( + logger: Logger, list_to_append_to: List[Any], field: Any, method_to_parse: Callable +) -> List[Any]: try: parsed_element = method_to_parse(field) list_to_append_to.append(parsed_element) @@ -72,8 +78,9 @@ def parse_list_of_elements(list_of_elements: List[Dict], method_to_parse_element logger = Logger() parsed_elements = [] for element_dict in list_of_elements: - parsed_elements = append_parsed_field_or_log_error(logger, parsed_elements, element_dict, - method_to_parse_element) + parsed_elements = append_parsed_field_or_log_error( + logger, parsed_elements, element_dict, method_to_parse_element + ) raise_parsing_error_if_logger_has_messages(logger) return parsed_elements diff --git a/src/spdx/parser/jsonlikedict/extracted_licensing_info_parser.py b/src/spdx/parser/jsonlikedict/extracted_licensing_info_parser.py index f1bad9657..65ec7495f 100644 --- a/src/spdx/parser/jsonlikedict/extracted_licensing_info_parser.py +++ b/src/spdx/parser/jsonlikedict/extracted_licensing_info_parser.py @@ -13,8 +13,8 @@ from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.jsonlikedict.dict_parsing_functions import parse_field_or_no_assertion -from spdx.parser.parsing_functions import construct_or_raise_parsing_error from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error class ExtractedLicensingInfoParser: @@ -28,13 +28,18 @@ def parse_extracted_licensing_info(extracted_licensing_info_dict: Dict) -> Extra license_id: Optional[str] = extracted_licensing_info_dict.get("licenseId") extracted_text: Optional[str] = extracted_licensing_info_dict.get("extractedText") license_name: Optional[Union[str, SpdxNoAssertion]] = parse_field_or_no_assertion( - extracted_licensing_info_dict.get("name")) + extracted_licensing_info_dict.get("name") + ) cross_references: List[str] = extracted_licensing_info_dict.get("seeAlsos", []) comment: Optional[str] = extracted_licensing_info_dict.get("comment") - extracted_licensing_info = construct_or_raise_parsing_error(ExtractedLicensingInfo, - dict(license_id=license_id, - extracted_text=extracted_text, - comment=comment, - license_name=license_name, - cross_references=cross_references)) + extracted_licensing_info = construct_or_raise_parsing_error( + ExtractedLicensingInfo, + dict( + license_id=license_id, + extracted_text=extracted_text, + comment=comment, + license_name=license_name, + cross_references=cross_references, + ), + ) return extracted_licensing_info diff --git a/src/spdx/parser/jsonlikedict/file_parser.py b/src/spdx/parser/jsonlikedict/file_parser.py index e89d9844b..501ba4b76 100644 --- a/src/spdx/parser/jsonlikedict/file_parser.py +++ b/src/spdx/parser/jsonlikedict/file_parser.py @@ -10,16 +10,17 @@ # limitations under the License. from typing import Dict, List, Optional, Union +from license_expression import LicenseExpression + from spdx.model.checksum import Checksum from spdx.model.file import File, FileType -from license_expression import LicenseExpression from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.parser.jsonlikedict.checksum_parser import ChecksumParser from spdx.parser.jsonlikedict.dict_parsing_functions import parse_field_or_log_error -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.jsonlikedict.license_expression_parser import LicenseExpressionParser from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class FileParser: @@ -37,35 +38,50 @@ def parse_file(self, file_dict: Dict) -> Optional[File]: name: Optional[str] = file_dict.get("fileName") spdx_id: Optional[str] = file_dict.get("SPDXID") checksums_list: List[Dict] = file_dict.get("checksums") - checksums: List[Checksum] = parse_field_or_log_error(logger, checksums_list, - self.checksum_parser.parse_checksum, field_is_list=True) + checksums: List[Checksum] = parse_field_or_log_error( + logger, checksums_list, self.checksum_parser.parse_checksum, field_is_list=True + ) attribution_texts: List[str] = file_dict.get("attributionTexts", []) comment: Optional[str] = file_dict.get("comment") copyright_text: Optional[str] = file_dict.get("copyrightText") file_contributors: List[str] = file_dict.get("fileContributors", []) - file_types: List[FileType] = parse_field_or_log_error(logger, file_dict.get("fileTypes"), self.parse_file_types) + file_types: List[FileType] = parse_field_or_log_error( + logger, file_dict.get("fileTypes"), self.parse_file_types + ) license_comments: Optional[str] = file_dict.get("licenseComments") license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_field_or_log_error( - logger, file_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression) + logger, file_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression + ) license_info_in_files: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_field_or_log_error( - logger, file_dict.get("licenseInfoInFiles"), self.license_expression_parser.parse_license_expression, - field_is_list=True) + logger, + file_dict.get("licenseInfoInFiles"), + self.license_expression_parser.parse_license_expression, + field_is_list=True, + ) notice_text: Optional[str] = file_dict.get("noticeText") raise_parsing_error_if_logger_has_messages(logger, "File") - file = construct_or_raise_parsing_error(File, dict(name=name, spdx_id=spdx_id, checksums=checksums, - attribution_texts=attribution_texts, comment=comment, - copyright_text=copyright_text, file_types=file_types, - contributors=file_contributors, - license_comment=license_comments, - license_concluded=license_concluded, - license_info_in_file=license_info_in_files, - notice=notice_text) - ) + file = construct_or_raise_parsing_error( + File, + dict( + name=name, + spdx_id=spdx_id, + checksums=checksums, + attribution_texts=attribution_texts, + comment=comment, + copyright_text=copyright_text, + file_types=file_types, + contributors=file_contributors, + license_comment=license_comments, + license_concluded=license_concluded, + license_info_in_file=license_info_in_files, + notice=notice_text, + ), + ) return file @staticmethod diff --git a/src/spdx/parser/jsonlikedict/json_like_dict_parser.py b/src/spdx/parser/jsonlikedict/json_like_dict_parser.py index a4ecf49a7..148cd4dd2 100644 --- a/src/spdx/parser/jsonlikedict/json_like_dict_parser.py +++ b/src/spdx/parser/jsonlikedict/json_like_dict_parser.py @@ -15,13 +15,13 @@ from spdx.parser.jsonlikedict.annotation_parser import AnnotationParser from spdx.parser.jsonlikedict.creation_info_parser import CreationInfoParser from spdx.parser.jsonlikedict.dict_parsing_functions import parse_list_of_elements -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.jsonlikedict.extracted_licensing_info_parser import ExtractedLicensingInfoParser from spdx.parser.jsonlikedict.file_parser import FileParser -from spdx.parser.logger import Logger from spdx.parser.jsonlikedict.package_parser import PackageParser from spdx.parser.jsonlikedict.relationship_parser import RelationshipParser from spdx.parser.jsonlikedict.snippet_parser import SnippetParser +from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class JsonLikeDictParser: @@ -45,23 +45,39 @@ def __init__(self): self.annotation_parser = AnnotationParser() def parse(self, json_like_dict: Dict) -> Document: - - fields_to_parse = [("creation_info", json_like_dict, self.creation_info_parser.parse_creation_info, False), - ("packages", json_like_dict.get("packages"), lambda x: parse_list_of_elements(x, - self.package_parser.parse_package, - self.package_parser.logger), True), - ("files", json_like_dict.get("files"), lambda x: parse_list_of_elements(x, - self.file_parser.parse_file, - self.file_parser.logger), True), - ("annotations", json_like_dict, self.annotation_parser.parse_all_annotations, True), - ("snippets", json_like_dict.get("snippets"), lambda x: parse_list_of_elements(x, - self.snippet_parser.parse_snippet, - self.snippet_parser.logger), True), - ("relationships", json_like_dict, self.relationship_parser.parse_all_relationships, True), - ("extracted_licensing_info", json_like_dict.get("hasExtractedLicensingInfos"), - lambda x: parse_list_of_elements(x, - self.extracted_licensing_info_parser.parse_extracted_licensing_info, - self.extracted_licensing_info_parser.logger), True)] + fields_to_parse = [ + ("creation_info", json_like_dict, self.creation_info_parser.parse_creation_info, False), + ( + "packages", + json_like_dict.get("packages"), + lambda x: parse_list_of_elements(x, self.package_parser.parse_package, self.package_parser.logger), + True, + ), + ( + "files", + json_like_dict.get("files"), + lambda x: parse_list_of_elements(x, self.file_parser.parse_file, self.file_parser.logger), + True, + ), + ("annotations", json_like_dict, self.annotation_parser.parse_all_annotations, True), + ( + "snippets", + json_like_dict.get("snippets"), + lambda x: parse_list_of_elements(x, self.snippet_parser.parse_snippet, self.snippet_parser.logger), + True, + ), + ("relationships", json_like_dict, self.relationship_parser.parse_all_relationships, True), + ( + "extracted_licensing_info", + json_like_dict.get("hasExtractedLicensingInfos"), + lambda x: parse_list_of_elements( + x, + self.extracted_licensing_info_parser.parse_extracted_licensing_info, + self.extracted_licensing_info_parser.logger, + ), + True, + ), + ] parsed_fields = {} diff --git a/src/spdx/parser/jsonlikedict/license_expression_parser.py b/src/spdx/parser/jsonlikedict/license_expression_parser.py index a2e1912a8..74ce63034 100644 --- a/src/spdx/parser/jsonlikedict/license_expression_parser.py +++ b/src/spdx/parser/jsonlikedict/license_expression_parser.py @@ -8,16 +8,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union, List +from typing import Union -from license_expression import LicenseExpression, Licensing, ExpressionError +from license_expression import ExpressionError, LicenseExpression, Licensing from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.parser.error import SPDXParsingError -from spdx.parser.jsonlikedict.dict_parsing_functions import append_parsed_field_or_log_error -from spdx.parser.parsing_functions import raise_parsing_error_if_logger_has_messages -from spdx.parser.logger import Logger class LicenseExpressionParser: diff --git a/src/spdx/parser/jsonlikedict/package_parser.py b/src/spdx/parser/jsonlikedict/package_parser.py index 50049092d..9ed80c0ee 100644 --- a/src/spdx/parser/jsonlikedict/package_parser.py +++ b/src/spdx/parser/jsonlikedict/package_parser.py @@ -11,21 +11,32 @@ from datetime import datetime from typing import Dict, List, Optional, Union -from spdx.model.actor import Actor from license_expression import LicenseExpression -from spdx.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \ - ExternalPackageRefCategory + +from spdx.datetime_conversions import datetime_from_str +from spdx.model.actor import Actor +from spdx.model.package import ( + ExternalPackageRef, + ExternalPackageRefCategory, + Package, + PackagePurpose, + PackageVerificationCode, +) from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from spdx.parser.error import SPDXParsingError from spdx.parser.actor_parser import ActorParser +from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.checksum_parser import ChecksumParser -from spdx.parser.jsonlikedict.dict_parsing_functions import append_parsed_field_or_log_error, \ - json_str_to_enum_name, parse_field_or_log_error, parse_field_or_no_assertion_or_none, parse_field_or_no_assertion -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages -from spdx.datetime_conversions import datetime_from_str +from spdx.parser.jsonlikedict.dict_parsing_functions import ( + append_parsed_field_or_log_error, + json_str_to_enum_name, + parse_field_or_log_error, + parse_field_or_no_assertion, + parse_field_or_no_assertion_or_none, +) from spdx.parser.jsonlikedict.license_expression_parser import LicenseExpressionParser from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class PackageParser: @@ -46,19 +57,23 @@ def parse_package(self, package_dict: Dict) -> Package: spdx_id: Optional[str] = package_dict.get("SPDXID") attribution_texts: List[str] = package_dict.get("attributionTexts", []) - built_date: Optional[datetime] = parse_field_or_log_error(logger, package_dict.get("builtDate"), - datetime_from_str) + built_date: Optional[datetime] = parse_field_or_log_error( + logger, package_dict.get("builtDate"), datetime_from_str + ) - checksums = parse_field_or_log_error(logger, package_dict.get("checksums"), self.checksum_parser.parse_checksum, - field_is_list=True) + checksums = parse_field_or_log_error( + logger, package_dict.get("checksums"), self.checksum_parser.parse_checksum, field_is_list=True + ) comment: Optional[str] = package_dict.get("comment") copyright_text: Optional[str] = package_dict.get("copyrightText") description: Optional[str] = package_dict.get("description") download_location: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = parse_field_or_no_assertion_or_none( - package_dict.get("downloadLocation")) + package_dict.get("downloadLocation") + ) - external_refs: List[ExternalPackageRef] = parse_field_or_log_error(logger, package_dict.get("externalRefs"), - self.parse_external_refs) + external_refs: List[ExternalPackageRef] = parse_field_or_log_error( + logger, package_dict.get("externalRefs"), self.parse_external_refs + ) files_analyzed: Optional[Union[bool, str]] = package_dict.get("filesAnalyzed") @@ -73,85 +88,112 @@ def parse_package(self, package_dict: Dict) -> Package: homepage: Optional[str] = package_dict.get("homepage") license_comments: Optional[str] = package_dict.get("licenseComments") license_concluded = parse_field_or_log_error( - logger, package_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression) + logger, package_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression + ) license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_field_or_log_error( - logger, package_dict.get("licenseDeclared"), self.license_expression_parser.parse_license_expression) + logger, package_dict.get("licenseDeclared"), self.license_expression_parser.parse_license_expression + ) license_info_from_file: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_field_or_log_error( - logger, package_dict.get("licenseInfoFromFiles"), self.license_expression_parser.parse_license_expression, - field_is_list=True) + logger, + package_dict.get("licenseInfoFromFiles"), + self.license_expression_parser.parse_license_expression, + field_is_list=True, + ) originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_field_or_log_error( - logger, package_dict.get("originator"), - lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor)) + logger, + package_dict.get("originator"), + lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor), + ) package_file_name: Optional[str] = package_dict.get("packageFileName") - package_verification_code: Optional[ - PackageVerificationCode] = parse_field_or_log_error(logger, package_dict.get("packageVerificationCode"), - self.parse_package_verification_code) - primary_package_purpose: Optional[PackagePurpose] = parse_field_or_log_error(logger, package_dict.get( - "primaryPackagePurpose"), self.parse_primary_package_purpose) + package_verification_code: Optional[PackageVerificationCode] = parse_field_or_log_error( + logger, package_dict.get("packageVerificationCode"), self.parse_package_verification_code + ) + primary_package_purpose: Optional[PackagePurpose] = parse_field_or_log_error( + logger, package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose + ) - release_date: Optional[datetime] = parse_field_or_log_error(logger, package_dict.get("releaseDate"), - datetime_from_str) + release_date: Optional[datetime] = parse_field_or_log_error( + logger, package_dict.get("releaseDate"), datetime_from_str + ) source_info: Optional[str] = package_dict.get("sourceInfo") summary: Optional[str] = package_dict.get("summary") supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_field_or_log_error( - logger, package_dict.get("supplier"), - lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor)) - valid_until_date: Optional[datetime] = parse_field_or_log_error(logger, package_dict.get("validUntilDate"), - datetime_from_str) + logger, + package_dict.get("supplier"), + lambda x: parse_field_or_no_assertion(x, self.actor_parser.parse_actor), + ) + valid_until_date: Optional[datetime] = parse_field_or_log_error( + logger, package_dict.get("validUntilDate"), datetime_from_str + ) version_info: Optional[str] = package_dict.get("versionInfo") raise_parsing_error_if_logger_has_messages(logger, "Package") - package = construct_or_raise_parsing_error(Package, - dict(spdx_id=spdx_id, name=name, download_location=download_location, - version=version_info, file_name=package_file_name, - supplier=supplier, originator=originator, - files_analyzed=files_analyzed, - verification_code=package_verification_code, - checksums=checksums, homepage=homepage, source_info=source_info, - license_concluded=license_concluded, - license_info_from_files=license_info_from_file, - license_declared=license_declared, - license_comment=license_comments, - copyright_text=copyright_text, summary=summary, - description=description, comment=comment, - external_references=external_refs, - attribution_texts=attribution_texts, - primary_package_purpose=primary_package_purpose, - release_date=release_date, built_date=built_date, - valid_until_date=valid_until_date)) + package = construct_or_raise_parsing_error( + Package, + dict( + spdx_id=spdx_id, + name=name, + download_location=download_location, + version=version_info, + file_name=package_file_name, + supplier=supplier, + originator=originator, + files_analyzed=files_analyzed, + verification_code=package_verification_code, + checksums=checksums, + homepage=homepage, + source_info=source_info, + license_concluded=license_concluded, + license_info_from_files=license_info_from_file, + license_declared=license_declared, + license_comment=license_comments, + copyright_text=copyright_text, + summary=summary, + description=description, + comment=comment, + external_references=external_refs, + attribution_texts=attribution_texts, + primary_package_purpose=primary_package_purpose, + release_date=release_date, + built_date=built_date, + valid_until_date=valid_until_date, + ), + ) return package def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]: external_refs = [] for external_ref_dict in external_ref_dicts: - external_refs = append_parsed_field_or_log_error(self.logger, external_refs, external_ref_dict, - self.parse_external_ref) + external_refs = append_parsed_field_or_log_error( + self.logger, external_refs, external_ref_dict, self.parse_external_ref + ) return external_refs def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef: logger = Logger() - ref_category = parse_field_or_log_error(logger, external_ref_dict.get("referenceCategory"), - self.parse_external_ref_category) + ref_category = parse_field_or_log_error( + logger, external_ref_dict.get("referenceCategory"), self.parse_external_ref_category + ) ref_locator: Optional[str] = external_ref_dict.get("referenceLocator") ref_type: Optional[str] = external_ref_dict.get("referenceType") comment: Optional[str] = external_ref_dict.get("comment") raise_parsing_error_if_logger_has_messages(logger, "ExternalPackageRef") - external_ref = construct_or_raise_parsing_error(ExternalPackageRef, - dict(category=ref_category, reference_type=ref_type, - locator=ref_locator, comment=comment)) + external_ref = construct_or_raise_parsing_error( + ExternalPackageRef, + dict(category=ref_category, reference_type=ref_type, locator=ref_locator, comment=comment), + ) return external_ref @staticmethod def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory: try: - external_ref_category = ExternalPackageRefCategory[ - json_str_to_enum_name(external_ref_category_str)] + external_ref_category = ExternalPackageRefCategory[json_str_to_enum_name(external_ref_category_str)] except KeyError: raise SPDXParsingError([f"Invalid ExternalPackageRefCategory: {external_ref_category_str}"]) @@ -162,9 +204,9 @@ def parse_package_verification_code(verification_code_dict: Dict) -> PackageVeri excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles", []) verification_code_value: Optional[str] = verification_code_dict.get("packageVerificationCodeValue") - package_verification_code = construct_or_raise_parsing_error(PackageVerificationCode, - dict(value=verification_code_value, - excluded_files=excluded_files)) + package_verification_code = construct_or_raise_parsing_error( + PackageVerificationCode, dict(value=verification_code_value, excluded_files=excluded_files) + ) return package_verification_code diff --git a/src/spdx/parser/jsonlikedict/relationship_parser.py b/src/spdx/parser/jsonlikedict/relationship_parser.py index c78d2771d..4d72f851a 100644 --- a/src/spdx/parser/jsonlikedict/relationship_parser.py +++ b/src/spdx/parser/jsonlikedict/relationship_parser.py @@ -10,13 +10,17 @@ # limitations under the License. from typing import Dict, List, Optional -from spdx.model.relationship import Relationship, RelationshipType from common.typing.constructor_type_errors import ConstructorTypeErrors +from spdx.model.relationship import Relationship, RelationshipType from spdx.parser.error import SPDXParsingError -from spdx.parser.jsonlikedict.dict_parsing_functions import json_str_to_enum_name, \ - parse_field_or_log_error, parse_field_or_no_assertion_or_none, delete_duplicates_from_list -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.jsonlikedict.dict_parsing_functions import ( + delete_duplicates_from_list, + json_str_to_enum_name, + parse_field_or_log_error, + parse_field_or_no_assertion_or_none, +) from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages class RelationshipParser: @@ -29,27 +33,40 @@ def parse_all_relationships(self, input_doc_dict: Dict) -> List[Relationship]: relationships = [] relationship_dicts: List[Dict] = input_doc_dict.get("relationships", []) relationships.extend( - parse_field_or_log_error(self.logger, relationship_dicts, self.parse_relationship, [], True)) + parse_field_or_log_error(self.logger, relationship_dicts, self.parse_relationship, [], True) + ) document_describes: List[str] = delete_duplicates_from_list(input_doc_dict.get("documentDescribes", [])) doc_spdx_id: Optional[str] = input_doc_dict.get("SPDXID") relationships.extend( - parse_field_or_log_error(self.logger, document_describes, lambda x: self.parse_document_describes( - doc_spdx_id=doc_spdx_id, described_spdx_ids=x, - existing_relationships=relationships), [])) + parse_field_or_log_error( + self.logger, + document_describes, + lambda x: self.parse_document_describes( + doc_spdx_id=doc_spdx_id, described_spdx_ids=x, existing_relationships=relationships + ), + [], + ) + ) package_dicts: List[Dict] = input_doc_dict.get("packages", []) - relationships.extend(parse_field_or_log_error( - self.logger, package_dicts, - lambda x: self.parse_has_files(package_dicts=x, existing_relationships=relationships), [])) + relationships.extend( + parse_field_or_log_error( + self.logger, + package_dicts, + lambda x: self.parse_has_files(package_dicts=x, existing_relationships=relationships), + [], + ) + ) file_dicts: List[Dict] = input_doc_dict.get("files", []) - # not implemented yet: deal with deprecated fields in file: https://github.com/spdx/tools-python/issues/294 & https://github.com/spdx/tools-python/issues/387 - generated_relationships = self.parse_artifact_of(file_dicts=file_dicts) - dependency_relationships = self.parse_file_dependencies(file_dicts=file_dicts) + # not implemented yet: deal with deprecated fields in file: + # https://github.com/spdx/tools-python/issues/294 & https://github.com/spdx/tools-python/issues/387 + _ = self.parse_artifact_of(file_dicts=file_dicts) + _ = self.parse_file_dependencies(file_dicts=file_dicts) raise_parsing_error_if_logger_has_messages(self.logger) @@ -58,16 +75,24 @@ def parse_all_relationships(self, input_doc_dict: Dict) -> List[Relationship]: def parse_relationship(self, relationship_dict: Dict) -> Relationship: logger = Logger() spdx_element_id: Optional[str] = relationship_dict.get("spdxElementId") - related_spdx_element: Optional[str] = parse_field_or_no_assertion_or_none(relationship_dict.get("relatedSpdxElement")) - relationship_type: Optional[RelationshipType] = parse_field_or_log_error(logger, relationship_dict.get( - "relationshipType"), self.parse_relationship_type) + related_spdx_element: Optional[str] = parse_field_or_no_assertion_or_none( + relationship_dict.get("relatedSpdxElement") + ) + relationship_type: Optional[RelationshipType] = parse_field_or_log_error( + logger, relationship_dict.get("relationshipType"), self.parse_relationship_type + ) relationship_comment: Optional[str] = relationship_dict.get("comment") raise_parsing_error_if_logger_has_messages(logger, "Relationship") - relationship = construct_or_raise_parsing_error(Relationship, dict(spdx_element_id=spdx_element_id, - relationship_type=relationship_type, - related_spdx_element_id=related_spdx_element, - comment=relationship_comment)) + relationship = construct_or_raise_parsing_error( + Relationship, + dict( + spdx_element_id=spdx_element_id, + relationship_type=relationship_type, + related_spdx_element_id=related_spdx_element, + comment=relationship_comment, + ), + ) return relationship @staticmethod @@ -78,15 +103,18 @@ def parse_relationship_type(relationship_type_str: str) -> RelationshipType: raise SPDXParsingError([f"Invalid RelationshipType: {relationship_type_str}"]) return relationship_type - def parse_document_describes(self, doc_spdx_id: str, described_spdx_ids: List[str], - existing_relationships: List[Relationship]) -> List[Relationship]: + def parse_document_describes( + self, doc_spdx_id: str, described_spdx_ids: List[str], existing_relationships: List[Relationship] + ) -> List[Relationship]: logger = Logger() describes_relationships = [] for spdx_id in described_spdx_ids: try: - describes_relationship = Relationship(spdx_element_id=doc_spdx_id, - relationship_type=RelationshipType.DESCRIBES, - related_spdx_element_id=spdx_id) + describes_relationship = Relationship( + spdx_element_id=doc_spdx_id, + relationship_type=RelationshipType.DESCRIBES, + related_spdx_element_id=spdx_id, + ) except ConstructorTypeErrors as err: logger.append(err.get_messages()) continue @@ -96,8 +124,9 @@ def parse_document_describes(self, doc_spdx_id: str, described_spdx_ids: List[st return describes_relationships - def parse_has_files(self, package_dicts: List[Dict], existing_relationships: List[Relationship]) -> List[ - Relationship]: + def parse_has_files( + self, package_dicts: List[Dict], existing_relationships: List[Relationship] + ) -> List[Relationship]: logger = Logger() contains_relationships = [] for package in package_dicts: @@ -107,23 +136,28 @@ def parse_has_files(self, package_dicts: List[Dict], existing_relationships: Lis continue for file_spdx_id in contained_files: try: - contains_relationship = Relationship(spdx_element_id=package_spdx_id, - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id=file_spdx_id) + contains_relationship = Relationship( + spdx_element_id=package_spdx_id, + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id=file_spdx_id, + ) except ConstructorTypeErrors as err: logger.append(err.get_messages()) continue - if not self.check_if_relationship_exists(relationship=contains_relationship, - existing_relationships=existing_relationships): + if not self.check_if_relationship_exists( + relationship=contains_relationship, existing_relationships=existing_relationships + ): contains_relationships.append(contains_relationship) raise_parsing_error_if_logger_has_messages(logger, "package contains relationships") return contains_relationships - def check_if_relationship_exists(self, relationship: Relationship, - existing_relationships: List[Relationship]) -> bool: + def check_if_relationship_exists( + self, relationship: Relationship, existing_relationships: List[Relationship] + ) -> bool: existing_relationships_without_comments: List[Relationship] = self.get_all_relationships_without_comments( - existing_relationships) + existing_relationships + ) if relationship in existing_relationships_without_comments: return True relationship_inverted: Relationship = self.invert_relationship(relationship) @@ -134,32 +168,41 @@ def check_if_relationship_exists(self, relationship: Relationship, @staticmethod def get_all_relationships_without_comments(existing_relationships: List[Relationship]) -> List[Relationship]: - relationships_without_comments = [Relationship(relationship_type=relationship.relationship_type, - related_spdx_element_id=relationship.related_spdx_element_id, - spdx_element_id=relationship.spdx_element_id) for relationship in - existing_relationships] + relationships_without_comments = [ + Relationship( + relationship_type=relationship.relationship_type, + related_spdx_element_id=relationship.related_spdx_element_id, + spdx_element_id=relationship.spdx_element_id, + ) + for relationship in existing_relationships + ] return relationships_without_comments def invert_relationship(self, relationship: Relationship) -> Relationship: - return Relationship(related_spdx_element_id=relationship.spdx_element_id, - spdx_element_id=relationship.related_spdx_element_id, - relationship_type=self.invert_relationship_types[relationship.relationship_type], - comment=relationship.comment) - - invert_relationship_types = {RelationshipType.DESCRIBES: RelationshipType.DESCRIBED_BY, - RelationshipType.DESCRIBED_BY: RelationshipType.DESCRIBES, - RelationshipType.CONTAINS: RelationshipType.CONTAINED_BY, - RelationshipType.CONTAINED_BY: RelationshipType.CONTAINS} + return Relationship( + related_spdx_element_id=relationship.spdx_element_id, + spdx_element_id=relationship.related_spdx_element_id, + relationship_type=self.invert_relationship_types[relationship.relationship_type], + comment=relationship.comment, + ) + + invert_relationship_types = { + RelationshipType.DESCRIBES: RelationshipType.DESCRIBED_BY, + RelationshipType.DESCRIBED_BY: RelationshipType.DESCRIBES, + RelationshipType.CONTAINS: RelationshipType.CONTAINED_BY, + RelationshipType.CONTAINED_BY: RelationshipType.CONTAINS, + } @staticmethod - def parse_file_dependencies(file_dicts: List[Dict]) -> List[ - Relationship]: + def parse_file_dependencies(file_dicts: List[Dict]) -> List[Relationship]: dependency_relationships = [] - # the field fileDependencies is deprecated and should be converted to a relationship (https://github.com/spdx/tools-python/issues/387) + # the field fileDependencies is deprecated and should be converted to a relationship + # https://github.com/spdx/tools-python/issues/387 return dependency_relationships @staticmethod def parse_artifact_of(file_dicts: List[Dict]) -> List[Relationship]: generated_relationships = [] - # artifactOfs is deprecated and should be converted to an external package and a generated from relationship (https://github.com/spdx/tools-python/issues/294) + # artifactOfs is deprecated and should be converted to an external package and a generated from relationship + # https://github.com/spdx/tools-python/issues/294 return generated_relationships diff --git a/src/spdx/parser/jsonlikedict/snippet_parser.py b/src/spdx/parser/jsonlikedict/snippet_parser.py index b942abe07..548a3eb6f 100644 --- a/src/spdx/parser/jsonlikedict/snippet_parser.py +++ b/src/spdx/parser/jsonlikedict/snippet_parser.py @@ -8,20 +8,19 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from enum import auto, Enum -from typing import Dict, Tuple, List, Optional, Union +from enum import Enum, auto +from typing import Dict, List, Optional, Tuple, Union from license_expression import LicenseExpression + from spdx.model.snippet import Snippet from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.parser.error import SPDXParsingError -from spdx.parser.jsonlikedict.dict_parsing_functions import parse_field_or_log_error, \ - parse_field_or_no_assertion_or_none -from spdx.parser.parsing_functions import construct_or_raise_parsing_error - +from spdx.parser.jsonlikedict.dict_parsing_functions import parse_field_or_log_error from spdx.parser.jsonlikedict.license_expression_parser import LicenseExpressionParser from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error class RangeType(Enum): @@ -54,21 +53,34 @@ def parse_snippet(self, snippet_dict: Dict) -> Snippet: copyright_text: Optional[str] = snippet_dict.get("copyrightText") license_comment: Optional[str] = snippet_dict.get("licenseComments") license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_field_or_log_error( - logger, snippet_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression) + logger, snippet_dict.get("licenseConcluded"), self.license_expression_parser.parse_license_expression + ) license_info: List[Union[LicenseExpression], SpdxNoAssertion, SpdxNone] = parse_field_or_log_error( - logger, snippet_dict.get("licenseInfoInSnippets"), self.license_expression_parser.parse_license_expression, - field_is_list=True) + logger, + snippet_dict.get("licenseInfoInSnippets"), + self.license_expression_parser.parse_license_expression, + field_is_list=True, + ) if logger.has_messages(): raise SPDXParsingError([f"Error while parsing snippet: {logger.get_messages()}"]) - snippet = construct_or_raise_parsing_error(Snippet, - dict(spdx_id=spdx_id, name=name, byte_range=byte_range, - file_spdx_id=file_spdx_id, line_range=line_range, - attribution_texts=attribution_texts, comment=comment, - copyright_text=copyright_text, license_comment=license_comment, - license_concluded=license_concluded, - license_info_in_snippet=license_info)) + snippet = construct_or_raise_parsing_error( + Snippet, + dict( + spdx_id=spdx_id, + name=name, + byte_range=byte_range, + file_spdx_id=file_spdx_id, + line_range=line_range, + attribution_texts=attribution_texts, + comment=comment, + copyright_text=copyright_text, + license_comment=license_comment, + license_concluded=license_concluded, + license_info_in_snippet=license_info, + ), + ) return snippet @@ -118,8 +130,9 @@ def validate_pointer_and_get_type(pointer: Dict) -> RangeType: return RangeType.BYTE if "offset" in pointer else RangeType.LINE @staticmethod - def convert_range_from_str(_range: Tuple[Union[int, str], Union[int, str]]) -> Tuple[ - Union[int, str], Union[int, str]]: + def convert_range_from_str( + _range: Tuple[Union[int, str], Union[int, str]] + ) -> Tuple[Union[int, str], Union[int, str]]: # XML does not support integers, so we have to convert from string (if possible) if not _range: return _range diff --git a/src/spdx/parser/parse_anything.py b/src/spdx/parser/parse_anything.py index 8b156cf34..51a730ae5 100644 --- a/src/spdx/parser/parse_anything.py +++ b/src/spdx/parser/parse_anything.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from spdx.formats import file_name_to_format, FileFormat +from spdx.formats import FileFormat, file_name_to_format from spdx.parser.json import json_parser from spdx.parser.rdf import rdf_parser from spdx.parser.tagvalue import tagvalue_parser diff --git a/src/spdx/parser/rdf/annotation_parser.py b/src/spdx/parser/rdf/annotation_parser.py index 88fe0ae65..80d6229bf 100644 --- a/src/spdx/parser/rdf/annotation_parser.py +++ b/src/spdx/parser/rdf/annotation_parser.py @@ -8,32 +8,45 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import URIRef, Graph, RDFS +from rdflib import RDFS, Graph, URIRef from spdx.datetime_conversions import datetime_from_str from spdx.model.annotation import Annotation, AnnotationType from spdx.parser.actor_parser import ActorParser from spdx.parser.logger import Logger -from spdx.parser.parsing_functions import raise_parsing_error_if_logger_has_messages, construct_or_raise_parsing_error -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_spdx_id, parse_enum_value +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.rdf.graph_parsing_functions import parse_enum_value, parse_literal, parse_spdx_id from spdx.rdfschema.namespace import SPDX_NAMESPACE def parse_annotation(annotation_node: URIRef, graph: Graph, parent_node: URIRef, doc_namespace: str) -> Annotation: logger = Logger() spdx_id = parse_spdx_id(parent_node, doc_namespace, graph) - annotator = parse_literal(logger, graph, annotation_node, SPDX_NAMESPACE.annotator, - parsing_method=ActorParser.parse_actor) - annotation_type = parse_literal(logger, graph, annotation_node, SPDX_NAMESPACE.annotationType, - parsing_method=lambda x: parse_enum_value(x, AnnotationType, - SPDX_NAMESPACE.annotationType_)) - annotation_date = parse_literal(logger, graph, annotation_node, SPDX_NAMESPACE.annotationDate, - parsing_method=datetime_from_str) + annotator = parse_literal( + logger, graph, annotation_node, SPDX_NAMESPACE.annotator, parsing_method=ActorParser.parse_actor + ) + annotation_type = parse_literal( + logger, + graph, + annotation_node, + SPDX_NAMESPACE.annotationType, + parsing_method=lambda x: parse_enum_value(x, AnnotationType, SPDX_NAMESPACE.annotationType_), + ) + annotation_date = parse_literal( + logger, graph, annotation_node, SPDX_NAMESPACE.annotationDate, parsing_method=datetime_from_str + ) annotation_comment = parse_literal(logger, graph, annotation_node, RDFS.comment) raise_parsing_error_if_logger_has_messages(logger, "Annotation") - annotation = construct_or_raise_parsing_error(Annotation, dict(spdx_id=spdx_id, annotation_type=annotation_type, - annotator=annotator, annotation_date=annotation_date, - annotation_comment=annotation_comment)) + annotation = construct_or_raise_parsing_error( + Annotation, + dict( + spdx_id=spdx_id, + annotation_type=annotation_type, + annotator=annotator, + annotation_date=annotation_date, + annotation_comment=annotation_comment, + ), + ) return annotation diff --git a/src/spdx/parser/rdf/checksum_parser.py b/src/spdx/parser/rdf/checksum_parser.py index 4ec73059e..91fd82244 100644 --- a/src/spdx/parser/rdf/checksum_parser.py +++ b/src/spdx/parser/rdf/checksum_parser.py @@ -9,9 +9,9 @@ # See the License for the specific language governing permissions and # limitations under the License. from rdflib import Graph, URIRef -from spdx.parser.error import SPDXParsingError from spdx.model.checksum import Checksum, ChecksumAlgorithm +from spdx.parser.error import SPDXParsingError from spdx.parser.logger import Logger from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.rdf.graph_parsing_functions import parse_literal, remove_prefix @@ -20,8 +20,9 @@ def parse_checksum(parent_node: URIRef, graph: Graph) -> Checksum: logger = Logger() - algorithm = parse_literal(logger, graph, parent_node, SPDX_NAMESPACE.algorithm, - parsing_method=convert_rdf_to_algorithm) + algorithm = parse_literal( + logger, graph, parent_node, SPDX_NAMESPACE.algorithm, parsing_method=convert_rdf_to_algorithm + ) value = parse_literal(logger, graph, parent_node, SPDX_NAMESPACE.checksumValue) raise_parsing_error_if_logger_has_messages(logger, "Checksum") diff --git a/src/spdx/parser/rdf/creation_info_parser.py b/src/spdx/parser/rdf/creation_info_parser.py index 7ca2215e1..57e63ca9d 100644 --- a/src/spdx/parser/rdf/creation_info_parser.py +++ b/src/spdx/parser/rdf/creation_info_parser.py @@ -13,30 +13,34 @@ from typing import Tuple from urllib.parse import urldefrag -from rdflib import Graph, RDFS, RDF, Namespace +from rdflib import RDF, RDFS, Graph, Namespace from rdflib.exceptions import UniquenessError from rdflib.term import URIRef -from spdx.parser.error import SPDXParsingError -from spdx.parser.logger import Logger -from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages -from spdx.parser.rdf.checksum_parser import parse_checksum -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_spdx_id, remove_prefix -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE - from spdx.datetime_conversions import datetime_from_str from spdx.model.document import CreationInfo from spdx.model.external_document_ref import ExternalDocumentRef from spdx.model.version import Version from spdx.parser.actor_parser import ActorParser +from spdx.parser.error import SPDXParsingError +from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.rdf.checksum_parser import parse_checksum +from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_spdx_id, remove_prefix +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE def parse_creation_info(graph: Graph) -> Tuple[CreationInfo, URIRef]: logger = Logger() namespace, spdx_id, doc_node = parse_namespace_and_spdx_id(graph) spec_version = parse_literal(logger, graph, doc_node, SPDX_NAMESPACE.specVersion) - data_license = parse_literal(logger, graph, doc_node, SPDX_NAMESPACE.dataLicense, - parsing_method=lambda x: remove_prefix(x, LICENSE_NAMESPACE)) + data_license = parse_literal( + logger, + graph, + doc_node, + SPDX_NAMESPACE.dataLicense, + parsing_method=lambda x: remove_prefix(x, LICENSE_NAMESPACE), + ) comment = parse_literal(logger, graph, doc_node, RDFS.comment) name = parse_literal(logger, graph, doc_node, SPDX_NAMESPACE.name) @@ -45,27 +49,37 @@ def parse_creation_info(graph: Graph) -> Tuple[CreationInfo, URIRef]: logger.append("CreationInfo does not exist.") raise SPDXParsingError([f"Error while parsing document {name}: {logger.get_messages()}"]) - created = parse_literal(logger, graph, creation_info_node, SPDX_NAMESPACE.created, - parsing_method=datetime_from_str) - license_list_version = parse_literal(logger, graph, creation_info_node, SPDX_NAMESPACE.licenseListVersion, - parsing_method=Version.from_string) + created = parse_literal( + logger, graph, creation_info_node, SPDX_NAMESPACE.created, parsing_method=datetime_from_str + ) + license_list_version = parse_literal( + logger, graph, creation_info_node, SPDX_NAMESPACE.licenseListVersion, parsing_method=Version.from_string + ) creator_comment = parse_literal(logger, graph, creation_info_node, RDFS.comment) creators = [] - for (_, _, creator_literal) in graph.triples((creation_info_node, SPDX_NAMESPACE.creator, None)): + for _, _, creator_literal in graph.triples((creation_info_node, SPDX_NAMESPACE.creator, None)): creators.append(ActorParser.parse_actor(creator_literal)) external_document_refs = [] - for (_, _, external_document_node) in graph.triples((doc_node, SPDX_NAMESPACE.externalDocumentRef, None)): + for _, _, external_document_node in graph.triples((doc_node, SPDX_NAMESPACE.externalDocumentRef, None)): external_document_refs.append(parse_external_document_refs(external_document_node, graph, namespace)) raise_parsing_error_if_logger_has_messages(logger, "CreationInfo") - creation_info = construct_or_raise_parsing_error(CreationInfo, dict(spdx_id=spdx_id, document_namespace=namespace, - spdx_version=spec_version, name=name, - data_license=data_license, - document_comment=comment, created=created, - license_list_version=license_list_version, - creator_comment=creator_comment, - creators=creators, - external_document_refs=external_document_refs)) + creation_info = construct_or_raise_parsing_error( + CreationInfo, + dict( + spdx_id=spdx_id, + document_namespace=namespace, + spdx_version=spec_version, + name=name, + data_license=data_license, + document_comment=comment, + created=created, + license_list_version=license_list_version, + creator_comment=creator_comment, + creators=creators, + external_document_refs=external_document_refs, + ), + ) return creation_info, doc_node @@ -79,16 +93,19 @@ def parse_namespace_and_spdx_id(graph: Graph) -> (str, str): if not subject: logging.error("No SpdxDocument found, can't parse rdf file.") sys.exit(1) - if not "#" in subject: - logging.error("No '#' found in the URI of SpdxDocument, " - "the URI for the SpdxDocument should be the namespace appended by '#SPDXRef-DOCUMENT.") + if "#" not in subject: + logging.error( + "No '#' found in the URI of SpdxDocument, " + "the URI for the SpdxDocument should be the namespace appended by '#SPDXRef-DOCUMENT." + ) sys.exit(1) namespace, spdx_id = urldefrag(subject) if not namespace: logging.error( - "No namespace found, the URI for the SpdxDocument should be the namespace appended by '#SPDXRef-DOCUMENT.") + "No namespace found, the URI for the SpdxDocument should be the namespace appended by '#SPDXRef-DOCUMENT." + ) sys.exit(1) if not spdx_id: @@ -97,16 +114,22 @@ def parse_namespace_and_spdx_id(graph: Graph) -> (str, str): return namespace, spdx_id, subject -def parse_external_document_refs(external_document_node: URIRef, graph: Graph, - doc_namespace: str) -> ExternalDocumentRef: +def parse_external_document_refs( + external_document_node: URIRef, graph: Graph, doc_namespace: str +) -> ExternalDocumentRef: logger = Logger() document_ref_id = parse_spdx_id(external_document_node, doc_namespace, graph) document_uri = parse_literal(logger, graph, external_document_node, SPDX_NAMESPACE.spdxDocument) - checksum = parse_literal(logger, graph, external_document_node, SPDX_NAMESPACE.checksum, - parsing_method=lambda x: parse_checksum(x, graph)) - external_document_ref = construct_or_raise_parsing_error(ExternalDocumentRef, dict(document_ref_id=document_ref_id, - document_uri=document_uri, - checksum=checksum)) + checksum = parse_literal( + logger, + graph, + external_document_node, + SPDX_NAMESPACE.checksum, + parsing_method=lambda x: parse_checksum(x, graph), + ) + external_document_ref = construct_or_raise_parsing_error( + ExternalDocumentRef, dict(document_ref_id=document_ref_id, document_uri=document_uri, checksum=checksum) + ) # To replace the external doc namespaces by the ref id in spdx ids later (e.g. in a relationship), we need to bind # the namespace to the graph. diff --git a/src/spdx/parser/rdf/extracted_licensing_info_parser.py b/src/spdx/parser/rdf/extracted_licensing_info_parser.py index edaf68b4a..2fa598696 100644 --- a/src/spdx/parser/rdf/extracted_licensing_info_parser.py +++ b/src/spdx/parser/rdf/extracted_licensing_info_parser.py @@ -8,13 +8,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import URIRef, Graph, RDFS -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_literal_or_no_assertion_or_none - -from spdx.parser.parsing_functions import raise_parsing_error_if_logger_has_messages, construct_or_raise_parsing_error +from rdflib import RDFS, Graph, URIRef from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.parser.logger import Logger +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_literal_or_no_assertion_or_none from spdx.rdfschema.namespace import SPDX_NAMESPACE @@ -23,15 +22,22 @@ def parse_extracted_licensing_info(extracted_licensing_info_node: URIRef, graph: license_id = parse_literal(logger, graph, extracted_licensing_info_node, SPDX_NAMESPACE.licenseId) extracted_text = parse_literal(logger, graph, extracted_licensing_info_node, SPDX_NAMESPACE.extractedText) comment = parse_literal(logger, graph, extracted_licensing_info_node, RDFS.comment) - license_name = parse_literal_or_no_assertion_or_none(logger, graph, extracted_licensing_info_node, SPDX_NAMESPACE.name) + license_name = parse_literal_or_no_assertion_or_none( + logger, graph, extracted_licensing_info_node, SPDX_NAMESPACE.name + ) cross_references = [] - for (_, _, cross_reference_node) in graph.triples((extracted_licensing_info_node, RDFS.seeAlso, None)): + for _, _, cross_reference_node in graph.triples((extracted_licensing_info_node, RDFS.seeAlso, None)): cross_references.append(cross_reference_node.toPython()) raise_parsing_error_if_logger_has_messages(logger, "ExtractedLicensingInfo") - extracted_licensing_info = construct_or_raise_parsing_error(ExtractedLicensingInfo, dict(license_id=license_id, - extracted_text=extracted_text, - comment=comment, - license_name=license_name, - cross_references=cross_references)) + extracted_licensing_info = construct_or_raise_parsing_error( + ExtractedLicensingInfo, + dict( + license_id=license_id, + extracted_text=extracted_text, + comment=comment, + license_name=license_name, + cross_references=cross_references, + ), + ) return extracted_licensing_info diff --git a/src/spdx/parser/rdf/file_parser.py b/src/spdx/parser/rdf/file_parser.py index 37cb2ca50..5f0a0a5cd 100644 --- a/src/spdx/parser/rdf/file_parser.py +++ b/src/spdx/parser/rdf/file_parser.py @@ -8,14 +8,20 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import URIRef, Graph, RDFS +from rdflib import RDFS, Graph, URIRef from spdx.model.file import File, FileType from spdx.parser.logger import Logger from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.rdf.checksum_parser import parse_checksum -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_spdx_id, parse_literal_or_no_assertion_or_none, \ - get_correctly_typed_value, apply_parsing_method_or_log_error, parse_enum_value +from spdx.parser.rdf.graph_parsing_functions import ( + apply_parsing_method_or_log_error, + get_correctly_typed_value, + parse_enum_value, + parse_literal, + parse_literal_or_no_assertion_or_none, + parse_spdx_id, +) from spdx.parser.rdf.license_expression_parser import parse_license_expression from spdx.rdfschema.namespace import SPDX_NAMESPACE @@ -25,41 +31,57 @@ def parse_file(file_node: URIRef, graph: Graph, doc_namespace: str) -> File: spdx_id = parse_spdx_id(file_node, doc_namespace, graph) name = parse_literal(logger, graph, file_node, SPDX_NAMESPACE.fileName) checksums = [] - for (_, _, checksum_node) in graph.triples((file_node, SPDX_NAMESPACE.checksum, None)): + for _, _, checksum_node in graph.triples((file_node, SPDX_NAMESPACE.checksum, None)): checksums.append(parse_checksum(checksum_node, graph)) file_types = [] - for (_, _, file_type_ref) in graph.triples((file_node, SPDX_NAMESPACE.fileType, None)): + for _, _, file_type_ref in graph.triples((file_node, SPDX_NAMESPACE.fileType, None)): file_types.append( - apply_parsing_method_or_log_error(logger, file_type_ref, - parsing_method=lambda x: parse_enum_value(x, FileType, - SPDX_NAMESPACE.fileType_))) + apply_parsing_method_or_log_error( + logger, file_type_ref, parsing_method=lambda x: parse_enum_value(x, FileType, SPDX_NAMESPACE.fileType_) + ) + ) license_concluded = parse_literal_or_no_assertion_or_none( - logger, graph, file_node, SPDX_NAMESPACE.licenseConcluded, - parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace)) + logger, + graph, + file_node, + SPDX_NAMESPACE.licenseConcluded, + parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace), + ) license_info_in_file = [] - for (_, _, license_info_from_files_node) in graph.triples((file_node, SPDX_NAMESPACE.licenseInfoInFile, None)): + for _, _, license_info_from_files_node in graph.triples((file_node, SPDX_NAMESPACE.licenseInfoInFile, None)): license_info_in_file.append( - get_correctly_typed_value(logger, license_info_from_files_node, - lambda x: parse_license_expression(x, graph, doc_namespace))) + get_correctly_typed_value( + logger, license_info_from_files_node, lambda x: parse_license_expression(x, graph, doc_namespace) + ) + ) license_comment = parse_literal(logger, graph, file_node, SPDX_NAMESPACE.licenseComments) copyright_text = parse_literal_or_no_assertion_or_none(logger, graph, file_node, SPDX_NAMESPACE.copyrightText) file_contributors = [] - for (_, _, file_contributor) in graph.triples((file_node, SPDX_NAMESPACE.fileContributor, None)): + for _, _, file_contributor in graph.triples((file_node, SPDX_NAMESPACE.fileContributor, None)): file_contributors.append(file_contributor.toPython()) notice_text = parse_literal(logger, graph, file_node, SPDX_NAMESPACE.noticeText) comment = parse_literal(logger, graph, file_node, RDFS.comment) attribution_texts = [] - for (_, _, attribution_text_literal) in graph.triples((file_node, SPDX_NAMESPACE.attributionText, None)): + for _, _, attribution_text_literal in graph.triples((file_node, SPDX_NAMESPACE.attributionText, None)): attribution_texts.append(attribution_text_literal.toPython()) raise_parsing_error_if_logger_has_messages(logger, "File") - file = construct_or_raise_parsing_error(File, dict(name=name, spdx_id=spdx_id, checksums=checksums, - attribution_texts=attribution_texts, comment=comment, - copyright_text=copyright_text, file_types=file_types, - contributors=file_contributors, - license_comment=license_comment, - license_concluded=license_concluded, - license_info_in_file=license_info_in_file, - notice=notice_text)) + file = construct_or_raise_parsing_error( + File, + dict( + name=name, + spdx_id=spdx_id, + checksums=checksums, + attribution_texts=attribution_texts, + comment=comment, + copyright_text=copyright_text, + file_types=file_types, + contributors=file_contributors, + license_comment=license_comment, + license_concluded=license_concluded, + license_info_in_file=license_info_in_file, + notice=notice_text, + ), + ) return file diff --git a/src/spdx/parser/rdf/graph_parsing_functions.py b/src/spdx/parser/rdf/graph_parsing_functions.py index 08fe3aae0..297f6e9ba 100644 --- a/src/spdx/parser/rdf/graph_parsing_functions.py +++ b/src/spdx/parser/rdf/graph_parsing_functions.py @@ -16,24 +16,31 @@ from rdflib.namespace import NamespaceManager from rdflib.term import Node -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING -from spdx.model.spdx_none import SpdxNone, SPDX_NONE_STRING +from spdx.casing_tools import camel_case_to_snake_case +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion +from spdx.model.spdx_none import SPDX_NONE_STRING, SpdxNone from spdx.parser.error import SPDXParsingError from spdx.parser.logger import Logger from spdx.rdfschema.namespace import SPDX_NAMESPACE -from spdx.casing_tools import camel_case_to_snake_case -def parse_literal(logger: Logger, graph: Graph, subject: Node, predicate: Node, - parsing_method: Callable = lambda x: x.strip(), default: Any = None): +def parse_literal( + logger: Logger, + graph: Graph, + subject: Node, + predicate: Node, + parsing_method: Callable = lambda x: x.strip(), + default: Any = None, +): value = get_unique_value(logger, graph, subject, predicate, default) if not value: return default return apply_parsing_method_or_log_error(logger, value, parsing_method, default) -def apply_parsing_method_or_log_error(logger: Logger, value: Any, parsing_method: Callable = lambda x: x.strip(), - default: Any = None): +def apply_parsing_method_or_log_error( + logger: Logger, value: Any, parsing_method: Callable = lambda x: x.strip(), default: Any = None +): try: return parsing_method(value) except SPDXParsingError as err: @@ -43,14 +50,21 @@ def apply_parsing_method_or_log_error(logger: Logger, value: Any, parsing_method return default -def parse_literal_or_no_assertion_or_none(logger: Logger, graph: Graph, subject: Node, predicate: Node, - parsing_method: Callable = lambda x: x.strip(), default: Any = None): +def parse_literal_or_no_assertion_or_none( + logger: Logger, + graph: Graph, + subject: Node, + predicate: Node, + parsing_method: Callable = lambda x: x.strip(), + default: Any = None, +): value = get_unique_value(logger, graph, subject, predicate, default) return get_correctly_typed_value(logger, value, parsing_method, default) -def get_correctly_typed_value(logger: Logger, value: Any, parsing_method: Callable = lambda x: x.strip(), - default: Any = None): +def get_correctly_typed_value( + logger: Logger, value: Any, parsing_method: Callable = lambda x: x.strip(), default: Any = None +): if not value: return default if value == SPDX_NAMESPACE.noassertion or value.toPython() == SPDX_NO_ASSERTION_STRING: @@ -93,5 +107,5 @@ def parse_spdx_id(resource: URIRef, doc_namespace: str, graph: Graph) -> Optiona # to write our own helper method to delete prefixes. def remove_prefix(string: str, prefix: str) -> str: if string.startswith(prefix): - return string[len(prefix):] + return string[len(prefix) :] return string diff --git a/src/spdx/parser/rdf/license_expression_parser.py b/src/spdx/parser/rdf/license_expression_parser.py index b178252e0..346fd5143 100644 --- a/src/spdx/parser/rdf/license_expression_parser.py +++ b/src/spdx/parser/rdf/license_expression_parser.py @@ -10,16 +10,17 @@ # limitations under the License. from typing import Union -from rdflib import Graph, RDF from license_expression import LicenseExpression, get_spdx_licensing -from rdflib.term import Identifier, URIRef, BNode, Node -from spdx.parser.rdf.graph_parsing_functions import remove_prefix +from rdflib import RDF, Graph +from rdflib.term import BNode, Identifier, Node, URIRef -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE +from spdx.parser.rdf.graph_parsing_functions import remove_prefix +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE -def parse_license_expression(license_expression_node: Union[URIRef, BNode, Node], graph: Graph, - doc_namespace: str) -> LicenseExpression: +def parse_license_expression( + license_expression_node: Union[URIRef, BNode, Node], graph: Graph, doc_namespace: str +) -> LicenseExpression: spdx_licensing = get_spdx_licensing() expression = "" if license_expression_node.startswith(LICENSE_NAMESPACE): @@ -32,19 +33,21 @@ def parse_license_expression(license_expression_node: Union[URIRef, BNode, Node] node_type = graph.value(license_expression_node, RDF.type) if node_type == SPDX_NAMESPACE.ConjunctiveLicenseSet: members = [] - for (_, _, member_node) in graph.triples((license_expression_node, SPDX_NAMESPACE.member, None)): + for _, _, member_node in graph.triples((license_expression_node, SPDX_NAMESPACE.member, None)): members.append(parse_license_expression(member_node, graph, doc_namespace)) expression = " AND ".join([str(member) for member in members]) if node_type == SPDX_NAMESPACE.DisjunctiveLicenseSet: members = [] - for (_, _, member_node) in graph.triples((license_expression_node, SPDX_NAMESPACE.member, None)): + for _, _, member_node in graph.triples((license_expression_node, SPDX_NAMESPACE.member, None)): members.append(parse_license_expression(member_node, graph, doc_namespace)) expression = " OR ".join([str(member) for member in members]) if node_type == SPDX_NAMESPACE.WithExceptionOperator: - license_expression = parse_license_expression(graph.value(license_expression_node, SPDX_NAMESPACE.member), - graph, doc_namespace) - exception = parse_license_exception(graph.value(license_expression_node, SPDX_NAMESPACE.licenseException), - graph) + license_expression = parse_license_expression( + graph.value(license_expression_node, SPDX_NAMESPACE.member), graph, doc_namespace + ) + exception = parse_license_exception( + graph.value(license_expression_node, SPDX_NAMESPACE.licenseException), graph + ) expression = f"{license_expression} WITH {exception}" return spdx_licensing.parse(expression) diff --git a/src/spdx/parser/rdf/package_parser.py b/src/spdx/parser/rdf/package_parser.py index 27977daba..0301ecdee 100644 --- a/src/spdx/parser/rdf/package_parser.py +++ b/src/spdx/parser/rdf/package_parser.py @@ -9,57 +9,85 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Optional -from rdflib import URIRef, Graph, RDFS, DOAP, Literal + +from rdflib import DOAP, RDFS, Graph, URIRef from spdx.datetime_conversions import datetime_from_str -from spdx.model.package import Package, PackagePurpose, ExternalPackageRef, PackageVerificationCode, \ - ExternalPackageRefCategory +from spdx.model.package import ( + ExternalPackageRef, + ExternalPackageRefCategory, + Package, + PackagePurpose, + PackageVerificationCode, +) from spdx.parser.actor_parser import ActorParser from spdx.parser.logger import Logger -from spdx.parser.parsing_functions import raise_parsing_error_if_logger_has_messages, construct_or_raise_parsing_error +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages from spdx.parser.rdf.checksum_parser import parse_checksum -from spdx.parser.rdf.graph_parsing_functions import parse_spdx_id, parse_literal, parse_enum_value, \ - parse_literal_or_no_assertion_or_none, get_correctly_typed_value, parse_literal_or_no_assertion_or_none, remove_prefix +from spdx.parser.rdf.graph_parsing_functions import ( + get_correctly_typed_value, + parse_enum_value, + parse_literal, + parse_literal_or_no_assertion_or_none, + parse_spdx_id, +) from spdx.parser.rdf.license_expression_parser import parse_license_expression -from spdx.rdfschema.namespace import SPDX_NAMESPACE, REFERENCE_NAMESPACE +from spdx.rdfschema.namespace import REFERENCE_NAMESPACE, SPDX_NAMESPACE def parse_package(package_node: URIRef, graph: Graph, doc_namespace: str) -> Package: logger = Logger() spdx_id = parse_spdx_id(package_node, doc_namespace, graph) name = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.name) - download_location = parse_literal_or_no_assertion_or_none(logger, graph, package_node, - SPDX_NAMESPACE.downloadLocation) + download_location = parse_literal_or_no_assertion_or_none( + logger, graph, package_node, SPDX_NAMESPACE.downloadLocation + ) checksums = [] - for (_, _, checksum_node) in graph.triples((package_node, SPDX_NAMESPACE.checksum, None)): + for _, _, checksum_node in graph.triples((package_node, SPDX_NAMESPACE.checksum, None)): checksums.append(parse_checksum(checksum_node, graph)) version_info = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.versionInfo) package_file_name = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.packageFileName) - supplier = parse_literal_or_no_assertion_or_none(logger, graph, package_node, SPDX_NAMESPACE.supplier, - parsing_method=ActorParser.parse_actor) - originator = parse_literal_or_no_assertion_or_none(logger, graph, package_node, SPDX_NAMESPACE.originator, - parsing_method=ActorParser.parse_actor) - verification_code = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.packageVerificationCode, - parsing_method=lambda x: parse_package_verification_code(x, graph)) + supplier = parse_literal_or_no_assertion_or_none( + logger, graph, package_node, SPDX_NAMESPACE.supplier, parsing_method=ActorParser.parse_actor + ) + originator = parse_literal_or_no_assertion_or_none( + logger, graph, package_node, SPDX_NAMESPACE.originator, parsing_method=ActorParser.parse_actor + ) + verification_code = parse_literal( + logger, + graph, + package_node, + SPDX_NAMESPACE.packageVerificationCode, + parsing_method=lambda x: parse_package_verification_code(x, graph), + ) external_package_refs = [] - for (_, _, external_package_ref_node) in graph.triples((package_node, SPDX_NAMESPACE.externalRef, None)): + for _, _, external_package_ref_node in graph.triples((package_node, SPDX_NAMESPACE.externalRef, None)): external_package_refs.append(parse_external_package_ref(external_package_ref_node, graph, doc_namespace)) files_analyzed = bool(graph.value(package_node, SPDX_NAMESPACE.filesAnalyzed, default=True)) license_concluded = parse_literal_or_no_assertion_or_none( - logger, graph, package_node, SPDX_NAMESPACE.licenseConcluded, - parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace)) + logger, + graph, + package_node, + SPDX_NAMESPACE.licenseConcluded, + parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace), + ) license_declared = parse_literal_or_no_assertion_or_none( - logger, graph, package_node, SPDX_NAMESPACE.licenseDeclared, - parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace)) + logger, + graph, + package_node, + SPDX_NAMESPACE.licenseDeclared, + parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace), + ) license_info_from_files = [] - for (_, _, license_info_from_files_node) in graph.triples( - (package_node, SPDX_NAMESPACE.licenseInfoFromFiles, None)): + for _, _, license_info_from_files_node in graph.triples((package_node, SPDX_NAMESPACE.licenseInfoFromFiles, None)): license_info_from_files.append( - get_correctly_typed_value(logger, license_info_from_files_node, - lambda x: parse_license_expression(x, graph, doc_namespace))) + get_correctly_typed_value( + logger, license_info_from_files_node, lambda x: parse_license_expression(x, graph, doc_namespace) + ) + ) license_comment = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.licenseComments) comment = parse_literal(logger, graph, package_node, RDFS.comment) summary = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.summary) @@ -67,55 +95,76 @@ def parse_package(package_node: URIRef, graph: Graph, doc_namespace: str) -> Pac copyright_text = parse_literal_or_no_assertion_or_none(logger, graph, package_node, SPDX_NAMESPACE.copyrightText) source_info = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.sourceInfo) primary_package_purpose = parse_literal( - logger, graph, package_node, SPDX_NAMESPACE.primaryPackagePurpose, - parsing_method=lambda x: parse_enum_value(x, PackagePurpose, SPDX_NAMESPACE.purpose_)) + logger, + graph, + package_node, + SPDX_NAMESPACE.primaryPackagePurpose, + parsing_method=lambda x: parse_enum_value(x, PackagePurpose, SPDX_NAMESPACE.purpose_), + ) homepage = parse_literal(logger, graph, package_node, DOAP.homepage) attribution_texts = [] - for (_, _, attribution_text_literal) in graph.triples((package_node, SPDX_NAMESPACE.attributionText, None)): + for _, _, attribution_text_literal in graph.triples((package_node, SPDX_NAMESPACE.attributionText, None)): attribution_texts.append(attribution_text_literal.toPython()) - release_date = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.releaseDate, - parsing_method=datetime_from_str) + release_date = parse_literal( + logger, graph, package_node, SPDX_NAMESPACE.releaseDate, parsing_method=datetime_from_str + ) built_date = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.builtDate, parsing_method=datetime_from_str) - valid_until_date = parse_literal(logger, graph, package_node, SPDX_NAMESPACE.validUntilDate, - parsing_method=datetime_from_str) + valid_until_date = parse_literal( + logger, graph, package_node, SPDX_NAMESPACE.validUntilDate, parsing_method=datetime_from_str + ) raise_parsing_error_if_logger_has_messages(logger, "Package") - package = construct_or_raise_parsing_error(Package, - dict(name=name, spdx_id=spdx_id, download_location=download_location, - version=version_info, file_name=package_file_name, - supplier=supplier, originator=originator, - files_analyzed=files_analyzed, - verification_code=verification_code, - checksums=checksums, homepage=homepage, - source_info=source_info, - license_concluded=license_concluded, - license_info_from_files=license_info_from_files, - license_declared=license_declared, - license_comment=license_comment, - copyright_text=copyright_text, summary=summary, - description=description, comment=comment, - external_references=external_package_refs, - attribution_texts=attribution_texts, - primary_package_purpose=primary_package_purpose, - release_date=release_date, built_date=built_date, - valid_until_date=valid_until_date)) + package = construct_or_raise_parsing_error( + Package, + dict( + name=name, + spdx_id=spdx_id, + download_location=download_location, + version=version_info, + file_name=package_file_name, + supplier=supplier, + originator=originator, + files_analyzed=files_analyzed, + verification_code=verification_code, + checksums=checksums, + homepage=homepage, + source_info=source_info, + license_concluded=license_concluded, + license_info_from_files=license_info_from_files, + license_declared=license_declared, + license_comment=license_comment, + copyright_text=copyright_text, + summary=summary, + description=description, + comment=comment, + external_references=external_package_refs, + attribution_texts=attribution_texts, + primary_package_purpose=primary_package_purpose, + release_date=release_date, + built_date=built_date, + valid_until_date=valid_until_date, + ), + ) return package -def parse_package_verification_code(package_verification_code_node: URIRef, graph: Graph) -> Optional[ - PackageVerificationCode]: +def parse_package_verification_code( + package_verification_code_node: URIRef, graph: Graph +) -> Optional[PackageVerificationCode]: logger = Logger() value = parse_literal(logger, graph, package_verification_code_node, SPDX_NAMESPACE.packageVerificationCodeValue) excluded_files = [] - for (_, _, excluded_file_literal) in graph.triples( - (package_verification_code_node, SPDX_NAMESPACE.packageVerificationCodeExcludedFile, None)): + for _, _, excluded_file_literal in graph.triples( + (package_verification_code_node, SPDX_NAMESPACE.packageVerificationCodeExcludedFile, None) + ): excluded_files.append(excluded_file_literal.toPython()) raise_parsing_error_if_logger_has_messages(logger, "PackageVerificationCode") - package_verification_code = construct_or_raise_parsing_error(PackageVerificationCode, dict(value=value, - excluded_files=excluded_files)) + package_verification_code = construct_or_raise_parsing_error( + PackageVerificationCode, dict(value=value, excluded_files=excluded_files) + ) return package_verification_code @@ -123,16 +172,25 @@ def parse_external_package_ref(external_package_ref_node: URIRef, graph: Graph, logger = Logger() ref_locator = parse_literal(logger, graph, external_package_ref_node, SPDX_NAMESPACE.referenceLocator) ref_category = parse_literal( - logger, graph, external_package_ref_node, SPDX_NAMESPACE.referenceCategory, - parsing_method=lambda x: parse_enum_value(x, ExternalPackageRefCategory, SPDX_NAMESPACE.referenceCategory_)) - ref_type = parse_literal(logger, graph, external_package_ref_node, SPDX_NAMESPACE.referenceType, - parsing_method=lambda x: parse_external_package_ref_type(x, doc_namespace)) + logger, + graph, + external_package_ref_node, + SPDX_NAMESPACE.referenceCategory, + parsing_method=lambda x: parse_enum_value(x, ExternalPackageRefCategory, SPDX_NAMESPACE.referenceCategory_), + ) + ref_type = parse_literal( + logger, + graph, + external_package_ref_node, + SPDX_NAMESPACE.referenceType, + parsing_method=lambda x: parse_external_package_ref_type(x, doc_namespace), + ) comment = parse_literal(logger, graph, external_package_ref_node, RDFS.comment) raise_parsing_error_if_logger_has_messages(logger, "ExternalPackageRef") - external_package_ref = construct_or_raise_parsing_error(ExternalPackageRef, - dict(category=ref_category, reference_type=ref_type, - locator=ref_locator, comment=comment)) + external_package_ref = construct_or_raise_parsing_error( + ExternalPackageRef, dict(category=ref_category, reference_type=ref_type, locator=ref_locator, comment=comment) + ) return external_package_ref diff --git a/src/spdx/parser/rdf/rdf_parser.py b/src/spdx/parser/rdf/rdf_parser.py index e343f4b26..60f0bfb9f 100644 --- a/src/spdx/parser/rdf/rdf_parser.py +++ b/src/spdx/parser/rdf/rdf_parser.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, RDF +from rdflib import RDF, Graph from spdx.model.document import Document from spdx.parser.error import SPDXParsingError @@ -44,22 +44,25 @@ def translate_graph_to_document(graph: Graph) -> Document: parsed_fields["creation_info"] = creation_info - for element, triple, parsing_method in [("packages", (None, RDF.type, SPDX_NAMESPACE.Package), parse_package), - ("files", (None, RDF.type, SPDX_NAMESPACE.File), parse_file), - ("snippets", (None, RDF.type, SPDX_NAMESPACE.Snippet), parse_snippet)]: + for element, triple, parsing_method in [ + ("packages", (None, RDF.type, SPDX_NAMESPACE.Package), parse_package), + ("files", (None, RDF.type, SPDX_NAMESPACE.File), parse_file), + ("snippets", (None, RDF.type, SPDX_NAMESPACE.Snippet), parse_snippet), + ]: elements = [] - for (element_node, _, _) in graph.triples(triple): + for element_node, _, _ in graph.triples(triple): try: elements.append(parsing_method(element_node, graph, creation_info.document_namespace)) except SPDXParsingError as err: logger.extend(err.get_messages()) parsed_fields[element] = elements - for element, triple, parsing_method in [("annotations", (None, SPDX_NAMESPACE.annotation, None), parse_annotation), - ("relationships", (None, SPDX_NAMESPACE.relationship, None), - parse_relationship)]: + for element, triple, parsing_method in [ + ("annotations", (None, SPDX_NAMESPACE.annotation, None), parse_annotation), + ("relationships", (None, SPDX_NAMESPACE.relationship, None), parse_relationship), + ]: elements = [] - for (parent_node, _, element_node) in graph.triples(triple): + for parent_node, _, element_node in graph.triples(triple): try: elements.append(parsing_method(element_node, graph, parent_node, creation_info.document_namespace)) except SPDXParsingError as err: @@ -67,7 +70,7 @@ def translate_graph_to_document(graph: Graph) -> Document: parsed_fields[element] = elements extracted_licensing_infos = [] - for (_, _, extracted_licensing_info_node) in graph.triples((None, SPDX_NAMESPACE.hasExtractedLicensingInfo, None)): + for _, _, extracted_licensing_info_node in graph.triples((None, SPDX_NAMESPACE.hasExtractedLicensingInfo, None)): try: extracted_licensing_infos.append(parse_extracted_licensing_info(extracted_licensing_info_node, graph)) except SPDXParsingError as err: diff --git a/src/spdx/parser/rdf/relationship_parser.py b/src/spdx/parser/rdf/relationship_parser.py index c9a49403e..e0bb13e17 100644 --- a/src/spdx/parser/rdf/relationship_parser.py +++ b/src/spdx/parser/rdf/relationship_parser.py @@ -8,33 +8,51 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import URIRef, Graph, RDFS +from rdflib import RDFS, Graph, URIRef from spdx.model.relationship import Relationship, RelationshipType from spdx.parser.logger import Logger -from spdx.parser.parsing_functions import raise_parsing_error_if_logger_has_messages, construct_or_raise_parsing_error -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_enum_value, \ - parse_literal_or_no_assertion_or_none, parse_spdx_id +from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.rdf.graph_parsing_functions import ( + parse_enum_value, + parse_literal, + parse_literal_or_no_assertion_or_none, + parse_spdx_id, +) from spdx.rdfschema.namespace import SPDX_NAMESPACE -def parse_relationship(relationship_node: URIRef, graph: Graph, parent_node: URIRef, - doc_namespace: str) -> Relationship: +def parse_relationship( + relationship_node: URIRef, graph: Graph, parent_node: URIRef, doc_namespace: str +) -> Relationship: logger = Logger() spdx_element_id = parse_spdx_id(parent_node, doc_namespace, graph) relationship_type = parse_literal( - logger, graph, relationship_node, SPDX_NAMESPACE.relationshipType, - parsing_method=lambda x: parse_enum_value(x, RelationshipType, SPDX_NAMESPACE.relationshipType_)) + logger, + graph, + relationship_node, + SPDX_NAMESPACE.relationshipType, + parsing_method=lambda x: parse_enum_value(x, RelationshipType, SPDX_NAMESPACE.relationshipType_), + ) related_spdx_element = parse_literal_or_no_assertion_or_none( - logger, graph, relationship_node, SPDX_NAMESPACE.relatedSpdxElement, - parsing_method=lambda x: parse_spdx_id(x, doc_namespace, graph)) + logger, + graph, + relationship_node, + SPDX_NAMESPACE.relatedSpdxElement, + parsing_method=lambda x: parse_spdx_id(x, doc_namespace, graph), + ) comment = parse_literal(logger, graph, relationship_node, RDFS.comment) raise_parsing_error_if_logger_has_messages(logger, "Relationship") - relationship = construct_or_raise_parsing_error(Relationship, - dict(spdx_element_id=spdx_element_id, - relationship_type=relationship_type, - related_spdx_element_id=related_spdx_element, comment=comment)) + relationship = construct_or_raise_parsing_error( + Relationship, + dict( + spdx_element_id=spdx_element_id, + relationship_type=relationship_type, + related_spdx_element_id=related_spdx_element, + comment=comment, + ), + ) return relationship diff --git a/src/spdx/parser/rdf/snippet_parser.py b/src/spdx/parser/rdf/snippet_parser.py index 096681fe0..6a69306f3 100644 --- a/src/spdx/parser/rdf/snippet_parser.py +++ b/src/spdx/parser/rdf/snippet_parser.py @@ -8,20 +8,25 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Tuple, Optional, Dict +from typing import Dict, Optional, Tuple -from rdflib import Graph, RDF, RDFS +from rdflib import RDF, RDFS, Graph from rdflib.exceptions import UniquenessError -from rdflib.term import URIRef, Node -from spdx.parser.error import SPDXParsingError +from rdflib.term import Node, URIRef from spdx.model.snippet import Snippet +from spdx.parser.error import SPDXParsingError from spdx.parser.logger import Logger from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages -from spdx.parser.rdf.graph_parsing_functions import parse_literal, parse_spdx_id, parse_literal_or_no_assertion_or_none, \ - get_correctly_typed_value, apply_parsing_method_or_log_error +from spdx.parser.rdf.graph_parsing_functions import ( + apply_parsing_method_or_log_error, + get_correctly_typed_value, + parse_literal, + parse_literal_or_no_assertion_or_none, + parse_spdx_id, +) from spdx.parser.rdf.license_expression_parser import parse_license_expression -from spdx.rdfschema.namespace import SPDX_NAMESPACE, POINTER_NAMESPACE +from spdx.rdfschema.namespace import POINTER_NAMESPACE, SPDX_NAMESPACE def parse_snippet(snippet_node: URIRef, graph: Graph, doc_namespace: str) -> Snippet: @@ -31,42 +36,60 @@ def parse_snippet(snippet_node: URIRef, graph: Graph, doc_namespace: str) -> Sni file_spdx_id = parse_spdx_id(file_spdx_id_uri, doc_namespace, graph) byte_range = None line_range = None - for (_, _, start_end_pointer) in graph.triples((snippet_node, SPDX_NAMESPACE.range, None)): - parsed_range = apply_parsing_method_or_log_error(logger, start_end_pointer, - parsing_method=lambda x: parse_ranges(x, graph)) + for _, _, start_end_pointer in graph.triples((snippet_node, SPDX_NAMESPACE.range, None)): + parsed_range = apply_parsing_method_or_log_error( + logger, start_end_pointer, parsing_method=lambda x: parse_ranges(x, graph) + ) byte_range, line_range = set_range_or_log_error(byte_range, line_range, logger, parsed_range) license_concluded = parse_literal_or_no_assertion_or_none( - logger, graph, snippet_node, SPDX_NAMESPACE.licenseConcluded, - parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace)) + logger, + graph, + snippet_node, + SPDX_NAMESPACE.licenseConcluded, + parsing_method=lambda x: parse_license_expression(x, graph, doc_namespace), + ) license_info_in_snippet = [] - for (_, _, license_info_in_snippet_node) in graph.triples( - (snippet_node, SPDX_NAMESPACE.licenseInfoInSnippet, None)): + for _, _, license_info_in_snippet_node in graph.triples((snippet_node, SPDX_NAMESPACE.licenseInfoInSnippet, None)): license_info_in_snippet.append( - get_correctly_typed_value(logger, license_info_in_snippet_node, - lambda x: parse_license_expression(x, graph, doc_namespace))) + get_correctly_typed_value( + logger, license_info_in_snippet_node, lambda x: parse_license_expression(x, graph, doc_namespace) + ) + ) license_comment = parse_literal(logger, graph, snippet_node, SPDX_NAMESPACE.licenseComments) copyright_text = parse_literal_or_no_assertion_or_none(logger, graph, snippet_node, SPDX_NAMESPACE.copyrightText) comment = parse_literal(logger, graph, snippet_node, RDFS.comment) name = parse_literal(logger, graph, snippet_node, SPDX_NAMESPACE.name) attribution_texts = [] - for (_, _, attribution_text_literal) in graph.triples((snippet_node, SPDX_NAMESPACE.attributionText, None)): + for _, _, attribution_text_literal in graph.triples((snippet_node, SPDX_NAMESPACE.attributionText, None)): attribution_texts.append(attribution_text_literal.toPython()) raise_parsing_error_if_logger_has_messages(logger, "Snippet") - snippet = construct_or_raise_parsing_error(Snippet, - dict(spdx_id=spdx_id, file_spdx_id=file_spdx_id, byte_range=byte_range, - line_range=line_range, license_concluded=license_concluded, - license_info_in_snippet=license_info_in_snippet, - license_comment=license_comment, - copyright_text=copyright_text, comment=comment, name=name, - attribution_texts=attribution_texts)) + snippet = construct_or_raise_parsing_error( + Snippet, + dict( + spdx_id=spdx_id, + file_spdx_id=file_spdx_id, + byte_range=byte_range, + line_range=line_range, + license_concluded=license_concluded, + license_info_in_snippet=license_info_in_snippet, + license_comment=license_comment, + copyright_text=copyright_text, + comment=comment, + name=name, + attribution_texts=attribution_texts, + ), + ) return snippet def set_range_or_log_error( - byte_range: Optional[Tuple[int, int]], line_range: Optional[Tuple[int, int]], logger: Logger, - parsed_range: Dict[str, Tuple[int, int]]) -> Tuple[Optional[Tuple[int, int]], Optional[Tuple[int, int]]]: + byte_range: Optional[Tuple[int, int]], + line_range: Optional[Tuple[int, int]], + logger: Logger, + parsed_range: Dict[str, Tuple[int, int]], +) -> Tuple[Optional[Tuple[int, int]], Optional[Tuple[int, int]]]: if not parsed_range: return byte_range, line_range if "ByteOffsetPointer" in parsed_range.keys() and not byte_range: @@ -86,13 +109,12 @@ def parse_ranges(start_end_pointer: URIRef, graph: Graph) -> Dict[str, Tuple[int end_pointer_type, end_pointer_node = get_pointer_type(graph, POINTER_NAMESPACE.endPointer, start_end_pointer) if start_pointer_type != end_pointer_type: - raise SPDXParsingError([f"Types of startPointer and endPointer don't match"]) + raise SPDXParsingError(["Types of startPointer and endPointer don't match"]) range_values["startPointer"] = parse_range_value(graph, start_pointer_node, POINTER_MATCHING[start_pointer_type]) range_values["endPointer"] = parse_range_value(graph, end_pointer_node, POINTER_MATCHING[end_pointer_type]) - return {str(start_pointer_type.fragment): ( - range_values["startPointer"], range_values["endPointer"])} + return {str(start_pointer_type.fragment): (range_values["startPointer"], range_values["endPointer"])} def get_pointer_type(graph: Graph, pointer: URIRef, start_end_pointer: URIRef) -> Tuple[URIRef, URIRef]: @@ -108,7 +130,8 @@ def get_pointer_type(graph: Graph, pointer: URIRef, start_end_pointer: URIRef) - POINTER_MATCHING = { POINTER_NAMESPACE.ByteOffsetPointer: POINTER_NAMESPACE.offset, - POINTER_NAMESPACE.LineCharPointer: POINTER_NAMESPACE.lineNumber} + POINTER_NAMESPACE.LineCharPointer: POINTER_NAMESPACE.lineNumber, +} def parse_range_value(graph: Graph, pointer_node: Node, predicate: URIRef) -> Optional[int]: diff --git a/src/spdx/parser/tagvalue/helper_methods.py b/src/spdx/parser/tagvalue/helper_methods.py index 3f7ad0012..3814b3d29 100644 --- a/src/spdx/parser/tagvalue/helper_methods.py +++ b/src/spdx/parser/tagvalue/helper_methods.py @@ -9,7 +9,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import re -from typing import Optional, Callable, Any, Dict +from typing import Any, Callable, Dict, Optional from ply.yacc import YaccProduction @@ -54,13 +54,16 @@ def parse_checksum(checksum_str: str) -> Checksum: return checksum -def set_value(parsed_value: YaccProduction, dict_to_fill: Dict[str, Any], argument_name: Optional[str] = None, - method_to_apply: Callable = lambda x: x): +def set_value( + parsed_value: YaccProduction, + dict_to_fill: Dict[str, Any], + argument_name: Optional[str] = None, + method_to_apply: Callable = lambda x: x, +): if not argument_name: argument_name = get_property_name(parsed_value[1]) if argument_name in dict_to_fill: - dict_to_fill["logger"].append( - f"Multiple values for {parsed_value[1]} found. Line: {parsed_value.lineno(1)}") + dict_to_fill["logger"].append(f"Multiple values for {parsed_value[1]} found. Line: {parsed_value.lineno(1)}") return try: dict_to_fill[argument_name] = method_to_apply(parsed_value[2]) @@ -82,31 +85,54 @@ def get_property_name(tag: str): # This mapping is not complete as we only list the values which can be parsed by a generic method and don't need any # individual logic. TAG_DATA_MODEL_FIELD = { - "SPDXVersion": (CreationInfo, "spdx_version"), "DataLicense": (CreationInfo, "data_license"), - "DocumentName": (CreationInfo, "name"), "DocumentComment": (CreationInfo, "document_comment"), - "DocumentNamespace": (CreationInfo, "document_namespace"), "Creator": (CreationInfo, "creator"), - "Created": (CreationInfo, "created"), "CreatorComment": (CreationInfo, "creator_comment"), + "SPDXVersion": (CreationInfo, "spdx_version"), + "DataLicense": (CreationInfo, "data_license"), + "DocumentName": (CreationInfo, "name"), + "DocumentComment": (CreationInfo, "document_comment"), + "DocumentNamespace": (CreationInfo, "document_namespace"), + "Creator": (CreationInfo, "creator"), + "Created": (CreationInfo, "created"), + "CreatorComment": (CreationInfo, "creator_comment"), "LicenseListVersion": (CreationInfo, "license_list_version"), "ExternalDocumentRef": (CreationInfo, "external_document_refs"), - "FileName": (File, "name"), "FileType": (File, "file_type"), "FileChecksum": (File, "checksums"), - "FileNotice": (File, "notice"), "FileCopyrightText": (File, "copyright_text"), - "LicenseComments": (File, "license_comment"), "FileComment": (File, "comment"), - "LicenseConcluded": (File, "license_concluded"), "LicenseDeclared": (File, "license_declared"), - "PackageName": (Package, "name"), "PackageComment": (Package, "comment"), - "PackageCopyrightText": (Package, "copyright_text"), "PackageLicenseComments": (Package, "license_comment"), - "PackageLicenseDeclared": (Package, "license_declared"), "PackageLicenseConcluded": (Package, "license_concluded"), - "PackageFileName": (Package, "file_name"), "PackageVersion": (Package, "version"), - "PackageDownloadLocation": (Package, "download_location"), "PackageSummary": (Package, "summary"), - "PackageSourceInfo": (Package, "source_info"), "PackageSupplier": (Package, "supplier"), - "PackageOriginator": (Package, "originator"), "PackageDescription": (Package, "description"), + "FileName": (File, "name"), + "FileType": (File, "file_type"), + "FileChecksum": (File, "checksums"), + "FileNotice": (File, "notice"), + "FileCopyrightText": (File, "copyright_text"), + "LicenseComments": (File, "license_comment"), + "FileComment": (File, "comment"), + "LicenseConcluded": (File, "license_concluded"), + "LicenseDeclared": (File, "license_declared"), + "PackageName": (Package, "name"), + "PackageComment": (Package, "comment"), + "PackageCopyrightText": (Package, "copyright_text"), + "PackageLicenseComments": (Package, "license_comment"), + "PackageLicenseDeclared": (Package, "license_declared"), + "PackageLicenseConcluded": (Package, "license_concluded"), + "PackageFileName": (Package, "file_name"), + "PackageVersion": (Package, "version"), + "PackageDownloadLocation": (Package, "download_location"), + "PackageSummary": (Package, "summary"), + "PackageSourceInfo": (Package, "source_info"), + "PackageSupplier": (Package, "supplier"), + "PackageOriginator": (Package, "originator"), + "PackageDescription": (Package, "description"), "PackageHomePage": (Package, "homepage"), - "SnippetSPDXID": (Snippet, "spdx_id"), "SnippetFromFileSPDXID": (Snippet, "file_spdx_id"), + "SnippetSPDXID": (Snippet, "spdx_id"), + "SnippetFromFileSPDXID": (Snippet, "file_spdx_id"), "SnippetName": (Snippet, "name"), - "SnippetComment": (Snippet, "comment"), "SnippetCopyrightText": (Snippet, "copyright_text"), - "SnippetLicenseComments": (Snippet, "license_comment"), "SnippetLicenseConcluded": (Snippet, "license_concluded"), - "SnippetByteRange": (Snippet, "byte_range"), "SnippetLineRange": (Snippet, "line_range"), + "SnippetComment": (Snippet, "comment"), + "SnippetCopyrightText": (Snippet, "copyright_text"), + "SnippetLicenseComments": (Snippet, "license_comment"), + "SnippetLicenseConcluded": (Snippet, "license_concluded"), + "SnippetByteRange": (Snippet, "byte_range"), + "SnippetLineRange": (Snippet, "line_range"), "Annotator": (Annotation, "annotator"), - "SPDXREF": (Annotation, "spdx_id"), "AnnotationComment": (Annotation, "annotation_comment"), - "LicenseID": (ExtractedLicensingInfo, "license_id"), "ExtractedText": (ExtractedLicensingInfo, "extracted_text"), - "LicenseComment": (ExtractedLicensingInfo, "comment"), "LicenseName": (ExtractedLicensingInfo, "license_name") + "SPDXREF": (Annotation, "spdx_id"), + "AnnotationComment": (Annotation, "annotation_comment"), + "LicenseID": (ExtractedLicensingInfo, "license_id"), + "ExtractedText": (ExtractedLicensingInfo, "extracted_text"), + "LicenseComment": (ExtractedLicensingInfo, "comment"), + "LicenseName": (ExtractedLicensingInfo, "license_name"), } diff --git a/src/spdx/parser/tagvalue/lexer.py b/src/spdx/parser/tagvalue/lexer.py index 8a103833f..7556267b7 100644 --- a/src/spdx/parser/tagvalue/lexer.py +++ b/src/spdx/parser/tagvalue/lexer.py @@ -97,20 +97,20 @@ class SPDXLexer: "SnippetLineRange": "SNIPPET_LINE_RANGE", # Common fields "NOASSERTION": "NO_ASSERTION", - "NONE": "NONE" + "NONE": "NONE", } states = (("text", "exclusive"),) tokens = [ - "TEXT", - "TOOL_VALUE", - "UNKNOWN_TAG", - "ORGANIZATION_VALUE", - "PERSON_VALUE", - "ISO8601_DATE", - "LINE", - "CHECKSUM" - ] + list(reserved.values()) + "TEXT", + "TOOL_VALUE", + "UNKNOWN_TAG", + "ORGANIZATION_VALUE", + "PERSON_VALUE", + "ISO8601_DATE", + "LINE", + "CHECKSUM", + ] + list(reserved.values()) def __init__(self): self.lexer = None @@ -123,7 +123,7 @@ def t_text(self, t): @TOKEN(r"\s*") def t_text_end(self, t): t.type = "TEXT" - t.value = t.lexer.lexdata[t.lexer.text_start: t.lexer.lexpos] + t.value = t.lexer.lexdata[t.lexer.text_start : t.lexer.lexpos] t.lexer.lineno += t.value.count("\n") t.value = t.value.strip() t.lexer.begin("INITIAL") @@ -137,7 +137,9 @@ def t_text_error(self, t): print("Lexer error in text state") @TOKEN( - r":\s*(ADLER32|BLAKE2b-256|BLAKE2b-384|BLAKE2b-512|BLAKE3|MD2|MD4|MD5|MD6|SHA1|SHA224|SHA256|SHA384|SHA512|SHA3-256|SHA3-384|SHA3-512):\s*([a-f0-9]*)") + r":\s*(ADLER32|BLAKE2b-256|BLAKE2b-384|BLAKE2b-512|BLAKE3|MD2|MD4|MD5|MD6|SHA1|SHA224|SHA256|SHA384|SHA512|" + r"SHA3-256|SHA3-384|SHA3-512):\s*([a-f0-9]*)" + ) def t_CHECKSUM(self, t): t.value = t.value[1:].strip() return t diff --git a/src/spdx/parser/tagvalue/parser.py b/src/spdx/parser/tagvalue/parser.py index 9ee5a3ad8..8f4ec2790 100644 --- a/src/spdx/parser/tagvalue/parser.py +++ b/src/spdx/parser/tagvalue/parser.py @@ -11,20 +11,25 @@ # limitations under the License. import re -from typing import Any, List, Dict +from typing import Any, Dict, List from license_expression import get_spdx_licensing from ply import yacc from ply.yacc import LRParser from spdx.datetime_conversions import datetime_from_str -from spdx.model.annotation import AnnotationType, Annotation -from spdx.model.document import Document, CreationInfo +from spdx.model.annotation import Annotation, AnnotationType +from spdx.model.document import CreationInfo, Document from spdx.model.external_document_ref import ExternalDocumentRef from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.model.file import File, FileType -from spdx.model.package import Package, PackageVerificationCode, PackagePurpose, ExternalPackageRef, \ - ExternalPackageRefCategory +from spdx.model.package import ( + ExternalPackageRef, + ExternalPackageRefCategory, + Package, + PackagePurpose, + PackageVerificationCode, +) from spdx.model.relationship import Relationship, RelationshipType from spdx.model.snippet import Snippet from spdx.model.spdx_no_assertion import SpdxNoAssertion @@ -34,14 +39,31 @@ from spdx.parser.error import SPDXParsingError from spdx.parser.logger import Logger from spdx.parser.parsing_functions import construct_or_raise_parsing_error, raise_parsing_error_if_logger_has_messages +from spdx.parser.tagvalue.helper_methods import ( + TAG_DATA_MODEL_FIELD, + grammar_rule, + parse_checksum, + set_value, + str_from_text, +) from spdx.parser.tagvalue.lexer import SPDXLexer -from spdx.parser.tagvalue.helper_methods import grammar_rule, str_from_text, parse_checksum, set_value, \ - TAG_DATA_MODEL_FIELD -CLASS_MAPPING = dict(File="files", Annotation="annotations", Relationship="relationships", Snippet="snippets", - Package="packages", ExtractedLicensingInfo="extracted_licensing_info") -ELEMENT_EXPECTED_START_TAG = dict(File="FileName", Annotation="Annotator", Relationship="Relationship", - Snippet="SnippetSPDXID", Package="PackageName", ExtractedLicensingInfo="LicenseID") +CLASS_MAPPING = dict( + File="files", + Annotation="annotations", + Relationship="relationships", + Snippet="snippets", + Package="packages", + ExtractedLicensingInfo="extracted_licensing_info", +) +ELEMENT_EXPECTED_START_TAG = dict( + File="FileName", + Annotation="Annotator", + Relationship="Relationship", + Snippet="SnippetSPDXID", + Package="PackageName", + ExtractedLicensingInfo="LicenseID", +) class Parser: @@ -74,7 +96,7 @@ def p_start_attrib(self, p): @grammar_rule( "attrib : spdx_version\n| spdx_id\n| data_license\n| doc_name\n| document_comment\n| document_namespace\n| " "creator\n| created\n| creator_comment\n| license_list_version\n| ext_doc_ref\n" - # attributes for file + # attributes for file "| file_name\n| file_type\n| file_checksum\n| file_license_concluded\n| file_license_info\n" "| file_copyright_text\n| file_license_comment\n| file_attribution_text\n| file_notice\n| file_comment\n" "| file_contributor\n" @@ -94,83 +116,91 @@ def p_start_attrib(self, p): "| pkg_external_ref\n| primary_package_purpose\n| built_date\n| release_date\n| valid_until_date\n" # attributes for extracted licensing info "| license_id\n| extracted_text\n| license_name\n| license_cross_ref\n| lic_comment\n" - "| unknown_tag ") + "| unknown_tag " + ) def p_attrib(self, p): pass # general parsing methods - @grammar_rule("license_id : LICENSE_ID error\n license_cross_ref : LICENSE_CROSS_REF error\n " - "lic_comment : LICENSE_COMMENT error\n license_name : LICENSE_NAME error\n " - "extracted_text : LICENSE_TEXT error\n " - "file_name : FILE_NAME error\n file_contributor : FILE_CONTRIBUTOR error\n " - "file_notice : FILE_NOTICE error\n file_copyright_text : FILE_COPYRIGHT_TEXT error\n " - "file_license_comment : FILE_LICENSE_COMMENT error\n " - "file_license_info : FILE_LICENSE_INFO error\n file_comment : FILE_COMMENT error\n " - "file_checksum : FILE_CHECKSUM error\n file_license_concluded : FILE_LICENSE_CONCLUDED error\n " - "file_type : FILE_TYPE error\n file_attribution_text : FILE_ATTRIBUTION_TEXT error\n " - "package_name : PKG_NAME error\n pkg_attribution_text : PKG_ATTRIBUTION_TEXT error\n " - "description : PKG_DESCRIPTION error\n pkg_comment : PKG_COMMENT error\n " - "summary : PKG_SUMMARY error\n pkg_copyright_text : PKG_COPYRIGHT_TEXT error\n " - "pkg_external_ref : PKG_EXTERNAL_REF error\n pkg_license_comment : PKG_LICENSE_COMMENT error\n " - "pkg_license_declared : PKG_LICENSE_DECLARED error\n pkg_license_info : PKG_LICENSE_INFO error \n " - "pkg_license_concluded : PKG_LICENSE_CONCLUDED error\n source_info : PKG_SOURCE_INFO error\n " - "homepage : PKG_HOMEPAGE error\n pkg_checksum : PKG_CHECKSUM error\n " - "verification_code : PKG_VERIFICATION_CODE error\n originator : PKG_ORIGINATOR error\n " - "download_location : PKG_DOWNLOAD_LOCATION error\n files_analyzed : PKG_FILES_ANALYZED error\n " - "supplier : PKG_SUPPLIER error\n pkg_file_name : PKG_FILE_NAME error\n " - "package_version : PKG_VERSION error\n primary_package_purpose : PRIMARY_PACKAGE_PURPOSE error\n " - "built_date : BUILT_DATE error\n release_date : RELEASE_DATE error\n " - "valid_until_date : VALID_UNTIL_DATE error\n snippet_spdx_id : SNIPPET_SPDX_ID error\n " - "snippet_name : SNIPPET_NAME error\n snippet_comment : SNIPPET_COMMENT error\n " - "snippet_attribution_text : SNIPPET_ATTRIBUTION_TEXT error\n " - "snippet_copyright_text : SNIPPET_COPYRIGHT_TEXT error\n " - "snippet_license_comment : SNIPPET_LICENSE_COMMENT error\n file_spdx_id : SNIPPET_FILE_SPDXID error\n " - "snippet_license_concluded : SNIPPET_LICENSE_CONCLUDED error\n " - "snippet_license_info : SNIPPET_LICENSE_INFO error\n " - "snippet_byte_range : SNIPPET_BYTE_RANGE error\n snippet_line_range : SNIPPET_LINE_RANGE error\n " - "annotator : ANNOTATOR error\n annotation_date : ANNOTATION_DATE error\n " - "annotation_comment : ANNOTATION_COMMENT error\n annotation_type : ANNOTATION_TYPE error\n " - "annotation_spdx_id : ANNOTATION_SPDX_ID error\n relationship : RELATIONSHIP error") + @grammar_rule( + "license_id : LICENSE_ID error\n license_cross_ref : LICENSE_CROSS_REF error\n " + "lic_comment : LICENSE_COMMENT error\n license_name : LICENSE_NAME error\n " + "extracted_text : LICENSE_TEXT error\n " + "file_name : FILE_NAME error\n file_contributor : FILE_CONTRIBUTOR error\n " + "file_notice : FILE_NOTICE error\n file_copyright_text : FILE_COPYRIGHT_TEXT error\n " + "file_license_comment : FILE_LICENSE_COMMENT error\n " + "file_license_info : FILE_LICENSE_INFO error\n file_comment : FILE_COMMENT error\n " + "file_checksum : FILE_CHECKSUM error\n file_license_concluded : FILE_LICENSE_CONCLUDED error\n " + "file_type : FILE_TYPE error\n file_attribution_text : FILE_ATTRIBUTION_TEXT error\n " + "package_name : PKG_NAME error\n pkg_attribution_text : PKG_ATTRIBUTION_TEXT error\n " + "description : PKG_DESCRIPTION error\n pkg_comment : PKG_COMMENT error\n " + "summary : PKG_SUMMARY error\n pkg_copyright_text : PKG_COPYRIGHT_TEXT error\n " + "pkg_external_ref : PKG_EXTERNAL_REF error\n pkg_license_comment : PKG_LICENSE_COMMENT error\n " + "pkg_license_declared : PKG_LICENSE_DECLARED error\n pkg_license_info : PKG_LICENSE_INFO error \n " + "pkg_license_concluded : PKG_LICENSE_CONCLUDED error\n source_info : PKG_SOURCE_INFO error\n " + "homepage : PKG_HOMEPAGE error\n pkg_checksum : PKG_CHECKSUM error\n " + "verification_code : PKG_VERIFICATION_CODE error\n originator : PKG_ORIGINATOR error\n " + "download_location : PKG_DOWNLOAD_LOCATION error\n files_analyzed : PKG_FILES_ANALYZED error\n " + "supplier : PKG_SUPPLIER error\n pkg_file_name : PKG_FILE_NAME error\n " + "package_version : PKG_VERSION error\n primary_package_purpose : PRIMARY_PACKAGE_PURPOSE error\n " + "built_date : BUILT_DATE error\n release_date : RELEASE_DATE error\n " + "valid_until_date : VALID_UNTIL_DATE error\n snippet_spdx_id : SNIPPET_SPDX_ID error\n " + "snippet_name : SNIPPET_NAME error\n snippet_comment : SNIPPET_COMMENT error\n " + "snippet_attribution_text : SNIPPET_ATTRIBUTION_TEXT error\n " + "snippet_copyright_text : SNIPPET_COPYRIGHT_TEXT error\n " + "snippet_license_comment : SNIPPET_LICENSE_COMMENT error\n file_spdx_id : SNIPPET_FILE_SPDXID error\n " + "snippet_license_concluded : SNIPPET_LICENSE_CONCLUDED error\n " + "snippet_license_info : SNIPPET_LICENSE_INFO error\n " + "snippet_byte_range : SNIPPET_BYTE_RANGE error\n snippet_line_range : SNIPPET_LINE_RANGE error\n " + "annotator : ANNOTATOR error\n annotation_date : ANNOTATION_DATE error\n " + "annotation_comment : ANNOTATION_COMMENT error\n annotation_type : ANNOTATION_TYPE error\n " + "annotation_spdx_id : ANNOTATION_SPDX_ID error\n relationship : RELATIONSHIP error" + ) def p_current_element_error(self, p): if p[1] in ELEMENT_EXPECTED_START_TAG.values(): self.initialize_new_current_element(TAG_DATA_MODEL_FIELD[p[1]][0]) self.current_element["logger"].append( - f"Error while parsing {p[1]}: Token did not match specified grammar rule. Line: {p.lineno(1)}") - - @grammar_rule("license_name : LICENSE_NAME line_or_no_assertion\n extracted_text : LICENSE_TEXT text_or_line\n " - "lic_comment : LICENSE_COMMENT text_or_line\n license_id : LICENSE_ID LINE\n " - "file_name : FILE_NAME LINE \n file_notice : FILE_NOTICE text_or_line\n " - "file_copyright_text : FILE_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " - "file_license_comment : FILE_LICENSE_COMMENT text_or_line\n " - "file_comment : FILE_COMMENT text_or_line\n " - "file_license_concluded : FILE_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " - "package_name : PKG_NAME LINE\n description : PKG_DESCRIPTION text_or_line\n " - "summary : PKG_SUMMARY text_or_line\n source_info : PKG_SOURCE_INFO text_or_line\n " - "homepage : PKG_HOMEPAGE line_or_no_assertion_or_none\n " - "download_location : PKG_DOWNLOAD_LOCATION line_or_no_assertion_or_none\n " - "originator : PKG_ORIGINATOR actor_or_no_assertion\n supplier : PKG_SUPPLIER actor_or_no_assertion\n " - "pkg_comment : PKG_COMMENT text_or_line\n " - "pkg_copyright_text : PKG_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " - "pkg_license_declared : PKG_LICENSE_DECLARED license_or_no_assertion_or_none\n " - "pkg_file_name : PKG_FILE_NAME LINE\n " - "pkg_license_concluded : PKG_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " - "package_version : PKG_VERSION LINE\n pkg_license_comment : PKG_LICENSE_COMMENT text_or_line\n " - "snippet_spdx_id : SNIPPET_SPDX_ID LINE\n snippet_name : SNIPPET_NAME LINE\n " - "snippet_comment : SNIPPET_COMMENT text_or_line\n " - "snippet_copyright_text : SNIPPET_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " - "snippet_license_comment : SNIPPET_LICENSE_COMMENT text_or_line\n " - "file_spdx_id : SNIPPET_FILE_SPDXID LINE\n " - "snippet_license_concluded : SNIPPET_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " - "annotation_spdx_id : ANNOTATION_SPDX_ID LINE\n " - "annotation_comment : ANNOTATION_COMMENT text_or_line") + f"Error while parsing {p[1]}: Token did not match specified grammar rule. Line: {p.lineno(1)}" + ) + + @grammar_rule( + "license_name : LICENSE_NAME line_or_no_assertion\n extracted_text : LICENSE_TEXT text_or_line\n " + "lic_comment : LICENSE_COMMENT text_or_line\n license_id : LICENSE_ID LINE\n " + "file_name : FILE_NAME LINE \n file_notice : FILE_NOTICE text_or_line\n " + "file_copyright_text : FILE_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " + "file_license_comment : FILE_LICENSE_COMMENT text_or_line\n " + "file_comment : FILE_COMMENT text_or_line\n " + "file_license_concluded : FILE_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " + "package_name : PKG_NAME LINE\n description : PKG_DESCRIPTION text_or_line\n " + "summary : PKG_SUMMARY text_or_line\n source_info : PKG_SOURCE_INFO text_or_line\n " + "homepage : PKG_HOMEPAGE line_or_no_assertion_or_none\n " + "download_location : PKG_DOWNLOAD_LOCATION line_or_no_assertion_or_none\n " + "originator : PKG_ORIGINATOR actor_or_no_assertion\n supplier : PKG_SUPPLIER actor_or_no_assertion\n " + "pkg_comment : PKG_COMMENT text_or_line\n " + "pkg_copyright_text : PKG_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " + "pkg_license_declared : PKG_LICENSE_DECLARED license_or_no_assertion_or_none\n " + "pkg_file_name : PKG_FILE_NAME LINE\n " + "pkg_license_concluded : PKG_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " + "package_version : PKG_VERSION LINE\n pkg_license_comment : PKG_LICENSE_COMMENT text_or_line\n " + "snippet_spdx_id : SNIPPET_SPDX_ID LINE\n snippet_name : SNIPPET_NAME LINE\n " + "snippet_comment : SNIPPET_COMMENT text_or_line\n " + "snippet_copyright_text : SNIPPET_COPYRIGHT_TEXT line_or_no_assertion_or_none\n " + "snippet_license_comment : SNIPPET_LICENSE_COMMENT text_or_line\n " + "file_spdx_id : SNIPPET_FILE_SPDXID LINE\n " + "snippet_license_concluded : SNIPPET_LICENSE_CONCLUDED license_or_no_assertion_or_none\n " + "annotation_spdx_id : ANNOTATION_SPDX_ID LINE\n " + "annotation_comment : ANNOTATION_COMMENT text_or_line" + ) def p_generic_value(self, p): if p[1] in ELEMENT_EXPECTED_START_TAG.values(): self.initialize_new_current_element(TAG_DATA_MODEL_FIELD[p[1]][0]) if self.check_that_current_element_matches_class_for_value(TAG_DATA_MODEL_FIELD[p[1]][0], p.lineno(1)): set_value(p, self.current_element) - @grammar_rule("unknown_tag : UNKNOWN_TAG text_or_line\n | UNKNOWN_TAG ISO8601_DATE\n | UNKNOWN_TAG PERSON_VALUE \n" - "| UNKNOWN_TAG") + @grammar_rule( + "unknown_tag : UNKNOWN_TAG text_or_line\n | UNKNOWN_TAG ISO8601_DATE\n | UNKNOWN_TAG PERSON_VALUE \n" + "| UNKNOWN_TAG" + ) def p_unknown_tag(self, p): self.logger.append(f"Unknown tag provided in line {p.lineno(1)}") @@ -182,8 +212,10 @@ def p_text(self, p): def p_line(self, p): p[0] = p[1] - @grammar_rule("license_or_no_assertion_or_none : NO_ASSERTION\n actor_or_no_assertion : NO_ASSERTION\n" - "line_or_no_assertion : NO_ASSERTION\n line_or_no_assertion_or_none : NO_ASSERTION") + @grammar_rule( + "license_or_no_assertion_or_none : NO_ASSERTION\n actor_or_no_assertion : NO_ASSERTION\n" + "line_or_no_assertion : NO_ASSERTION\n line_or_no_assertion_or_none : NO_ASSERTION" + ) def p_no_assertion(self, p): p[0] = SpdxNoAssertion() @@ -211,17 +243,22 @@ def p_spdx_id(self, p): # parsing methods for creation info / document level - @grammar_rule("license_list_version : LICENSE_LIST_VERSION error\n document_comment : DOC_COMMENT error\n " - "document_namespace : DOC_NAMESPACE error\n data_license : DOC_LICENSE error\n " - "doc_name : DOC_NAME error\n ext_doc_ref : EXT_DOC_REF error\n spdx_version : DOC_VERSION error\n " - "creator_comment : CREATOR_COMMENT error\n creator : CREATOR error\n created : CREATED error") + @grammar_rule( + "license_list_version : LICENSE_LIST_VERSION error\n document_comment : DOC_COMMENT error\n " + "document_namespace : DOC_NAMESPACE error\n data_license : DOC_LICENSE error\n " + "doc_name : DOC_NAME error\n ext_doc_ref : EXT_DOC_REF error\n spdx_version : DOC_VERSION error\n " + "creator_comment : CREATOR_COMMENT error\n creator : CREATOR error\n created : CREATED error" + ) def p_creation_info_value_error(self, p): self.creation_info["logger"].append( - f"Error while parsing {p[1]}: Token did not match specified grammar rule. Line: {p.lineno(1)}") + f"Error while parsing {p[1]}: Token did not match specified grammar rule. Line: {p.lineno(1)}" + ) - @grammar_rule("document_comment : DOC_COMMENT text_or_line\n document_namespace : DOC_NAMESPACE LINE\n " - "data_license : DOC_LICENSE LINE\n spdx_version : DOC_VERSION LINE\n " - "creator_comment : CREATOR_COMMENT text_or_line\n doc_name : DOC_NAME LINE") + @grammar_rule( + "document_comment : DOC_COMMENT text_or_line\n document_namespace : DOC_NAMESPACE LINE\n " + "data_license : DOC_LICENSE LINE\n spdx_version : DOC_VERSION LINE\n " + "creator_comment : CREATOR_COMMENT text_or_line\n doc_name : DOC_NAME LINE" + ) def p_generic_value_creation_info(self, p): set_value(p, self.creation_info) @@ -235,14 +272,16 @@ def p_external_document_ref(self, p): external_doc_ref_match = external_doc_ref_regex.match(p[2]) if not external_doc_ref_match: self.creation_info["logger"].append( - f"Error while parsing ExternalDocumentRef: Couldn\'t match Checksum. Line: {p.lineno(1)}") + f"Error while parsing ExternalDocumentRef: Couldn't match Checksum. Line: {p.lineno(1)}" + ) return try: document_ref_id, document_uri = external_doc_ref_match.group(1).strip().split(" ") except ValueError: self.creation_info["logger"].append( f"Error while parsing ExternalDocumentRef: Couldn't split the first part of the value into " - f"document_ref_id and document_uri. Line: {p.lineno(1)}") + f"document_ref_id and document_uri. Line: {p.lineno(1)}" + ) return checksum = parse_checksum(external_doc_ref_match.group(2).strip()) external_document_ref = ExternalDocumentRef(document_ref_id, document_uri, checksum) @@ -306,7 +345,8 @@ def p_pkg_attribution_text(self, p): self.current_element.setdefault("attribution_texts", []).append(p[2]) @grammar_rule( - "pkg_external_ref : PKG_EXTERNAL_REF LINE PKG_EXTERNAL_REF_COMMENT text_or_line\n | PKG_EXTERNAL_REF LINE") + "pkg_external_ref : PKG_EXTERNAL_REF LINE PKG_EXTERNAL_REF_COMMENT text_or_line\n | PKG_EXTERNAL_REF LINE" + ) def p_pkg_external_refs(self, p): if not self.check_that_current_element_matches_class_for_value(Package, p.lineno(1)): return @@ -314,7 +354,8 @@ def p_pkg_external_refs(self, p): category, reference_type, locator = p[2].split(" ") except ValueError: self.current_element["logger"].append( - f"Couldn't split PackageExternalRef in category, reference_type and locator. Line: {p.lineno(1)}") + f"Couldn't split PackageExternalRef in category, reference_type and locator. Line: {p.lineno(1)}" + ) return comment = None if len(p) == 5: @@ -323,14 +364,14 @@ def p_pkg_external_refs(self, p): category = ExternalPackageRefCategory[category.replace("-", "_")] except KeyError: self.current_element["logger"].append( - f"Invalid ExternalPackageRefCategory: {category}. Line: {p.lineno(1)}") + f"Invalid ExternalPackageRefCategory: {category}. Line: {p.lineno(1)}" + ) return try: - external_package_ref = construct_or_raise_parsing_error(ExternalPackageRef, - {"category": category, - "reference_type": reference_type, - "locator": locator, - "comment": comment}) + external_package_ref = construct_or_raise_parsing_error( + ExternalPackageRef, + {"category": category, "reference_type": reference_type, "locator": locator, "comment": comment}, + ) except SPDXParsingError as err: self.current_element["logger"].append(err.get_messages()) return @@ -362,7 +403,8 @@ def p_pkg_verification_code(self, p): match = verif_code_regex.match(p[2]) if not match: self.current_element["logger"].append( - f"Error while parsing {p[1]}: Value did not match expected format. Line: {p.lineno(1)}") + f"Error while parsing {p[1]}: Value did not match expected format. Line: {p.lineno(1)}" + ) return value = match.group(verif_code_code_grp) excluded_files = None @@ -377,15 +419,17 @@ def p_pkg_files_analyzed(self, p): if "files_analyzed" in self.current_element: self.current_element["logger"].append(f"Multiple values for {p[1]} found. Line: {p.lineno(1)}") return - self.current_element["files_analyzed"] = p[2] in ['true', 'True'] + self.current_element["files_analyzed"] = p[2] in ["true", "True"] @grammar_rule("primary_package_purpose : PRIMARY_PACKAGE_PURPOSE LINE") def p_primary_package_purpose(self, p): if self.check_that_current_element_matches_class_for_value(Package, p.lineno(1)): set_value(p, self.current_element, method_to_apply=lambda x: PackagePurpose[x.replace("-", "_")]) - @grammar_rule("built_date : BUILT_DATE ISO8601_DATE\n release_date : RELEASE_DATE ISO8601_DATE\n " - "valid_until_date : VALID_UNTIL_DATE ISO8601_DATE") + @grammar_rule( + "built_date : BUILT_DATE ISO8601_DATE\n release_date : RELEASE_DATE ISO8601_DATE\n " + "valid_until_date : VALID_UNTIL_DATE ISO8601_DATE" + ) def p_package_dates(self, p): if self.check_that_current_element_matches_class_for_value(Package, p.lineno(1)): set_value(p, self.current_element, method_to_apply=datetime_from_str) @@ -409,13 +453,13 @@ def p_snippet_range(self, p): argument_name = TAG_DATA_MODEL_FIELD[p[1]][1] if argument_name in self.current_element: - self.current_element["logger"].append( - f"Multiple values for {p[1]} found. Line: {p.lineno(1)}") + self.current_element["logger"].append(f"Multiple values for {p[1]} found. Line: {p.lineno(1)}") return range_re = re.compile(r"^(\d+):(\d+)$", re.UNICODE) if not range_re.match(p[2].strip()): - self.current_element["logger"].append(f"Value for {p[1]} doesn't match valid range pattern. " - f"Line: {p.lineno(1)}") + self.current_element["logger"].append( + f"Value for {p[1]} doesn't match valid range pattern. " f"Line: {p.lineno(1)}" + ) return startpoint = int(p[2].split(":")[0]) endpoint = int(p[2].split(":")[-1]) @@ -440,8 +484,7 @@ def p_annotation_type(self, p): # parsing methods for relationship - @grammar_rule("relationship : RELATIONSHIP LINE RELATIONSHIP_COMMENT text_or_line\n " - "| RELATIONSHIP LINE") + @grammar_rule("relationship : RELATIONSHIP LINE RELATIONSHIP_COMMENT text_or_line\n " "| RELATIONSHIP LINE") def p_relationship(self, p): self.initialize_new_current_element(Relationship) try: @@ -449,7 +492,8 @@ def p_relationship(self, p): except ValueError: self.current_element["logger"].append( f"Relationship couldn't be split in spdx_element_id, relationship_type and " - f"related_spdx_element. Line: {p.lineno(1)}") + f"related_spdx_element. Line: {p.lineno(1)}" + ) return try: self.current_element["relationship_type"] = RelationshipType[relationship_type] @@ -497,7 +541,8 @@ def check_that_current_element_matches_class_for_value(self, expected_class, lin self.logger.append( f"Element {expected_class.__name__} is not the current element in scope, probably the expected tag to " f"start the element ({ELEMENT_EXPECTED_START_TAG[expected_class.__name__]}) is missing. " - f"Line: {line_number}") + f"Line: {line_number}" + ) return False return True @@ -511,7 +556,8 @@ def construct_current_element(self): try: raise_parsing_error_if_logger_has_messages(self.current_element.pop("logger"), clazz.__name__) self.elements_built.setdefault(CLASS_MAPPING[clazz.__name__], []).append( - construct_or_raise_parsing_error(clazz, self.current_element)) + construct_or_raise_parsing_error(clazz, self.current_element) + ) if clazz == File: self.check_for_preceding_package_and_build_contains_relationship() except SPDXParsingError as err: diff --git a/src/spdx/parser/xml/xml_parser.py b/src/spdx/parser/xml/xml_parser.py index ccccd15d3..9f9189a45 100644 --- a/src/spdx/parser/xml/xml_parser.py +++ b/src/spdx/parser/xml/xml_parser.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Any +from typing import Any, Dict import xmltodict @@ -16,7 +16,6 @@ from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser - LIST_LIKE_FIELDS = [ "creators", "externalDocumentRefs", @@ -41,8 +40,8 @@ "ranges", "licenseInfoInSnippets", "packageVerificationCodeExcludedFiles", - "attributionTexts" - ] + "attributionTexts", +] def parse_from_file(file_name: str) -> Document: diff --git a/src/spdx/validation/actor_validator.py b/src/spdx/validation/actor_validator.py index 033d2e94c..192b95774 100644 --- a/src/spdx/validation/actor_validator.py +++ b/src/spdx/validation/actor_validator.py @@ -12,7 +12,7 @@ from typing import List from spdx.model.actor import Actor, ActorType -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_actors(actors: List[Actor], parent_id: str) -> List[ValidationMessage]: @@ -30,7 +30,7 @@ def validate_actor(actor: Actor, parent_id: str) -> List[ValidationMessage]: validation_messages.append( ValidationMessage( f"email must be None if actor_type is TOOL, but is: {actor.email}", - ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor) + ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor), ) ) diff --git a/src/spdx/validation/annotation_validator.py b/src/spdx/validation/annotation_validator.py index 407b2f7b5..e162f2d1c 100644 --- a/src/spdx/validation/annotation_validator.py +++ b/src/spdx/validation/annotation_validator.py @@ -15,7 +15,7 @@ from spdx.model.document import Document from spdx.validation.actor_validator import validate_actor from spdx.validation.spdx_id_validators import validate_spdx_id -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_annotations(annotations: List[Annotation], document: Document) -> List[ValidationMessage]: @@ -28,8 +28,7 @@ def validate_annotations(annotations: List[Annotation], document: Document) -> L def validate_annotation(annotation: Annotation, document: Document) -> List[ValidationMessage]: validation_messages = [] - context = ValidationContext(element_type=SpdxElementType.ANNOTATION, - full_element=annotation) + context = ValidationContext(element_type=SpdxElementType.ANNOTATION, full_element=annotation) validation_messages.extend(validate_actor(annotation.annotator, "annotation")) diff --git a/src/spdx/validation/checksum_validator.py b/src/spdx/validation/checksum_validator.py index 1f4830336..f34cc0a2e 100644 --- a/src/spdx/validation/checksum_validator.py +++ b/src/spdx/validation/checksum_validator.py @@ -10,10 +10,10 @@ # limitations under the License. import re -from typing import List, Dict +from typing import Dict, List from spdx.model.checksum import Checksum, ChecksumAlgorithm -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage # in hexadecimal digits algorithm_length: Dict = { @@ -48,17 +48,18 @@ def validate_checksums(checksums: List[Checksum], parent_id: str, spdx_version: def validate_checksum(checksum: Checksum, parent_id: str, spdx_version: str) -> List[ValidationMessage]: validation_messages = [] algorithm = checksum.algorithm - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, - full_element=checksum) + context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, full_element=checksum) - if spdx_version == "SPDX-2.2" and algorithm in [ChecksumAlgorithm.SHA3_512, - ChecksumAlgorithm.SHA3_384, - ChecksumAlgorithm.SHA3_256, - ChecksumAlgorithm.BLAKE3, - ChecksumAlgorithm.BLAKE2B_512, - ChecksumAlgorithm.BLAKE2B_384, - ChecksumAlgorithm.BLAKE2B_256, - ChecksumAlgorithm.ADLER32]: + if spdx_version == "SPDX-2.2" and algorithm in [ + ChecksumAlgorithm.SHA3_512, + ChecksumAlgorithm.SHA3_384, + ChecksumAlgorithm.SHA3_256, + ChecksumAlgorithm.BLAKE3, + ChecksumAlgorithm.BLAKE2B_512, + ChecksumAlgorithm.BLAKE2B_384, + ChecksumAlgorithm.BLAKE2B_256, + ChecksumAlgorithm.ADLER32, + ]: return [ValidationMessage(f"{checksum.algorithm.name} is not supported in SPDX-2.2", context)] if not re.match("^[0-9a-f]{" + algorithm_length[algorithm] + "}$", checksum.value): @@ -70,8 +71,10 @@ def validate_checksum(checksum: Checksum, parent_id: str, spdx_version: str) -> length = algorithm_length[algorithm] validation_messages.append( ValidationMessage( - f"value of {algorithm} must consist of {length} lowercase hexadecimal digits, but is: {checksum.value} (length: {len(checksum.value)} digits)", - context) + f"value of {algorithm} must consist of {length} lowercase hexadecimal digits, but is: " + f"{checksum.value} (length: {len(checksum.value)} digits)", + context, + ) ) return validation_messages diff --git a/src/spdx/validation/creation_info_validator.py b/src/spdx/validation/creation_info_validator.py index 3511e1d89..a73e98635 100644 --- a/src/spdx/validation/creation_info_validator.py +++ b/src/spdx/validation/creation_info_validator.py @@ -15,7 +15,7 @@ from spdx.validation.actor_validator import validate_actors from spdx.validation.external_document_ref_validator import validate_external_document_refs from spdx.validation.uri_validators import validate_uri -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_creation_info(creation_info: CreationInfo, spdx_version: str) -> List[ValidationMessage]: @@ -25,29 +25,20 @@ def validate_creation_info(creation_info: CreationInfo, spdx_version: str) -> Li if creation_info.spdx_id != "SPDXRef-DOCUMENT": validation_messages.append( - ValidationMessage( - f'spdx_id must be "SPDXRef-DOCUMENT", but is: {creation_info.spdx_id}', - context - ) + ValidationMessage(f'spdx_id must be "SPDXRef-DOCUMENT", but is: {creation_info.spdx_id}', context) ) if creation_info.data_license != "CC0-1.0": validation_messages.append( - ValidationMessage( - f'data_license must be "CC0-1.0", but is: {creation_info.data_license}', - context - ) + ValidationMessage(f'data_license must be "CC0-1.0", but is: {creation_info.data_license}', context) ) for message in validate_uri(creation_info.document_namespace): - validation_messages.append( - ValidationMessage( - "document_namespace " + message, context - ) - ) + validation_messages.append(ValidationMessage("document_namespace " + message, context)) validation_messages.extend(validate_actors(creation_info.creators, creation_info.spdx_id)) validation_messages.extend( - validate_external_document_refs(creation_info.external_document_refs, creation_info.spdx_id, spdx_version)) + validate_external_document_refs(creation_info.external_document_refs, creation_info.spdx_id, spdx_version) + ) return validation_messages diff --git a/src/spdx/validation/document_validator.py b/src/spdx/validation/document_validator.py index 264e8d400..1446ce1bb 100644 --- a/src/spdx/validation/document_validator.py +++ b/src/spdx/validation/document_validator.py @@ -21,7 +21,7 @@ from spdx.validation.relationship_validator import validate_relationships from spdx.validation.snippet_validator import validate_snippets from spdx.validation.spdx_id_validators import get_list_of_all_spdx_ids -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_full_spdx_document(document: Document, spdx_version: str = None) -> List[ValidationMessage]: @@ -36,20 +36,29 @@ def validate_full_spdx_document(document: Document, spdx_version: str = None) -> if document_version not in ["SPDX-2.2", "SPDX-2.3"]: validation_messages.append( ValidationMessage( - f'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: {document_version}', - context + f'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: ' + f"{document_version}", + context, ) ) elif spdx_version != document_version: validation_messages.append( - ValidationMessage(f"provided SPDX version {spdx_version} does not match " - f"the document's SPDX version {document_version}", context) + ValidationMessage( + f"provided SPDX version {spdx_version} does not match " + f"the document's SPDX version {document_version}", + context, + ) ) if validation_messages: - validation_messages.append(ValidationMessage("There are issues concerning the SPDX version of the document. " - "As subsequent validation relies on the correct version, " - "the validation process has been cancelled.", context)) + validation_messages.append( + ValidationMessage( + "There are issues concerning the SPDX version of the document. " + "As subsequent validation relies on the correct version, " + "the validation process has been cancelled.", + context, + ) + ) return validation_messages validation_messages.extend(validate_creation_info(document.creation_info, spdx_version)) @@ -61,29 +70,35 @@ def validate_full_spdx_document(document: Document, spdx_version: str = None) -> validation_messages.extend(validate_extracted_licensing_infos(document.extracted_licensing_info)) document_id = document.creation_info.spdx_id - document_describes_relationships = filter_by_type_and_origin(document.relationships, RelationshipType.DESCRIBES, - document_id) - described_by_document_relationships = filter_by_type_and_target(document.relationships, - RelationshipType.DESCRIBED_BY, document_id) + document_describes_relationships = filter_by_type_and_origin( + document.relationships, RelationshipType.DESCRIBES, document_id + ) + described_by_document_relationships = filter_by_type_and_target( + document.relationships, RelationshipType.DESCRIBED_BY, document_id + ) if not document_describes_relationships + described_by_document_relationships: validation_messages.append( ValidationMessage( f'there must be at least one relationship "{document_id} DESCRIBES ..." or "... DESCRIBED_BY ' f'{document_id}"', - ValidationContext(spdx_id=document_id, - element_type=SpdxElementType.DOCUMENT))) + ValidationContext(spdx_id=document_id, element_type=SpdxElementType.DOCUMENT), + ) + ) all_spdx_ids: List[str] = get_list_of_all_spdx_ids(document) auxiliary_set = set() duplicated_spdx_ids = set( - spdx_id for spdx_id in all_spdx_ids if spdx_id in auxiliary_set or auxiliary_set.add(spdx_id)) + spdx_id for spdx_id in all_spdx_ids if spdx_id in auxiliary_set or auxiliary_set.add(spdx_id) + ) if duplicated_spdx_ids: validation_messages.append( ValidationMessage( - f"every spdx_id must be unique within the document, but found the following duplicates: {sorted(duplicated_spdx_ids)}", - context) + f"every spdx_id must be unique within the document, but found the following duplicates: " + f"{sorted(duplicated_spdx_ids)}", + context, + ) ) return validation_messages diff --git a/src/spdx/validation/external_document_ref_validator.py b/src/spdx/validation/external_document_ref_validator.py index 99156566b..6cd20d2da 100644 --- a/src/spdx/validation/external_document_ref_validator.py +++ b/src/spdx/validation/external_document_ref_validator.py @@ -15,11 +15,12 @@ from spdx.validation.checksum_validator import validate_checksum from spdx.validation.spdx_id_validators import is_valid_external_doc_ref_id from spdx.validation.uri_validators import validate_uri -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_external_document_refs(external_document_refs: List[ExternalDocumentRef], parent_id: str, - spdx_version: str) -> List[ValidationMessage]: +def validate_external_document_refs( + external_document_refs: List[ExternalDocumentRef], parent_id: str, spdx_version: str +) -> List[ValidationMessage]: validation_messages = [] for external_document_ref in external_document_refs: validation_messages.extend(validate_external_document_ref(external_document_ref, parent_id, spdx_version)) @@ -27,26 +28,25 @@ def validate_external_document_refs(external_document_refs: List[ExternalDocumen return validation_messages -def validate_external_document_ref(external_document_ref: ExternalDocumentRef, parent_id: str, spdx_version: str) -> \ -List[ValidationMessage]: +def validate_external_document_ref( + external_document_ref: ExternalDocumentRef, parent_id: str, spdx_version: str +) -> List[ValidationMessage]: validation_messages = [] - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_DOCUMENT_REF, - full_element=external_document_ref) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_DOCUMENT_REF, full_element=external_document_ref + ) if not is_valid_external_doc_ref_id(external_document_ref.document_ref_id): validation_messages.append( ValidationMessage( - f'document_ref_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: {external_document_ref.document_ref_id}', - context + f'document_ref_id must only contain letters, numbers, ".", "-" and "+" and must begin with ' + f'"DocumentRef-", but is: {external_document_ref.document_ref_id}', + context, ) ) for message in validate_uri(external_document_ref.document_uri): - validation_messages.append( - ValidationMessage( - "document_uri " + message, context - ) - ) + validation_messages.append(ValidationMessage("document_uri " + message, context)) validation_messages.extend(validate_checksum(external_document_ref.checksum, parent_id, spdx_version)) diff --git a/src/spdx/validation/external_package_ref_validator.py b/src/spdx/validation/external_package_ref_validator.py index 07a8f6bc4..8105ec0f6 100644 --- a/src/spdx/validation/external_package_ref_validator.py +++ b/src/spdx/validation/external_package_ref_validator.py @@ -9,23 +9,27 @@ # See the License for the specific language governing permissions and # limitations under the License. import re -from typing import List, Dict +from typing import Dict, List import uritools -from spdx.model.package import ExternalPackageRef, ExternalPackageRefCategory, CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES +from spdx.model.package import CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES, ExternalPackageRef, ExternalPackageRefCategory from spdx.validation.uri_validators import validate_url -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType - -CPE22TYPE_REGEX = r'^c[pP][eE]:/[AHOaho]?(:[A-Za-z0-9._\-~%]*){0,6}$' -CPE23TYPE_REGEX = r'^cpe:2\.3:[aho\*\-](:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&\'\(\)\+,\/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\*\-]))(:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&\'\(\)\+,\/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){4}$' -MAVEN_CENTRAL_REGEX = r'^[^:]+:[^:]+(:[^:]+)?$' -NPM_REGEX = r'^[^@]+@[^@]+$' -NUGET_REGEX = r'^[^/]+/[^/]+$' -BOWER_REGEX = r'^[^#]+#[^#]+$' -PURL_REGEX = r'^pkg:.+(\/.+)?\/.+(@.+)?(\?.+)?(#.+)?$' -SWH_REGEX = r'^swh:1:(snp|rel|rev|dir|cnt):[0-9a-fA-F]{40}$' -GITOID_REGEX = r'^gitoid:(blob|tree|commit|tag):(sha1:[0-9a-fA-F]{40}|sha256:[0-9a-fA-F]{64})$' +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage + +CPE22TYPE_REGEX = r"^c[pP][eE]:/[AHOaho]?(:[A-Za-z0-9._\-~%]*){0,6}$" +CPE23TYPE_REGEX = ( + r'^cpe:2\.3:[aho\*\-](:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&\'\(\)\+,\/:;<=>@\[\]\^' + r"`\{\|}~]))+(\?*|\*?))|[\*\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\*\-]))(:(((\?*" + r'|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&\'\(\)\+,\/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){4}$' +) +MAVEN_CENTRAL_REGEX = r"^[^:]+:[^:]+(:[^:]+)?$" +NPM_REGEX = r"^[^@]+@[^@]+$" +NUGET_REGEX = r"^[^/]+/[^/]+$" +BOWER_REGEX = r"^[^#]+#[^#]+$" +PURL_REGEX = r"^pkg:.+(\/.+)?\/.+(@.+)?(\?.+)?(#.+)?$" +SWH_REGEX = r"^swh:1:(snp|rel|rev|dir|cnt):[0-9a-fA-F]{40}$" +GITOID_REGEX = r"^gitoid:(blob|tree|commit|tag):(sha1:[0-9a-fA-F]{40}|sha256:[0-9a-fA-F]{64})$" TYPE_TO_REGEX: Dict[str, str] = { "cpe22Type": CPE22TYPE_REGEX, @@ -36,12 +40,13 @@ "bower": BOWER_REGEX, "purl": PURL_REGEX, "swh": SWH_REGEX, - "gitoid": GITOID_REGEX + "gitoid": GITOID_REGEX, } -def validate_external_package_refs(external_package_refs: List[ExternalPackageRef], parent_id: str, - spdx_version: str) -> List[ValidationMessage]: +def validate_external_package_refs( + external_package_refs: List[ExternalPackageRef], parent_id: str, spdx_version: str +) -> List[ValidationMessage]: validation_messages = [] for external_package_ref in external_package_refs: validation_messages.extend(validate_external_package_ref(external_package_ref, parent_id, spdx_version)) @@ -49,11 +54,13 @@ def validate_external_package_refs(external_package_refs: List[ExternalPackageRe return validation_messages -def validate_external_package_ref(external_package_ref: ExternalPackageRef, parent_id: str, spdx_version: str) -> List[ - ValidationMessage]: +def validate_external_package_ref( + external_package_ref: ExternalPackageRef, parent_id: str, spdx_version: str +) -> List[ValidationMessage]: validation_messages = [] - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, - full_element=external_package_ref) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, full_element=external_package_ref + ) category = external_package_ref.category locator = external_package_ref.locator @@ -61,29 +68,42 @@ def validate_external_package_ref(external_package_ref: ExternalPackageRef, pare if category == ExternalPackageRefCategory.OTHER: if " " in locator: - validation_messages.append(ValidationMessage( - f"externalPackageRef locator in category OTHER must contain no spaces, but is: {locator}", - context)) + validation_messages.append( + ValidationMessage( + f"externalPackageRef locator in category OTHER must contain no spaces, but is: {locator}", context + ) + ) elif spdx_version == "SPDX-2.2" and reference_type in ["advisory", "fix", "url", "swid"]: return [ValidationMessage(f'externalPackageRef type "{reference_type}" is not supported in SPDX-2.2', context)] elif reference_type not in CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]: - validation_messages.append(ValidationMessage( - f"externalPackageRef type in category {category.name} must be one of {CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]}, but is: {reference_type}", - context)) + validation_messages.append( + ValidationMessage( + f"externalPackageRef type in category {category.name} must be one of " + f"{CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[category]}, but is: {reference_type}", + context, + ) + ) elif reference_type in ["advisory", "fix", "url"]: if validate_url(locator): - validation_messages.append(ValidationMessage( - f'externalPackageRef locator of type "{reference_type}" must be a valid URL, but is: {locator}', - context)) + validation_messages.append( + ValidationMessage( + f'externalPackageRef locator of type "{reference_type}" must be a valid URL, but is: {locator}', + context, + ) + ) elif reference_type == "swid": if not uritools.isuri(locator) or not locator.startswith("swid"): - validation_messages.append(ValidationMessage( - f'externalPackageRef locator of type "swid" must be a valid URI with scheme swid, but is: {locator}', - context)) + validation_messages.append( + ValidationMessage( + f'externalPackageRef locator of type "swid" must be a valid URI with scheme swid, ' + f"but is: {locator}", + context, + ) + ) else: validation_messages.extend(validate_against_regex(locator, reference_type, context)) @@ -91,11 +111,16 @@ def validate_external_package_ref(external_package_ref: ExternalPackageRef, pare return validation_messages -def validate_against_regex(string_to_validate: str, reference_type: str, context: ValidationContext) -> List[ - ValidationMessage]: +def validate_against_regex( + string_to_validate: str, reference_type: str, context: ValidationContext +) -> List[ValidationMessage]: regex = TYPE_TO_REGEX[reference_type] if not re.match(regex, string_to_validate): - return [ValidationMessage( - f'externalPackageRef locator of type "{reference_type}" must conform with the regex {regex}, but is: {string_to_validate}', - context)] + return [ + ValidationMessage( + f'externalPackageRef locator of type "{reference_type}" must conform with the regex {regex}, ' + f"but is: {string_to_validate}", + context, + ) + ] return [] diff --git a/src/spdx/validation/extracted_licensing_info_validator.py b/src/spdx/validation/extracted_licensing_info_validator.py index 8b769e13d..a1def8ae7 100644 --- a/src/spdx/validation/extracted_licensing_info_validator.py +++ b/src/spdx/validation/extracted_licensing_info_validator.py @@ -14,11 +14,12 @@ from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.validation.uri_validators import validate_url -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_extracted_licensing_infos(extracted_licensing_infos: Optional[List[ExtractedLicensingInfo]]) -> List[ - ValidationMessage]: +def validate_extracted_licensing_infos( + extracted_licensing_infos: Optional[List[ExtractedLicensingInfo]], +) -> List[ValidationMessage]: validation_messages = [] for extracted_licensing_info in extracted_licensing_infos: validation_messages.extend(validate_extracted_licensing_info(extracted_licensing_info)) @@ -26,18 +27,20 @@ def validate_extracted_licensing_infos(extracted_licensing_infos: Optional[List[ return validation_messages -def validate_extracted_licensing_info(extracted_licensing_infos: ExtractedLicensingInfo) -> List[ - ValidationMessage]: +def validate_extracted_licensing_info(extracted_licensing_infos: ExtractedLicensingInfo) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] - context = ValidationContext(element_type=SpdxElementType.EXTRACTED_LICENSING_INFO, - full_element=extracted_licensing_infos) + context = ValidationContext( + element_type=SpdxElementType.EXTRACTED_LICENSING_INFO, full_element=extracted_licensing_infos + ) license_id: str = extracted_licensing_infos.license_id if license_id and not re.match(r"^LicenseRef-[\da-zA-Z.-]+$", license_id): validation_messages.append( ValidationMessage( - f'license_id must only contain letters, numbers, "." and "-" and must begin with "LicenseRef-", but is: {license_id}', - context) + f'license_id must only contain letters, numbers, "." and "-" and must begin with "LicenseRef-", ' + f"but is: {license_id}", + context, + ) ) if license_id and not extracted_licensing_infos.extracted_text: @@ -47,8 +50,6 @@ def validate_extracted_licensing_info(extracted_licensing_infos: ExtractedLicens for cross_reference in extracted_licensing_infos.cross_references: for message in validate_url(cross_reference): - validation_messages.append( - ValidationMessage("cross_reference " + message, context) - ) + validation_messages.append(ValidationMessage("cross_reference " + message, context)) return validation_messages diff --git a/src/spdx/validation/file_validator.py b/src/spdx/validation/file_validator.py index 745131bdc..c90cbc868 100644 --- a/src/spdx/validation/file_validator.py +++ b/src/spdx/validation/file_validator.py @@ -15,13 +15,14 @@ from spdx.model.document import Document from spdx.model.file import File from spdx.validation.checksum_validator import validate_checksums -from spdx.validation.license_expression_validator import validate_license_expressions, validate_license_expression +from spdx.validation.license_expression_validator import validate_license_expression, validate_license_expressions from spdx.validation.spdx_id_validators import validate_spdx_id -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_files(files: List[File], spdx_version: str, document: Optional[Document] = None) -> List[ - ValidationMessage]: +def validate_files( + files: List[File], spdx_version: str, document: Optional[Document] = None +) -> List[ValidationMessage]: validation_messages = [] if document: for file in files: @@ -35,8 +36,12 @@ def validate_files(files: List[File], spdx_version: str, document: Optional[Docu def validate_file_within_document(file: File, spdx_version: str, document: Document) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] - context = ValidationContext(spdx_id=file.spdx_id, parent_id=document.creation_info.spdx_id, - element_type=SpdxElementType.FILE, full_element=file) + context = ValidationContext( + spdx_id=file.spdx_id, + parent_id=document.creation_info.spdx_id, + element_type=SpdxElementType.FILE, + full_element=file, + ) for message in validate_spdx_id(file.spdx_id, document): validation_messages.append(ValidationMessage(message, context)) @@ -50,8 +55,9 @@ def validate_file_within_document(file: File, spdx_version: str, document: Docum return validation_messages -def validate_file(file: File, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ - ValidationMessage]: +def validate_file( + file: File, spdx_version: str, context: Optional[ValidationContext] = None +) -> List[ValidationMessage]: validation_messages = [] if not context: context = ValidationContext(spdx_id=file.spdx_id, element_type=SpdxElementType.FILE, full_element=file) @@ -59,27 +65,27 @@ def validate_file(file: File, spdx_version: str, context: Optional[ValidationCon if file.name.startswith("/"): validation_messages.append( ValidationMessage( - f'file name must not be an absolute path starting with "/", but is: {file.name}', context) + f'file name must not be an absolute path starting with "/", but is: {file.name}', context + ) ) if ChecksumAlgorithm.SHA1 not in [checksum.algorithm for checksum in file.checksums]: validation_messages.append( ValidationMessage( - f"checksums must contain a SHA1 algorithm checksum, but only contains: {[checksum.algorithm for checksum in file.checksums]}", - context) + f"checksums must contain a SHA1 algorithm checksum, but only contains: " + f"{[checksum.algorithm for checksum in file.checksums]}", + context, + ) ) validation_messages.extend(validate_checksums(file.checksums, file.spdx_id, spdx_version)) if spdx_version == "SPDX-2.2": if file.license_concluded is None: - validation_messages.append( - ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("license_concluded is mandatory in SPDX-2.2", context)) if not file.license_info_in_file: - validation_messages.append( - ValidationMessage(f"license_info_in_file is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("license_info_in_file is mandatory in SPDX-2.2", context)) if file.copyright_text is None: - validation_messages.append( - ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("copyright_text is mandatory in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/license_expression_validator.py b/src/spdx/validation/license_expression_validator.py index 789d6c8c4..ebf6e4ae8 100644 --- a/src/spdx/validation/license_expression_validator.py +++ b/src/spdx/validation/license_expression_validator.py @@ -11,19 +11,20 @@ from typing import List, Optional, Union -from license_expression import LicenseExpression, get_spdx_licensing, ExpressionError, ExpressionParseError -from spdx.model.document import Document +from license_expression import ExpressionError, ExpressionParseError, LicenseExpression, get_spdx_licensing +from spdx.model.document import Document from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_license_expressions( - license_expressions: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], - document: Document, parent_id: str) -> List[ValidationMessage]: - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, - full_element=license_expressions) + license_expressions: List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], document: Document, parent_id: str +) -> List[ValidationMessage]: + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, full_element=license_expressions + ) validation_messages = [] for license_expression in license_expressions: @@ -33,14 +34,18 @@ def validate_license_expressions( def validate_license_expression( - license_expression: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], document: Document, - parent_id: str, context: ValidationContext = None) -> List[ValidationMessage]: + license_expression: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], + document: Document, + parent_id: str, + context: ValidationContext = None, +) -> List[ValidationMessage]: if license_expression in [SpdxNoAssertion(), SpdxNone(), None]: return [] if not context: - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, - full_element=license_expression) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, full_element=license_expression + ) validation_messages = [] license_ref_ids: List[str] = [license_ref.license_id for license_ref in document.extracted_licensing_info] @@ -49,8 +54,10 @@ def validate_license_expression( if non_spdx_token not in license_ref_ids: validation_messages.append( ValidationMessage( - f"Unrecognized license reference: {non_spdx_token}. license_expression must only use IDs from the license list or extracted licensing info, but is: {license_expression}", - context) + f"Unrecognized license reference: {non_spdx_token}. license_expression must only use IDs from the " + f"license list or extracted licensing info, but is: {license_expression}", + context, + ) ) try: @@ -58,14 +65,11 @@ def validate_license_expression( except ExpressionParseError as err: # This error is raised when an exception symbol is used as a license symbol and vice versa. # So far, it only catches the first such error in the provided string. - validation_messages.append( - ValidationMessage( - f"{err}. for license_expression: {license_expression}", - context) - ) + validation_messages.append(ValidationMessage(f"{err}. for license_expression: {license_expression}", context)) except ExpressionError: - # This error is raised for invalid symbols within the license_expression, but it provides only a string of these. - # On the other hand, get_spdx_licensing().validate() gives an actual list of invalid symbols, so this is handled above. + # This error is raised for invalid symbols within the license_expression, but it provides only a string of + # these. On the other hand, get_spdx_licensing().validate() gives an actual list of invalid symbols, so this is + # handled above. pass return validation_messages diff --git a/src/spdx/validation/package_validator.py b/src/spdx/validation/package_validator.py index 4cd850fc8..ab68757e1 100644 --- a/src/spdx/validation/package_validator.py +++ b/src/spdx/validation/package_validator.py @@ -13,19 +13,20 @@ from spdx.model.document import Document from spdx.model.package import Package -from spdx.model.relationship import RelationshipType, Relationship +from spdx.model.relationship import Relationship, RelationshipType from spdx.model.relationship_filters import filter_by_type_and_origin, filter_by_type_and_target from spdx.validation.checksum_validator import validate_checksums from spdx.validation.external_package_ref_validator import validate_external_package_refs from spdx.validation.license_expression_validator import validate_license_expression, validate_license_expressions from spdx.validation.package_verification_code_validator import validate_verification_code from spdx.validation.spdx_id_validators import validate_spdx_id -from spdx.validation.uri_validators import validate_url, validate_download_location -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.uri_validators import validate_download_location, validate_url +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_packages(packages: List[Package], spdx_version: str, document: Optional[Document] = None) -> List[ - ValidationMessage]: +def validate_packages( + packages: List[Package], spdx_version: str, document: Optional[Document] = None +) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] if document: for package in packages: @@ -37,28 +38,38 @@ def validate_packages(packages: List[Package], spdx_version: str, document: Opti return validation_messages -def validate_package_within_document(package: Package, spdx_version: str, document: Document) -> List[ - ValidationMessage]: +def validate_package_within_document( + package: Package, spdx_version: str, document: Document +) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] - context = ValidationContext(spdx_id=package.spdx_id, parent_id=document.creation_info.spdx_id, - element_type=SpdxElementType.PACKAGE, full_element=package) + context = ValidationContext( + spdx_id=package.spdx_id, + parent_id=document.creation_info.spdx_id, + element_type=SpdxElementType.PACKAGE, + full_element=package, + ) for message in validate_spdx_id(package.spdx_id, document): validation_messages.append(ValidationMessage(message, context)) if not package.files_analyzed: - package_contains_relationships = filter_by_type_and_origin(document.relationships, RelationshipType.CONTAINS, - package.spdx_id) - contained_in_package_relationships = filter_by_type_and_target(document.relationships, - RelationshipType.CONTAINED_BY, package.spdx_id) + package_contains_relationships = filter_by_type_and_origin( + document.relationships, RelationshipType.CONTAINS, package.spdx_id + ) + contained_in_package_relationships = filter_by_type_and_target( + document.relationships, RelationshipType.CONTAINED_BY, package.spdx_id + ) - combined_relationships: List[Relationship] = package_contains_relationships + contained_in_package_relationships + combined_relationships: List[Relationship] = ( + package_contains_relationships + contained_in_package_relationships + ) if combined_relationships: validation_messages.append( ValidationMessage( f"package must contain no elements if files_analyzed is False, but found {combined_relationships}", - context) + context, + ) ) validation_messages.extend(validate_license_expression(package.license_concluded, document, package.spdx_id)) @@ -68,11 +79,15 @@ def validate_package_within_document(package: Package, spdx_version: str, docume if not package.files_analyzed: validation_messages.append( ValidationMessage( - f"license_info_from_files must be None if files_analyzed is False, but is: {license_info_from_files}", - context) + f"license_info_from_files must be None if files_analyzed is False, but is: " + f"{license_info_from_files}", + context, + ) ) else: - validation_messages.extend(validate_license_expressions(license_info_from_files, document, package.spdx_id)) + validation_messages.extend( + validate_license_expressions(license_info_from_files, document, package.spdx_id) + ) validation_messages.extend(validate_license_expression(package.license_declared, document, package.spdx_id)) @@ -81,11 +96,14 @@ def validate_package_within_document(package: Package, spdx_version: str, docume return validation_messages -def validate_package(package: Package, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ - ValidationMessage]: +def validate_package( + package: Package, spdx_version: str, context: Optional[ValidationContext] = None +) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] if not context: - context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package) + context = ValidationContext( + spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package + ) download_location = package.download_location if isinstance(download_location, str): @@ -102,38 +120,35 @@ def validate_package(package: Package, spdx_version: str, context: Optional[Vali if not package.files_analyzed: validation_messages.append( ValidationMessage( - f"verification_code must be None if files_analyzed is False, but is: {verification_code}", - context)) + f"verification_code must be None if files_analyzed is False, but is: {verification_code}", context + ) + ) else: validation_messages.extend(validate_verification_code(verification_code, package.spdx_id)) validation_messages.extend(validate_checksums(package.checksums, package.spdx_id, spdx_version)) validation_messages.extend( - validate_external_package_refs(package.external_references, package.spdx_id, spdx_version)) + validate_external_package_refs(package.external_references, package.spdx_id, spdx_version) + ) if spdx_version == "SPDX-2.2": if package.primary_package_purpose is not None: validation_messages.append( - ValidationMessage(f"primary_package_purpose is not supported in SPDX-2.2", context)) + ValidationMessage("primary_package_purpose is not supported in SPDX-2.2", context) + ) if package.built_date is not None: - validation_messages.append( - ValidationMessage(f"built_date is not supported in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("built_date is not supported in SPDX-2.2", context)) if package.release_date is not None: - validation_messages.append( - ValidationMessage(f"release_date is not supported in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("release_date is not supported in SPDX-2.2", context)) if package.valid_until_date is not None: - validation_messages.append( - ValidationMessage(f"valid_until_date is not supported in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("valid_until_date is not supported in SPDX-2.2", context)) if package.license_concluded is None: - validation_messages.append( - ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("license_concluded is mandatory in SPDX-2.2", context)) if package.license_declared is None: - validation_messages.append( - ValidationMessage(f"license_declared is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("license_declared is mandatory in SPDX-2.2", context)) if package.copyright_text is None: - validation_messages.append( - ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("copyright_text is mandatory in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/package_verification_code_validator.py b/src/spdx/validation/package_verification_code_validator.py index de6abbec2..b059dc69c 100644 --- a/src/spdx/validation/package_verification_code_validator.py +++ b/src/spdx/validation/package_verification_code_validator.py @@ -13,27 +13,29 @@ from typing import List from spdx.model.package import PackageVerificationCode -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def validate_verification_code(verification_code: PackageVerificationCode, parent_id: str) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE, - full_element=verification_code) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE, full_element=verification_code + ) for file in verification_code.excluded_files: if file.startswith("/"): validation_messages.append( - ValidationMessage( - f'file name must not be an absolute path starting with "/", but is: {file}', context) + ValidationMessage(f'file name must not be an absolute path starting with "/", but is: {file}', context) ) value: str = verification_code.value if not re.match("^[0-9a-f]{40}$", value): validation_messages.append( ValidationMessage( - f"value of verification_code must consist of 40 lowercase hexadecimal digits, but is: {value} (length: {len(value)} digits)", - context) + f"value of verification_code must consist of 40 lowercase hexadecimal digits, but is: {value} " + f"(length: {len(value)} digits)", + context, + ) ) return validation_messages diff --git a/src/spdx/validation/relationship_validator.py b/src/spdx/validation/relationship_validator.py index 4fa310970..11268d07c 100644 --- a/src/spdx/validation/relationship_validator.py +++ b/src/spdx/validation/relationship_validator.py @@ -16,11 +16,12 @@ from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.validation.spdx_id_validators import validate_spdx_id -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_relationships(relationships: List[Relationship], spdx_version: str, document: Document) -> List[ - ValidationMessage]: +def validate_relationships( + relationships: List[Relationship], spdx_version: str, document: Document +) -> List[ValidationMessage]: validation_messages = [] for relationship in relationships: validation_messages.extend(validate_relationship(relationship, spdx_version, document)) @@ -28,10 +29,11 @@ def validate_relationships(relationships: List[Relationship], spdx_version: str, return validation_messages -def validate_relationship(relationship: Relationship, spdx_version: str, document: Document) -> List[ValidationMessage]: +def validate_relationship( + relationship: Relationship, spdx_version: str, document: Document +) -> List[ValidationMessage]: validation_messages = [] - context = ValidationContext(element_type=SpdxElementType.RELATIONSHIP, - full_element=relationship) + context = ValidationContext(element_type=SpdxElementType.RELATIONSHIP, full_element=relationship) relationship_type: RelationshipType = relationship.relationship_type @@ -45,8 +47,10 @@ def validate_relationship(relationship: Relationship, spdx_version: str, documen validation_messages.append(ValidationMessage(message, context)) if spdx_version == "SPDX-2.2": - if relationship_type == RelationshipType.SPECIFICATION_FOR or relationship_type == RelationshipType.REQUIREMENT_DESCRIPTION_FOR: - validation_messages.append( - ValidationMessage(f"{relationship_type} is not supported in SPDX-2.2", context)) + if ( + relationship_type == RelationshipType.SPECIFICATION_FOR + or relationship_type == RelationshipType.REQUIREMENT_DESCRIPTION_FOR + ): + validation_messages.append(ValidationMessage(f"{relationship_type} is not supported in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/snippet_validator.py b/src/spdx/validation/snippet_validator.py index 90a110fa3..c709b1d37 100644 --- a/src/spdx/validation/snippet_validator.py +++ b/src/spdx/validation/snippet_validator.py @@ -13,14 +13,14 @@ from spdx.model.document import Document from spdx.model.snippet import Snippet -from spdx.validation.license_expression_validator import validate_license_expression, \ - validate_license_expressions +from spdx.validation.license_expression_validator import validate_license_expression, validate_license_expressions from spdx.validation.spdx_id_validators import validate_spdx_id -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage -def validate_snippets(snippets: List[Snippet], spdx_version: str, document: Optional[Document] = None) -> List[ - ValidationMessage]: +def validate_snippets( + snippets: List[Snippet], spdx_version: str, document: Optional[Document] = None +) -> List[ValidationMessage]: validation_messages = [] if document: for snippet in snippets: @@ -32,11 +32,16 @@ def validate_snippets(snippets: List[Snippet], spdx_version: str, document: Opti return validation_messages -def validate_snippet_within_document(snippet: Snippet, spdx_version: str, document: Document) -> List[ - ValidationMessage]: +def validate_snippet_within_document( + snippet: Snippet, spdx_version: str, document: Document +) -> List[ValidationMessage]: validation_messages: List[ValidationMessage] = [] - context = ValidationContext(spdx_id=snippet.spdx_id, parent_id=document.creation_info.spdx_id, - element_type=SpdxElementType.SNIPPET, full_element=snippet) + context = ValidationContext( + spdx_id=snippet.spdx_id, + parent_id=document.creation_info.spdx_id, + element_type=SpdxElementType.SNIPPET, + full_element=snippet, + ) messages: List[str] = validate_spdx_id(snippet.spdx_id, document) for message in messages: @@ -48,54 +53,61 @@ def validate_snippet_within_document(snippet: Snippet, spdx_version: str, docume validation_messages.extend(validate_license_expression(snippet.license_concluded, document, snippet.spdx_id)) - validation_messages.extend(validate_license_expressions(snippet.license_info_in_snippet, document, snippet.spdx_id)) + validation_messages.extend( + validate_license_expressions(snippet.license_info_in_snippet, document, snippet.spdx_id) + ) validation_messages.extend(validate_snippet(snippet, spdx_version, context)) return validation_messages -def validate_snippet(snippet: Snippet, spdx_version: str, context: Optional[ValidationContext] = None) -> List[ - ValidationMessage]: +def validate_snippet( + snippet: Snippet, spdx_version: str, context: Optional[ValidationContext] = None +) -> List[ValidationMessage]: validation_messages = [] if not context: - context = ValidationContext(spdx_id=snippet.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet) + context = ValidationContext( + spdx_id=snippet.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet + ) if snippet.byte_range[0] < 1: validation_messages.append( ValidationMessage( - f"byte_range values must be greater than or equal to 1, but is: {snippet.byte_range}", - context) + f"byte_range values must be greater than or equal to 1, but is: {snippet.byte_range}", context + ) ) if snippet.byte_range[0] > snippet.byte_range[1]: validation_messages.append( ValidationMessage( - f"the first value of byte_range must be less than or equal to the second, but is: {snippet.byte_range}", - context) + f"the first value of byte_range must be less than or equal to the second, but is: " + f"{snippet.byte_range}", + context, + ) ) if snippet.line_range: if snippet.line_range[0] < 1: validation_messages.append( ValidationMessage( - f"line_range values must be greater than or equal to 1, but is: {snippet.line_range}", - context) + f"line_range values must be greater than or equal to 1, but is: {snippet.line_range}", context + ) ) if snippet.line_range[0] > snippet.line_range[1]: validation_messages.append( ValidationMessage( - f"the first value of line_range must be less than or equal to the second, but is: {snippet.line_range}", - context) + f"the first value of line_range must be less than or equal to the second, " + f"but is: {snippet.line_range}", + context, + ) ) if spdx_version == "SPDX-2.2": if snippet.license_concluded is None: - validation_messages.append( - ValidationMessage(f"license_concluded is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("license_concluded is mandatory in SPDX-2.2", context)) if snippet.copyright_text is None: - validation_messages.append( - ValidationMessage(f"copyright_text is mandatory in SPDX-2.2", context)) + validation_messages.append(ValidationMessage("copyright_text is mandatory in SPDX-2.2", context)) return validation_messages diff --git a/src/spdx/validation/spdx_id_validators.py b/src/spdx/validation/spdx_id_validators.py index cdf8f0c3a..29164df65 100644 --- a/src/spdx/validation/spdx_id_validators.py +++ b/src/spdx/validation/spdx_id_validators.py @@ -43,17 +43,19 @@ def get_list_of_all_spdx_ids(document: Document) -> List[str]: def is_external_doc_ref_present_in_document(external_ref_id: str, document: Document) -> bool: - all_external_doc_ref_ids_in_document = [external_doc_ref.document_ref_id for external_doc_ref in - document.creation_info.external_document_refs] + all_external_doc_ref_ids_in_document = [ + external_doc_ref.document_ref_id for external_doc_ref in document.creation_info.external_document_refs + ] return external_ref_id in all_external_doc_ref_ids_in_document -def validate_spdx_id(spdx_id: str, document: Document, check_document: bool = False, check_files: bool = False) -> List[ - str]: - """ Test that the given spdx_id (and a potential DocumentRef to an external document) is valid +def validate_spdx_id( + spdx_id: str, document: Document, check_document: bool = False, check_files: bool = False +) -> List[str]: + """Test that the given spdx_id (and a potential DocumentRef to an external document) is valid and, if it is a reference, actually exists in the document. Optionally checks files or the whole document - for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages. """ + for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages.""" validation_messages: List[str] = [] split_id: List[str] = spdx_id.split(":") @@ -61,26 +63,35 @@ def validate_spdx_id(spdx_id: str, document: Document, check_document: bool = Fa # # # invalid case # # # if len(split_id) > 2: return [ - f"spdx_id must not contain more than one colon in order to separate the external document reference id from the internal SPDX id, but is: {spdx_id}"] + f"spdx_id must not contain more than one colon in order to separate the external document reference id " + f"from the internal SPDX id, but is: {spdx_id}" + ] # # # case with external document ref prefix # # # if len(split_id) == 2: if not is_valid_external_doc_ref_id(split_id[0]): validation_messages.append( - f'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: {split_id[0]}') + f'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and ' + f'"+" and must begin with "DocumentRef-", but is: {split_id[0]}' + ) if not is_valid_internal_spdx_id(split_id[1]): validation_messages.append( - f'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: {split_id[1]}') + f'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin ' + f'with "SPDXRef-", but is: {split_id[1]}' + ) if not is_external_doc_ref_present_in_document(split_id[0], document): validation_messages.append( - f'did not find the external document reference "{split_id[0]}" in the SPDX document') + f'did not find the external document reference "{split_id[0]}" in the SPDX document' + ) return validation_messages # # # "normal" case # # # if not is_valid_internal_spdx_id(spdx_id): validation_messages.append( - f'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: {spdx_id}') + f'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: ' + f"{spdx_id}" + ) if check_document: if not is_spdx_id_present_in_document(spdx_id, document): @@ -88,6 +99,8 @@ def validate_spdx_id(spdx_id: str, document: Document, check_document: bool = Fa if check_files: if not is_spdx_id_present_in_files(spdx_id, document.files): - validation_messages.append(f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document\'s files') + validation_messages.append( + f'did not find the referenced spdx_id "{spdx_id}" in the SPDX document\'s files' + ) return validation_messages diff --git a/src/spdx/validation/uri_validators.py b/src/spdx/validation/uri_validators.py index 3033e0458..8d57c997c 100644 --- a/src/spdx/validation/uri_validators.py +++ b/src/spdx/validation/uri_validators.py @@ -14,12 +14,16 @@ from uritools import isabsuri, urisplit -url_pattern = "(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/|ssh:\\/\\/|git:\\/\\/|svn:\\/\\/|sftp:\\/\\/|ftp:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+){0,100}\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?" +url_pattern = ( + "(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/|ssh:\\/\\/|git:\\/\\/|svn:\\/\\/|sftp:" + "\\/\\/|ftp:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+){0,100}\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?" +) supported_download_repos: str = "(git|hg|svn|bzr)" git_pattern = "(git\\+git@[a-zA-Z0-9\\.\\-]+:[a-zA-Z0-9/\\\\.@\\-]+)" bazaar_pattern = "(bzr\\+lp:[a-zA-Z0-9\\.\\-]+)" download_location_pattern = ( - "^(((" + supported_download_repos + "\\+)?" + url_pattern + ")|" + git_pattern + "|" + bazaar_pattern + ")$") + "^(((" + supported_download_repos + "\\+)?" + url_pattern + ")|" + git_pattern + "|" + bazaar_pattern + ")$" +) def validate_url(url: str) -> List[str]: diff --git a/src/spdx/validation/validation_message.py b/src/spdx/validation/validation_message.py index 70001b78a..c1679f1c7 100644 --- a/src/spdx/validation/validation_message.py +++ b/src/spdx/validation/validation_message.py @@ -11,7 +11,7 @@ from dataclasses import dataclass from enum import Enum, auto -from typing import Optional, Any +from typing import Any, Optional class SpdxElementType(Enum): diff --git a/src/spdx/writer/rdf/annotation_writer.py b/src/spdx/writer/rdf/annotation_writer.py index e1e275d77..6aa234ae6 100644 --- a/src/spdx/writer/rdf/annotation_writer.py +++ b/src/spdx/writer/rdf/annotation_writer.py @@ -10,25 +10,34 @@ # limitations under the License. from typing import Dict -from rdflib import Graph, Literal, RDFS, URIRef, RDF, BNode +from rdflib import RDF, RDFS, BNode, Graph, Literal, URIRef +from spdx.casing_tools import snake_case_to_camel_case from spdx.datetime_conversions import datetime_to_iso_string from spdx.model.annotation import Annotation -from spdx.casing_tools import snake_case_to_camel_case -from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id -def add_annotation_to_graph(annotation: Annotation, graph: Graph, doc_namespace: str, - external_doc_ref_to_namespace: Dict[str, str]): - annotation_resource = URIRef(add_namespace_to_spdx_id(annotation.spdx_id, doc_namespace, external_doc_ref_to_namespace)) +def add_annotation_to_graph( + annotation: Annotation, graph: Graph, doc_namespace: str, external_doc_ref_to_namespace: Dict[str, str] +): + annotation_resource = URIRef( + add_namespace_to_spdx_id(annotation.spdx_id, doc_namespace, external_doc_ref_to_namespace) + ) annotation_node = BNode() graph.add((annotation_node, RDF.type, SPDX_NAMESPACE.Annotation)) - graph.add((annotation_node, SPDX_NAMESPACE.annotationType, - SPDX_NAMESPACE[f"annotationType_{snake_case_to_camel_case(annotation.annotation_type.name)}"])) + graph.add( + ( + annotation_node, + SPDX_NAMESPACE.annotationType, + SPDX_NAMESPACE[f"annotationType_{snake_case_to_camel_case(annotation.annotation_type.name)}"], + ) + ) graph.add((annotation_node, SPDX_NAMESPACE.annotator, Literal(annotation.annotator.to_serialized_string()))) graph.add( - (annotation_node, SPDX_NAMESPACE.annotationDate, Literal(datetime_to_iso_string(annotation.annotation_date)))) + (annotation_node, SPDX_NAMESPACE.annotationDate, Literal(datetime_to_iso_string(annotation.annotation_date))) + ) graph.add((annotation_node, RDFS.comment, Literal(annotation.annotation_comment))) graph.add((annotation_resource, SPDX_NAMESPACE.annotation, annotation_node)) diff --git a/src/spdx/writer/rdf/checksum_writer.py b/src/spdx/writer/rdf/checksum_writer.py index b9b2fe84f..335b89d31 100644 --- a/src/spdx/writer/rdf/checksum_writer.py +++ b/src/spdx/writer/rdf/checksum_writer.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, URIRef, BNode, RDF, Literal +from rdflib import RDF, BNode, Graph, Literal, URIRef from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.rdfschema.namespace import SPDX_NAMESPACE @@ -22,9 +22,10 @@ def add_checksum_to_graph(checksum: Checksum, graph: Graph, parent: URIRef): graph.add((parent, SPDX_NAMESPACE.checksum, checksum_node)) + def algorithm_to_rdf_string(algorithm: ChecksumAlgorithm) -> URIRef: if "BLAKE2B" in algorithm.name: - algorithm_rdf_string = algorithm.name.replace("_","").lower() + algorithm_rdf_string = algorithm.name.replace("_", "").lower() else: algorithm_rdf_string = algorithm.name.lower() diff --git a/src/spdx/writer/rdf/creation_info_writer.py b/src/spdx/writer/rdf/creation_info_writer.py index 1fe1330c5..795ed2f1e 100644 --- a/src/spdx/writer/rdf/creation_info_writer.py +++ b/src/spdx/writer/rdf/creation_info_writer.py @@ -8,13 +8,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, BNode, RDF, Literal, RDFS, URIRef +from rdflib import RDF, RDFS, BNode, Graph, Literal, URIRef from spdx.datetime_conversions import datetime_to_iso_string from spdx.model.document import CreationInfo +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE from spdx.writer.rdf.external_document_ref_writer import add_external_document_ref_to_graph from spdx.writer.rdf.writer_utils import add_optional_literal -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE def add_creation_info_to_graph(creation_info: CreationInfo, graph: Graph): @@ -33,8 +33,9 @@ def add_creation_info_to_graph(creation_info: CreationInfo, graph: Graph): for creator in creation_info.creators: graph.add((creation_info_node, SPDX_NAMESPACE.creator, Literal(creator.to_serialized_string()))) - add_optional_literal(creation_info.license_list_version, graph, creation_info_node, - SPDX_NAMESPACE.licenseListVersion) + add_optional_literal( + creation_info.license_list_version, graph, creation_info_node, SPDX_NAMESPACE.licenseListVersion + ) add_optional_literal(creation_info.creator_comment, graph, creation_info_node, RDFS.comment) graph.add((doc_node, SPDX_NAMESPACE.creationInfo, creation_info_node)) diff --git a/src/spdx/writer/rdf/external_document_ref_writer.py b/src/spdx/writer/rdf/external_document_ref_writer.py index 7521bd338..85ef8da65 100644 --- a/src/spdx/writer/rdf/external_document_ref_writer.py +++ b/src/spdx/writer/rdf/external_document_ref_writer.py @@ -8,18 +8,21 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, URIRef, RDF +from rdflib import RDF, Graph, URIRef from spdx.model.external_document_ref import ExternalDocumentRef -from spdx.writer.rdf.checksum_writer import add_checksum_to_graph from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.checksum_writer import add_checksum_to_graph -def add_external_document_ref_to_graph(external_document_ref: ExternalDocumentRef, graph: Graph, doc_node: URIRef, - doc_namespace: str): +def add_external_document_ref_to_graph( + external_document_ref: ExternalDocumentRef, graph: Graph, doc_node: URIRef, doc_namespace: str +): external_document_ref_resource = URIRef(f"{doc_namespace}#{external_document_ref.document_ref_id}") graph.add((external_document_ref_resource, RDF.type, SPDX_NAMESPACE.ExternalDocumentRef)) - graph.add((external_document_ref_resource, SPDX_NAMESPACE.spdxDocument, URIRef(external_document_ref.document_uri))) + graph.add( + (external_document_ref_resource, SPDX_NAMESPACE.spdxDocument, URIRef(external_document_ref.document_uri)) + ) add_checksum_to_graph(external_document_ref.checksum, graph, external_document_ref_resource) graph.add((doc_node, SPDX_NAMESPACE.externalDocumentRef, external_document_ref_resource)) diff --git a/src/spdx/writer/rdf/extracted_licensing_info_writer.py b/src/spdx/writer/rdf/extracted_licensing_info_writer.py index 4d0f4b674..96bd3888e 100644 --- a/src/spdx/writer/rdf/extracted_licensing_info_writer.py +++ b/src/spdx/writer/rdf/extracted_licensing_info_writer.py @@ -8,26 +8,30 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, URIRef, RDF, BNode, RDFS, Literal -from spdx.writer.rdf.writer_utils import add_optional_literal, add_literal_or_no_assertion -from spdx.rdfschema.namespace import SPDX_NAMESPACE +from rdflib import RDF, RDFS, BNode, Graph, Literal, URIRef from spdx.model.extracted_licensing_info import ExtractedLicensingInfo +from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.writer_utils import add_literal_or_no_assertion, add_optional_literal -def add_extracted_licensing_info_to_graph(extracted_licensing_info: ExtractedLicensingInfo, graph: Graph, doc_node, - doc_namespace: str): +def add_extracted_licensing_info_to_graph( + extracted_licensing_info: ExtractedLicensingInfo, graph: Graph, doc_node, doc_namespace: str +): if extracted_licensing_info.license_id: extracted_licensing_info_resource = URIRef(f"{doc_namespace}#{extracted_licensing_info.license_id}") graph.add((extracted_licensing_info_resource, RDF.type, SPDX_NAMESPACE.ExtractedLicensingInfo)) else: extracted_licensing_info_resource = BNode() - add_optional_literal(extracted_licensing_info.license_id, graph, extracted_licensing_info_resource, - SPDX_NAMESPACE.licenseId) - add_optional_literal(extracted_licensing_info.extracted_text, graph, extracted_licensing_info_resource, - SPDX_NAMESPACE.extractedText) - add_literal_or_no_assertion(extracted_licensing_info.license_name, graph, extracted_licensing_info_resource, - SPDX_NAMESPACE.name) + add_optional_literal( + extracted_licensing_info.license_id, graph, extracted_licensing_info_resource, SPDX_NAMESPACE.licenseId + ) + add_optional_literal( + extracted_licensing_info.extracted_text, graph, extracted_licensing_info_resource, SPDX_NAMESPACE.extractedText + ) + add_literal_or_no_assertion( + extracted_licensing_info.license_name, graph, extracted_licensing_info_resource, SPDX_NAMESPACE.name + ) for cross_reference in extracted_licensing_info.cross_references: graph.add((extracted_licensing_info_resource, RDFS.seeAlso, Literal(cross_reference))) add_optional_literal(extracted_licensing_info.comment, graph, extracted_licensing_info_resource, RDFS.comment) diff --git a/src/spdx/writer/rdf/file_writer.py b/src/spdx/writer/rdf/file_writer.py index 6441d8c06..c896cdea8 100644 --- a/src/spdx/writer/rdf/file_writer.py +++ b/src/spdx/writer/rdf/file_writer.py @@ -10,32 +10,38 @@ # limitations under the License. from typing import Dict -from rdflib import Graph, URIRef, Literal, RDF, RDFS +from rdflib import RDF, RDFS, Graph, Literal, URIRef -from spdx.model.file import File from spdx.casing_tools import snake_case_to_camel_case +from spdx.model.file import File +from spdx.rdfschema.namespace import SPDX_NAMESPACE from spdx.writer.rdf.checksum_writer import add_checksum_to_graph from spdx.writer.rdf.license_expression_writer import add_license_expression_or_none_or_no_assertion -from spdx.writer.rdf.writer_utils import add_optional_literal, add_namespace_to_spdx_id -from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id, add_optional_literal -def add_file_to_graph(file: File, graph: Graph, doc_namespace: str, - external_doc_ref_to_namespace: Dict[str, str]): +def add_file_to_graph(file: File, graph: Graph, doc_namespace: str, external_doc_ref_to_namespace: Dict[str, str]): file_resource = URIRef(add_namespace_to_spdx_id(file.spdx_id, doc_namespace, external_doc_ref_to_namespace)) graph.add((file_resource, RDF.type, SPDX_NAMESPACE.File)) graph.add((file_resource, SPDX_NAMESPACE.fileName, Literal(file.name))) for file_type in file.file_types: - graph.add((file_resource, SPDX_NAMESPACE.fileType, - SPDX_NAMESPACE[f"fileType_{snake_case_to_camel_case(file_type.name)}"])) + graph.add( + ( + file_resource, + SPDX_NAMESPACE.fileType, + SPDX_NAMESPACE[f"fileType_{snake_case_to_camel_case(file_type.name)}"], + ) + ) for checksum in file.checksums: add_checksum_to_graph(checksum, graph, file_resource) - add_license_expression_or_none_or_no_assertion(file.license_concluded, graph, file_resource, - SPDX_NAMESPACE.licenseConcluded, doc_namespace) - add_license_expression_or_none_or_no_assertion(file.license_info_in_file, graph, file_resource, - SPDX_NAMESPACE.licenseInfoInFile, doc_namespace) + add_license_expression_or_none_or_no_assertion( + file.license_concluded, graph, file_resource, SPDX_NAMESPACE.licenseConcluded, doc_namespace + ) + add_license_expression_or_none_or_no_assertion( + file.license_info_in_file, graph, file_resource, SPDX_NAMESPACE.licenseInfoInFile, doc_namespace + ) add_optional_literal(file.license_comment, graph, file_resource, SPDX_NAMESPACE.licenseComments) add_optional_literal(file.copyright_text, graph, file_resource, SPDX_NAMESPACE.copyrightText) diff --git a/src/spdx/writer/rdf/license_expression_writer.py b/src/spdx/writer/rdf/license_expression_writer.py index cf4edde7e..bb584817f 100644 --- a/src/spdx/writer/rdf/license_expression_writer.py +++ b/src/spdx/writer/rdf/license_expression_writer.py @@ -8,23 +8,35 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union, List +from typing import List, Union from boolean import Expression -from rdflib import Graph, URIRef, BNode, RDF -from license_expression import AND, OR, LicenseWithExceptionSymbol, LicenseSymbol, get_spdx_licensing, ExpressionInfo, \ - LicenseExpression -from rdflib.term import Node, Literal +from license_expression import ( + AND, + OR, + ExpressionInfo, + LicenseExpression, + LicenseSymbol, + LicenseWithExceptionSymbol, + get_spdx_licensing, +) +from rdflib import RDF, BNode, Graph, URIRef +from rdflib.term import Literal, Node from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE - -def add_license_expression_or_none_or_no_assertion(value: Union[ - List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], LicenseExpression, SpdxNoAssertion, SpdxNone], graph: Graph, parent: Node, predicate: Node, - doc_namespace: str): +def add_license_expression_or_none_or_no_assertion( + value: Union[ + List[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]], LicenseExpression, SpdxNoAssertion, SpdxNone + ], + graph: Graph, + parent: Node, + predicate: Node, + doc_namespace: str, +): if isinstance(value, SpdxNoAssertion): graph.add((parent, predicate, SPDX_NAMESPACE.noassertion)) return @@ -38,8 +50,9 @@ def add_license_expression_or_none_or_no_assertion(value: Union[ add_license_expression_to_graph(value, graph, parent, predicate, doc_namespace) -def add_license_expression_to_graph(license_expression: Expression, graph: Graph, parent: Node, predicate: Node, - doc_namespace: str): +def add_license_expression_to_graph( + license_expression: Expression, graph: Graph, parent: Node, predicate: Node, doc_namespace: str +): if isinstance(license_expression, AND): member_node = BNode() graph.add((member_node, RDF.type, SPDX_NAMESPACE.ConjunctiveLicenseSet)) @@ -57,14 +70,14 @@ def add_license_expression_to_graph(license_expression: Expression, graph: Graph graph.add((member_node, RDF.type, SPDX_NAMESPACE.WithExceptionOperator)) graph.add((parent, predicate, member_node)) - add_license_expression_to_graph(license_expression.license_symbol, graph, member_node, SPDX_NAMESPACE.member, - doc_namespace) + add_license_expression_to_graph( + license_expression.license_symbol, graph, member_node, SPDX_NAMESPACE.member, doc_namespace + ) add_license_exception_to_graph(license_expression.exception_symbol, graph, member_node) if isinstance(license_expression, LicenseSymbol): if license_or_exception_is_on_spdx_licensing_list(license_expression): - graph.add( - (parent, predicate, LICENSE_NAMESPACE[str(license_expression)])) + graph.add((parent, predicate, LICENSE_NAMESPACE[str(license_expression)])) else: # assuming that the license expression is a LicenseRef to an instance of ExtractedLicensingInfo graph.add((parent, predicate, URIRef(f"{doc_namespace}#{license_expression}"))) diff --git a/src/spdx/writer/rdf/package_writer.py b/src/spdx/writer/rdf/package_writer.py index 890cf8f12..84cf94b8d 100644 --- a/src/spdx/writer/rdf/package_writer.py +++ b/src/spdx/writer/rdf/package_writer.py @@ -10,21 +10,29 @@ # limitations under the License. from typing import Dict -from rdflib import Graph, URIRef, RDF, Literal, XSD, BNode, DOAP, RDFS -from spdx.writer.rdf.license_expression_writer import add_license_expression_or_none_or_no_assertion +from rdflib import DOAP, RDF, RDFS, XSD, BNode, Graph, Literal, URIRef from spdx.casing_tools import snake_case_to_camel_case +from spdx.model.package import ( + CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES, + ExternalPackageRef, + Package, + PackageVerificationCode, +) +from spdx.rdfschema.namespace import REFERENCE_NAMESPACE, SPDX_NAMESPACE from spdx.writer.rdf.checksum_writer import add_checksum_to_graph - -from spdx.model.package import Package, PackageVerificationCode, ExternalPackageRef, \ - CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES -from spdx.writer.rdf.writer_utils import add_optional_literal, add_literal_or_no_assertion_or_none, \ - add_datetime_to_graph, add_namespace_to_spdx_id -from spdx.rdfschema.namespace import SPDX_NAMESPACE, REFERENCE_NAMESPACE +from spdx.writer.rdf.license_expression_writer import add_license_expression_or_none_or_no_assertion +from spdx.writer.rdf.writer_utils import ( + add_datetime_to_graph, + add_literal_or_no_assertion_or_none, + add_namespace_to_spdx_id, + add_optional_literal, +) -def add_package_to_graph(package: Package, graph: Graph, doc_namespace: str, - external_doc_ref_to_namespace: Dict[str, str]): +def add_package_to_graph( + package: Package, graph: Graph, doc_namespace: str, external_doc_ref_to_namespace: Dict[str, str] +): package_resource = URIRef(add_namespace_to_spdx_id(package.spdx_id, doc_namespace, external_doc_ref_to_namespace)) graph.add((package_resource, RDF.type, SPDX_NAMESPACE.Package)) @@ -33,8 +41,9 @@ def add_package_to_graph(package: Package, graph: Graph, doc_namespace: str, add_optional_literal(package.file_name, graph, package_resource, SPDX_NAMESPACE.packageFileName) add_optional_literal(package.supplier, graph, package_resource, SPDX_NAMESPACE.supplier) add_optional_literal(package.originator, graph, package_resource, SPDX_NAMESPACE.originator) - add_literal_or_no_assertion_or_none(package.download_location, graph, package_resource, - SPDX_NAMESPACE.downloadLocation) + add_literal_or_no_assertion_or_none( + package.download_location, graph, package_resource, SPDX_NAMESPACE.downloadLocation + ) graph.add((package_resource, SPDX_NAMESPACE.filesAnalyzed, Literal(package.files_analyzed, datatype=XSD.boolean))) add_package_verification_code_to_graph(package.verification_code, graph, package_resource) for checksum in package.checksums: @@ -42,12 +51,15 @@ def add_package_to_graph(package: Package, graph: Graph, doc_namespace: str, add_optional_literal(package.homepage, graph, package_resource, DOAP.homepage) add_optional_literal(package.source_info, graph, package_resource, SPDX_NAMESPACE.sourceInfo) - add_license_expression_or_none_or_no_assertion(package.license_concluded, graph, package_resource, - SPDX_NAMESPACE.licenseConcluded, doc_namespace) - add_license_expression_or_none_or_no_assertion(package.license_info_from_files, graph, package_resource, - SPDX_NAMESPACE.licenseInfoFromFiles, doc_namespace) - add_license_expression_or_none_or_no_assertion(package.license_declared, graph, package_resource, - SPDX_NAMESPACE.licenseDeclared, doc_namespace) + add_license_expression_or_none_or_no_assertion( + package.license_concluded, graph, package_resource, SPDX_NAMESPACE.licenseConcluded, doc_namespace + ) + add_license_expression_or_none_or_no_assertion( + package.license_info_from_files, graph, package_resource, SPDX_NAMESPACE.licenseInfoFromFiles, doc_namespace + ) + add_license_expression_or_none_or_no_assertion( + package.license_declared, graph, package_resource, SPDX_NAMESPACE.licenseDeclared, doc_namespace + ) add_optional_literal(package.license_comment, graph, package_resource, SPDX_NAMESPACE.licenseComments) add_optional_literal(package.copyright_text, graph, package_resource, SPDX_NAMESPACE.copyrightText) add_optional_literal(package.summary, graph, package_resource, SPDX_NAMESPACE.summary) @@ -58,42 +70,74 @@ def add_package_to_graph(package: Package, graph: Graph, doc_namespace: str, for attribution_text in package.attribution_texts: add_optional_literal(attribution_text, graph, package_resource, SPDX_NAMESPACE.attributionText) if package.primary_package_purpose: - graph.add((package_resource, SPDX_NAMESPACE.primaryPackagePurpose, - SPDX_NAMESPACE[f"purpose_{snake_case_to_camel_case(package.primary_package_purpose.name)}"])) + graph.add( + ( + package_resource, + SPDX_NAMESPACE.primaryPackagePurpose, + SPDX_NAMESPACE[f"purpose_{snake_case_to_camel_case(package.primary_package_purpose.name)}"], + ) + ) add_datetime_to_graph(package.release_date, graph, package_resource, SPDX_NAMESPACE.releaseDate) add_datetime_to_graph(package.built_date, graph, package_resource, SPDX_NAMESPACE.builtDate) add_datetime_to_graph(package.valid_until_date, graph, package_resource, SPDX_NAMESPACE.validUntilDate) -def add_package_verification_code_to_graph(package_verification_code: PackageVerificationCode, graph: Graph, - package_node: URIRef): +def add_package_verification_code_to_graph( + package_verification_code: PackageVerificationCode, graph: Graph, package_node: URIRef +): if not package_verification_code: return package_verification_code_node = BNode() graph.add((package_verification_code_node, RDF.type, SPDX_NAMESPACE.PackageVerificationCode)) - graph.add((package_verification_code_node, SPDX_NAMESPACE.packageVerificationCodeValue, - Literal(package_verification_code.value))) + graph.add( + ( + package_verification_code_node, + SPDX_NAMESPACE.packageVerificationCodeValue, + Literal(package_verification_code.value), + ) + ) for excluded_file in package_verification_code.excluded_files: - graph.add((package_verification_code_node, SPDX_NAMESPACE.packageVerificationCodeExcludedFile, - Literal(excluded_file))) + graph.add( + ( + package_verification_code_node, + SPDX_NAMESPACE.packageVerificationCodeExcludedFile, + Literal(excluded_file), + ) + ) graph.add((package_node, SPDX_NAMESPACE.packageVerificationCode, package_verification_code_node)) -def add_external_package_ref_to_graph(external_package_ref: ExternalPackageRef, graph: Graph, package_node: URIRef, - doc_namespace: str): +def add_external_package_ref_to_graph( + external_package_ref: ExternalPackageRef, graph: Graph, package_node: URIRef, doc_namespace: str +): external_package_ref_node = BNode() graph.add((external_package_ref_node, RDF.type, SPDX_NAMESPACE.ExternalRef)) - graph.add((external_package_ref_node, SPDX_NAMESPACE.referenceCategory, - SPDX_NAMESPACE[f"referenceCategory_{snake_case_to_camel_case(external_package_ref.category.name)}"])) + graph.add( + ( + external_package_ref_node, + SPDX_NAMESPACE.referenceCategory, + SPDX_NAMESPACE[f"referenceCategory_{snake_case_to_camel_case(external_package_ref.category.name)}"], + ) + ) if external_package_ref.reference_type in CATEGORY_TO_EXTERNAL_PACKAGE_REF_TYPES[external_package_ref.category]: - graph.add((external_package_ref_node, SPDX_NAMESPACE.referenceType, - REFERENCE_NAMESPACE[external_package_ref.reference_type])) + graph.add( + ( + external_package_ref_node, + SPDX_NAMESPACE.referenceType, + REFERENCE_NAMESPACE[external_package_ref.reference_type], + ) + ) else: - graph.add((external_package_ref_node, SPDX_NAMESPACE.referenceType, - URIRef(f"{doc_namespace}#{external_package_ref.reference_type}"))) + graph.add( + ( + external_package_ref_node, + SPDX_NAMESPACE.referenceType, + URIRef(f"{doc_namespace}#{external_package_ref.reference_type}"), + ) + ) graph.add((external_package_ref_node, SPDX_NAMESPACE.referenceLocator, Literal(external_package_ref.locator))) if external_package_ref.comment: graph.add((external_package_ref_node, RDFS.comment, Literal(external_package_ref.comment))) diff --git a/src/spdx/writer/rdf/rdf_writer.py b/src/spdx/writer/rdf/rdf_writer.py index 0e7848e86..64daf7389 100644 --- a/src/spdx/writer/rdf/rdf_writer.py +++ b/src/spdx/writer/rdf/rdf_writer.py @@ -10,10 +10,11 @@ # limitations under the License. from typing import Dict, List -from rdflib import Graph, DOAP +from rdflib import DOAP, Graph from rdflib.compare import to_isomorphic from spdx.model.document import Document +from spdx.rdfschema.namespace import POINTER_NAMESPACE, SPDX_NAMESPACE from spdx.validation.document_validator import validate_full_spdx_document from spdx.validation.validation_message import ValidationMessage from spdx.writer.rdf.annotation_writer import add_annotation_to_graph @@ -23,7 +24,6 @@ from spdx.writer.rdf.package_writer import add_package_to_graph from spdx.writer.rdf.relationship_writer import add_relationship_to_graph from spdx.writer.rdf.snippet_writer import add_snippet_to_graph -from spdx.rdfschema.namespace import SPDX_NAMESPACE, POINTER_NAMESPACE def write_document_to_file(document: Document, file_name: str, validate: bool): @@ -34,8 +34,10 @@ def write_document_to_file(document: Document, file_name: str, validate: bool): graph = Graph() doc_namespace = document.creation_info.document_namespace - external_doc_ref_to_namespace: Dict[str, str] = {external_doc_ref.document_ref_id: external_doc_ref.document_uri for - external_doc_ref in document.creation_info.external_document_refs} + external_doc_ref_to_namespace: Dict[str, str] = { + external_doc_ref.document_ref_id: external_doc_ref.document_uri + for external_doc_ref in document.creation_info.external_document_refs + } doc_node = add_creation_info_to_graph(document.creation_info, graph) for annotation in document.annotations: add_annotation_to_graph(annotation, graph, doc_namespace, external_doc_ref_to_namespace) diff --git a/src/spdx/writer/rdf/relationship_writer.py b/src/spdx/writer/rdf/relationship_writer.py index 66bc95e24..a59a2f537 100644 --- a/src/spdx/writer/rdf/relationship_writer.py +++ b/src/spdx/writer/rdf/relationship_writer.py @@ -10,31 +10,46 @@ # limitations under the License. from typing import Dict -from rdflib import Graph, BNode, RDF, URIRef, RDFS, Literal +from rdflib import RDF, RDFS, BNode, Graph, Literal, URIRef +from spdx.casing_tools import snake_case_to_camel_case from spdx.model.relationship import Relationship from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from spdx.casing_tools import snake_case_to_camel_case -from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id -def add_relationship_to_graph(relationship: Relationship, graph: Graph, doc_namespace: str, - external_doc_ref_to_namespace: Dict[str, str]): +def add_relationship_to_graph( + relationship: Relationship, graph: Graph, doc_namespace: str, external_doc_ref_to_namespace: Dict[str, str] +): relationship_node = BNode() graph.add((relationship_node, RDF.type, SPDX_NAMESPACE.Relationship)) - graph.add((relationship_node, SPDX_NAMESPACE.relationshipType, - SPDX_NAMESPACE[f"relationshipType_{snake_case_to_camel_case(relationship.relationship_type.name)}"])) + graph.add( + ( + relationship_node, + SPDX_NAMESPACE.relationshipType, + SPDX_NAMESPACE[f"relationshipType_{snake_case_to_camel_case(relationship.relationship_type.name)}"], + ) + ) if isinstance(relationship.related_spdx_element_id, SpdxNone): graph.add((relationship_node, SPDX_NAMESPACE.relatedSpdxElement, SPDX_NAMESPACE.none)) elif isinstance(relationship.related_spdx_element_id, SpdxNoAssertion): graph.add((relationship_node, SPDX_NAMESPACE.relatedSpdxElement, SPDX_NAMESPACE.noassertion)) else: - graph.add((relationship_node, SPDX_NAMESPACE.relatedSpdxElement, - URIRef(add_namespace_to_spdx_id(relationship.related_spdx_element_id, doc_namespace, - external_doc_ref_to_namespace)))) + graph.add( + ( + relationship_node, + SPDX_NAMESPACE.relatedSpdxElement, + URIRef( + add_namespace_to_spdx_id( + relationship.related_spdx_element_id, doc_namespace, external_doc_ref_to_namespace + ) + ), + ) + ) graph.add((relationship_node, RDFS.comment, Literal(relationship.comment))) relationship_resource = URIRef( - add_namespace_to_spdx_id(relationship.spdx_element_id, doc_namespace, external_doc_ref_to_namespace)) + add_namespace_to_spdx_id(relationship.spdx_element_id, doc_namespace, external_doc_ref_to_namespace) + ) graph.add((relationship_resource, SPDX_NAMESPACE.relationship, relationship_node)) diff --git a/src/spdx/writer/rdf/snippet_writer.py b/src/spdx/writer/rdf/snippet_writer.py index b7ab6ce2a..ab50ddd9d 100644 --- a/src/spdx/writer/rdf/snippet_writer.py +++ b/src/spdx/writer/rdf/snippet_writer.py @@ -8,34 +8,38 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Tuple, Optional, Dict +from typing import Dict, Optional, Tuple -from rdflib import Graph, URIRef, RDF, RDFS, Literal, BNode - -from spdx.writer.rdf.license_expression_writer import add_license_expression_or_none_or_no_assertion -from spdx.writer.rdf.writer_utils import add_optional_literal, add_namespace_to_spdx_id -from spdx.rdfschema.namespace import SPDX_NAMESPACE, POINTER_NAMESPACE +from rdflib import RDF, RDFS, BNode, Graph, Literal, URIRef from spdx.model.snippet import Snippet +from spdx.rdfschema.namespace import POINTER_NAMESPACE, SPDX_NAMESPACE +from spdx.writer.rdf.license_expression_writer import add_license_expression_or_none_or_no_assertion +from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id, add_optional_literal -def add_snippet_to_graph(snippet: Snippet, graph: Graph, doc_namespace: str, - external_doc_ref_to_namespace: Dict[str, str]): +def add_snippet_to_graph( + snippet: Snippet, graph: Graph, doc_namespace: str, external_doc_ref_to_namespace: Dict[str, str] +): snippet_resource = URIRef(add_namespace_to_spdx_id(snippet.spdx_id, doc_namespace, external_doc_ref_to_namespace)) graph.add((snippet_resource, RDF.type, SPDX_NAMESPACE.Snippet)) snippet_from_file_ref = URIRef( - add_namespace_to_spdx_id(snippet.file_spdx_id, doc_namespace, external_doc_ref_to_namespace)) - graph.add((snippet_resource, SPDX_NAMESPACE.snippetFromFile, - snippet_from_file_ref)) - add_range_to_graph(snippet.byte_range, graph, snippet_resource, snippet_from_file_ref, - POINTER_NAMESPACE.ByteOffsetPointer) - add_range_to_graph(snippet.line_range, graph, snippet_resource, snippet_from_file_ref, - POINTER_NAMESPACE.LineCharPointer) - add_license_expression_or_none_or_no_assertion(snippet.license_concluded, graph, snippet_resource, - SPDX_NAMESPACE.licenseConcluded, doc_namespace) - add_license_expression_or_none_or_no_assertion(snippet.license_info_in_snippet, graph, snippet_resource, - SPDX_NAMESPACE.licenseInfoInSnippet, doc_namespace) + add_namespace_to_spdx_id(snippet.file_spdx_id, doc_namespace, external_doc_ref_to_namespace) + ) + graph.add((snippet_resource, SPDX_NAMESPACE.snippetFromFile, snippet_from_file_ref)) + add_range_to_graph( + snippet.byte_range, graph, snippet_resource, snippet_from_file_ref, POINTER_NAMESPACE.ByteOffsetPointer + ) + add_range_to_graph( + snippet.line_range, graph, snippet_resource, snippet_from_file_ref, POINTER_NAMESPACE.LineCharPointer + ) + add_license_expression_or_none_or_no_assertion( + snippet.license_concluded, graph, snippet_resource, SPDX_NAMESPACE.licenseConcluded, doc_namespace + ) + add_license_expression_or_none_or_no_assertion( + snippet.license_info_in_snippet, graph, snippet_resource, SPDX_NAMESPACE.licenseInfoInSnippet, doc_namespace + ) add_optional_literal(snippet.license_comment, graph, snippet_resource, SPDX_NAMESPACE.licenseComments) add_optional_literal(snippet.copyright_text, graph, snippet_resource, SPDX_NAMESPACE.copyrightText) add_optional_literal(snippet.comment, graph, snippet_resource, RDFS.comment) @@ -44,12 +48,19 @@ def add_snippet_to_graph(snippet: Snippet, graph: Graph, doc_namespace: str, graph.add((snippet_resource, SPDX_NAMESPACE.attributionText, Literal(attribution_text))) -def add_range_to_graph(range_information: Optional[Tuple[int, int]], graph: Graph, snippet_node: URIRef, - snippet_from_file_ref: URIRef, pointer_class: URIRef): +def add_range_to_graph( + range_information: Optional[Tuple[int, int]], + graph: Graph, + snippet_node: URIRef, + snippet_from_file_ref: URIRef, + pointer_class: URIRef, +): start_end_pointer = BNode() graph.add((start_end_pointer, RDF.type, POINTER_NAMESPACE.StartEndPointer)) - for (predicate, value) in [(POINTER_NAMESPACE.startPointer, range_information[0]), - (POINTER_NAMESPACE.endPointer, range_information[1])]: + for predicate, value in [ + (POINTER_NAMESPACE.startPointer, range_information[0]), + (POINTER_NAMESPACE.endPointer, range_information[1]), + ]: pointer_node = BNode() graph.add((pointer_node, RDF.type, pointer_class)) graph.add((start_end_pointer, predicate, pointer_node)) diff --git a/src/spdx/writer/rdf/writer_utils.py b/src/spdx/writer/rdf/writer_utils.py index 1498b75a7..cfbe3b42e 100644 --- a/src/spdx/writer/rdf/writer_utils.py +++ b/src/spdx/writer/rdf/writer_utils.py @@ -10,7 +10,7 @@ # limitations under the License. import logging from datetime import datetime -from typing import Any, Optional, Dict +from typing import Any, Dict, Optional from rdflib import Graph, Literal from rdflib.term import Node diff --git a/src/spdx/writer/tagvalue/annotation_writer.py b/src/spdx/writer/tagvalue/annotation_writer.py index 231a7f5ea..b74991cc8 100644 --- a/src/spdx/writer/tagvalue/annotation_writer.py +++ b/src/spdx/writer/tagvalue/annotation_writer.py @@ -12,7 +12,7 @@ from spdx.datetime_conversions import datetime_to_iso_string from spdx.model.annotation import Annotation -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value def write_annotation(annotation: Annotation, text_output: TextIO): diff --git a/src/spdx/writer/tagvalue/checksum_writer.py b/src/spdx/writer/tagvalue/checksum_writer.py index 80df31e35..230c0dbfc 100644 --- a/src/spdx/writer/tagvalue/checksum_writer.py +++ b/src/spdx/writer/tagvalue/checksum_writer.py @@ -27,5 +27,5 @@ def write_checksum_to_tag_value(checksum: Checksum) -> str: ChecksumAlgorithm.BLAKE2B_512.name: "BLAKE2b-512", ChecksumAlgorithm.SHA3_256.name: "SHA3-256", ChecksumAlgorithm.SHA3_384.name: "SHA3-384", - ChecksumAlgorithm.SHA3_512.name: "SHA3-512" + ChecksumAlgorithm.SHA3_512.name: "SHA3-512", } diff --git a/src/spdx/writer/tagvalue/creation_info_writer.py b/src/spdx/writer/tagvalue/creation_info_writer.py index 219af57a5..798f7ed21 100644 --- a/src/spdx/writer/tagvalue/creation_info_writer.py +++ b/src/spdx/writer/tagvalue/creation_info_writer.py @@ -12,8 +12,12 @@ from spdx.datetime_conversions import datetime_to_iso_string from spdx.model.document import CreationInfo -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value, write_optional_heading, \ - write_separator +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import ( + write_optional_heading, + write_separator, + write_text_value, + write_value, +) def write_creation_info(creation_info: CreationInfo, text_output: TextIO): @@ -26,8 +30,13 @@ def write_creation_info(creation_info: CreationInfo, text_output: TextIO): write_optional_heading(creation_info.external_document_refs, "\n## External Document References\n", text_output) for external_document_ref in creation_info.external_document_refs: - external_document_ref_str = " ".join([external_document_ref.document_ref_id, external_document_ref.document_uri, - external_document_ref.checksum.algorithm.name + ": " + external_document_ref.checksum.value]) + external_document_ref_str = " ".join( + [ + external_document_ref.document_ref_id, + external_document_ref.document_uri, + external_document_ref.checksum.algorithm.name + ": " + external_document_ref.checksum.value, + ] + ) write_value("ExternalDocumentRef", external_document_ref_str, text_output) write_separator(text_output) diff --git a/src/spdx/writer/tagvalue/extracted_licensing_info_writer.py b/src/spdx/writer/tagvalue/extracted_licensing_info_writer.py index bddbe48c2..556fb0737 100644 --- a/src/spdx/writer/tagvalue/extracted_licensing_info_writer.py +++ b/src/spdx/writer/tagvalue/extracted_licensing_info_writer.py @@ -11,7 +11,7 @@ from typing import TextIO from spdx.model.extracted_licensing_info import ExtractedLicensingInfo -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value def write_extracted_licensing_info(extracted_licensing_info: ExtractedLicensingInfo, text_output: TextIO): diff --git a/src/spdx/writer/tagvalue/file_writer.py b/src/spdx/writer/tagvalue/file_writer.py index a12473738..c2d055fbd 100644 --- a/src/spdx/writer/tagvalue/file_writer.py +++ b/src/spdx/writer/tagvalue/file_writer.py @@ -12,7 +12,7 @@ from spdx.model.file import File from spdx.writer.tagvalue.checksum_writer import write_checksum_to_tag_value -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value def write_file(file: File, text_output: TextIO): diff --git a/src/spdx/writer/tagvalue/package_writer.py b/src/spdx/writer/tagvalue/package_writer.py index 74e4adeb6..4a7924685 100644 --- a/src/spdx/writer/tagvalue/package_writer.py +++ b/src/spdx/writer/tagvalue/package_writer.py @@ -13,8 +13,12 @@ from spdx.datetime_conversions import datetime_to_iso_string from spdx.model.package import Package, PackageVerificationCode from spdx.writer.tagvalue.checksum_writer import write_checksum_to_tag_value -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value, \ - transform_enum_name_to_tv, write_actor +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import ( + transform_enum_name_to_tv, + write_actor, + write_text_value, + write_value, +) def write_package(package: Package, text_output: TextIO): @@ -52,8 +56,11 @@ def write_package(package: Package, text_output: TextIO): for external_reference in package.external_references: external_reference_str = " ".join( - [transform_enum_name_to_tv(external_reference.category.name), external_reference.reference_type, - external_reference.locator] + [ + transform_enum_name_to_tv(external_reference.category.name), + external_reference.reference_type, + external_reference.locator, + ] ) write_value("ExternalRef", external_reference_str, text_output) if external_reference.comment: @@ -63,8 +70,9 @@ def write_package(package: Package, text_output: TextIO): write_text_value("PackageAttributionText", attribution_text, text_output) if package.primary_package_purpose: - write_value("PrimaryPackagePurpose", transform_enum_name_to_tv(package.primary_package_purpose.name), - text_output) + write_value( + "PrimaryPackagePurpose", transform_enum_name_to_tv(package.primary_package_purpose.name), text_output + ) if package.release_date: write_value("ReleaseDate", datetime_to_iso_string(package.release_date), text_output) diff --git a/src/spdx/writer/tagvalue/relationship_writer.py b/src/spdx/writer/tagvalue/relationship_writer.py index 8972996df..9cf7425fc 100644 --- a/src/spdx/writer/tagvalue/relationship_writer.py +++ b/src/spdx/writer/tagvalue/relationship_writer.py @@ -11,11 +11,19 @@ from typing import TextIO from spdx.model.relationship import Relationship -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_text_value, write_value def write_relationship(relationship: Relationship, text_output: TextIO): - write_value("Relationship", " ".join( - [relationship.spdx_element_id, relationship.relationship_type.name, str(relationship.related_spdx_element_id)]), - text_output) + write_value( + "Relationship", + " ".join( + [ + relationship.spdx_element_id, + relationship.relationship_type.name, + str(relationship.related_spdx_element_id), + ] + ), + text_output, + ) write_text_value("RelationshipComment", relationship.comment, text_output) diff --git a/src/spdx/writer/tagvalue/snippet_writer.py b/src/spdx/writer/tagvalue/snippet_writer.py index eee6b6416..55230bb07 100644 --- a/src/spdx/writer/tagvalue/snippet_writer.py +++ b/src/spdx/writer/tagvalue/snippet_writer.py @@ -11,7 +11,8 @@ from typing import TextIO from spdx.model.snippet import Snippet -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_value, write_text_value, write_range +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_range, write_text_value, write_value + def write_snippet(snippet: Snippet, text_output: TextIO): text_output.write("## Snippet Information\n") diff --git a/src/spdx/writer/tagvalue/tagvalue_writer.py b/src/spdx/writer/tagvalue/tagvalue_writer.py index 92db6f2e1..3c94e3dc4 100644 --- a/src/spdx/writer/tagvalue/tagvalue_writer.py +++ b/src/spdx/writer/tagvalue/tagvalue_writer.py @@ -8,7 +8,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import TextIO, List +from typing import List, TextIO from spdx.model.document import Document from spdx.validation.document_validator import validate_full_spdx_document @@ -20,8 +20,13 @@ from spdx.writer.tagvalue.package_writer import write_package from spdx.writer.tagvalue.relationship_writer import write_relationship from spdx.writer.tagvalue.snippet_writer import write_snippet -from spdx.writer.tagvalue.tagvalue_writer_helper_functions import write_separator, scan_relationships, \ - get_file_ids_with_contained_snippets, write_optional_heading, write_list_of_elements +from spdx.writer.tagvalue.tagvalue_writer_helper_functions import ( + get_file_ids_with_contained_snippets, + scan_relationships, + write_list_of_elements, + write_optional_heading, + write_separator, +) def write_document_to_file(document: Document, file_name: str, validate: bool = True): @@ -35,13 +40,14 @@ def write_document_to_file(document: Document, file_name: str, validate: bool = def write_document(document: Document, text_output: TextIO): - relationships_to_write, contained_files_by_package_id = scan_relationships(document.relationships, - document.packages, document.files) + relationships_to_write, contained_files_by_package_id = scan_relationships( + document.relationships, document.packages, document.files + ) file_ids_with_contained_snippets = get_file_ids_with_contained_snippets(document.snippets, document.files) - packaged_file_ids = [file.spdx_id for files_list in contained_files_by_package_id.values() - for file in files_list] - filed_snippet_ids = [snippet.spdx_id for snippets_list in file_ids_with_contained_snippets.values() - for snippet in snippets_list] + packaged_file_ids = [file.spdx_id for files_list in contained_files_by_package_id.values() for file in files_list] + filed_snippet_ids = [ + snippet.spdx_id for snippets_list in file_ids_with_contained_snippets.values() for snippet in snippets_list + ] text_output.write("## Document Information\n") write_creation_info(document.creation_info, text_output) @@ -57,8 +63,9 @@ def write_document(document: Document, text_output: TextIO): write_file(file, text_output) write_separator(text_output) if file.spdx_id in file_ids_with_contained_snippets: - write_list_of_elements(file_ids_with_contained_snippets[file.spdx_id], write_snippet, text_output, - with_separator=True) + write_list_of_elements( + file_ids_with_contained_snippets[file.spdx_id], write_snippet, text_output, with_separator=True + ) for package in document.packages: write_package(package, text_output) @@ -68,12 +75,14 @@ def write_document(document: Document, text_output: TextIO): write_file(file, text_output) write_separator(text_output) if file.spdx_id in file_ids_with_contained_snippets: - write_list_of_elements(file_ids_with_contained_snippets[file.spdx_id], write_snippet, text_output, - with_separator=True) + write_list_of_elements( + file_ids_with_contained_snippets[file.spdx_id], write_snippet, text_output, with_separator=True + ) write_optional_heading(document.extracted_licensing_info, "## License Information\n", text_output) - write_list_of_elements(document.extracted_licensing_info, write_extracted_licensing_info, text_output, - with_separator=True) + write_list_of_elements( + document.extracted_licensing_info, write_extracted_licensing_info, text_output, with_separator=True + ) write_optional_heading(relationships_to_write, "## Relationships\n", text_output) write_list_of_elements(relationships_to_write, write_relationship, text_output) diff --git a/src/spdx/writer/tagvalue/tagvalue_writer_helper_functions.py b/src/spdx/writer/tagvalue/tagvalue_writer_helper_functions.py index 1f30c0f45..7b3ad849b 100644 --- a/src/spdx/writer/tagvalue/tagvalue_writer_helper_functions.py +++ b/src/spdx/writer/tagvalue/tagvalue_writer_helper_functions.py @@ -8,11 +8,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import TextIO, Tuple, List, Dict, Any, Union, Callable, Optional +from typing import Any, Callable, Dict, List, Optional, TextIO, Tuple, Union + +from license_expression import LicenseExpression from spdx.model.actor import Actor from spdx.model.file import File -from license_expression import LicenseExpression from spdx.model.package import Package from spdx.model.relationship import Relationship, RelationshipType from spdx.model.snippet import Snippet @@ -24,7 +25,9 @@ def write_separator(out: TextIO): out.write("\n") -def write_value(tag: str, value: Optional[Union[bool, str, SpdxNone, SpdxNoAssertion, LicenseExpression]], out: TextIO): +def write_value( + tag: str, value: Optional[Union[bool, str, SpdxNone, SpdxNoAssertion, LicenseExpression]], out: TextIO +): if value is not None: out.write(f"{tag}: {value}\n") @@ -50,8 +53,12 @@ def write_optional_heading(optional_field: Any, heading: str, text_output: TextI text_output.write(heading) -def write_list_of_elements(list_of_elements: List[Any], write_method: Callable[[Any, TextIO], None], - text_output: TextIO, with_separator: bool = False): +def write_list_of_elements( + list_of_elements: List[Any], + write_method: Callable[[Any, TextIO], None], + text_output: TextIO, + with_separator: bool = False, +): for element in list_of_elements: write_method(element, text_output) if with_separator: @@ -65,25 +72,32 @@ def write_actor(tag: str, element_to_write: Optional[Union[Actor, SpdxNoAssertio write_value(tag, element_to_write, text_output) -def scan_relationships(relationships: List[Relationship], packages: List[Package], files: List[File]) \ - -> Tuple[List, Dict]: +def scan_relationships( + relationships: List[Relationship], packages: List[Package], files: List[File] +) -> Tuple[List, Dict]: contained_files_by_package_id = dict() relationships_to_write = [] files_by_spdx_id = {file.spdx_id: file for file in files} packages_spdx_ids = [package.spdx_id for package in packages] for relationship in relationships: - if relationship.relationship_type == RelationshipType.CONTAINS and \ - relationship.spdx_element_id in packages_spdx_ids and \ - relationship.related_spdx_element_id in files_by_spdx_id.keys(): + if ( + relationship.relationship_type == RelationshipType.CONTAINS + and relationship.spdx_element_id in packages_spdx_ids + and relationship.related_spdx_element_id in files_by_spdx_id.keys() + ): contained_files_by_package_id.setdefault(relationship.spdx_element_id, []).append( - files_by_spdx_id[relationship.related_spdx_element_id]) + files_by_spdx_id[relationship.related_spdx_element_id] + ) if relationship.comment: relationships_to_write.append(relationship) - elif relationship.relationship_type == RelationshipType.CONTAINED_BY and \ - relationship.related_spdx_element_id in packages_spdx_ids and \ - relationship.spdx_element_id in files_by_spdx_id: + elif ( + relationship.relationship_type == RelationshipType.CONTAINED_BY + and relationship.related_spdx_element_id in packages_spdx_ids + and relationship.spdx_element_id in files_by_spdx_id + ): contained_files_by_package_id.setdefault(relationship.related_spdx_element_id, []).append( - files_by_spdx_id[relationship.spdx_element_id]) + files_by_spdx_id[relationship.spdx_element_id] + ) if relationship.comment: relationships_to_write.append(relationship) else: diff --git a/src/spdx/writer/write_anything.py b/src/spdx/writer/write_anything.py index 7f8c67c21..b3ba5248e 100644 --- a/src/spdx/writer/write_anything.py +++ b/src/spdx/writer/write_anything.py @@ -8,11 +8,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from spdx.writer.rdf import rdf_writer - -from spdx.formats import file_name_to_format, FileFormat +from spdx.formats import FileFormat, file_name_to_format from spdx.model.document import Document from spdx.writer.json import json_writer +from spdx.writer.rdf import rdf_writer from spdx.writer.tagvalue import tagvalue_writer from spdx.writer.xml import xml_writer from spdx.writer.yaml import yaml_writer diff --git a/src/spdx/writer/xml/xml_writer.py b/src/spdx/writer/xml/xml_writer.py index 369bbfedc..d347b7d6d 100644 --- a/src/spdx/writer/xml/xml_writer.py +++ b/src/spdx/writer/xml/xml_writer.py @@ -18,8 +18,9 @@ from spdx.validation.validation_message import ValidationMessage -def write_document_to_file(document: Document, file_name: str, validate: bool = True, - converter: DocumentConverter = None): +def write_document_to_file( + document: Document, file_name: str, validate: bool = True, converter: DocumentConverter = None +): """ Serializes the provided document to XML and writes it to a file with the provided name. Unless validate is set to False, validates the document before serialization. Unless a DocumentConverter instance is provided, diff --git a/src/spdx/writer/yaml/yaml_writer.py b/src/spdx/writer/yaml/yaml_writer.py index 2db63cb8c..2dc365f95 100644 --- a/src/spdx/writer/yaml/yaml_writer.py +++ b/src/spdx/writer/yaml/yaml_writer.py @@ -18,8 +18,9 @@ from spdx.validation.validation_message import ValidationMessage -def write_document_to_file(document: Document, file_name: str, validate: bool = True, - converter: DocumentConverter = None): +def write_document_to_file( + document: Document, file_name: str, validate: bool = True, converter: DocumentConverter = None +): """ Serializes the provided document to yaml and writes it to a file with the provided name. Unless validate is set to False, validates the document before serialization. Unless a DocumentConverter instance is provided, diff --git a/tests/spdx/fixtures.py b/tests/spdx/fixtures.py index 1158a87ef..6bfe9f72d 100644 --- a/tests/spdx/fixtures.py +++ b/tests/spdx/fixtures.py @@ -19,16 +19,21 @@ from spdx.model.external_document_ref import ExternalDocumentRef from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.model.file import File, FileType -from spdx.model.package import Package, PackageVerificationCode, PackagePurpose, ExternalPackageRef, \ - ExternalPackageRefCategory +from spdx.model.package import ( + ExternalPackageRef, + ExternalPackageRefCategory, + Package, + PackagePurpose, + PackageVerificationCode, +) from spdx.model.relationship import Relationship, RelationshipType from spdx.model.snippet import Snippet from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.model.version import Version -"""Utility methods to create data model instances. All properties have valid defaults, so they don't need to be -specified unless relevant for the test.""" +# Utility methods to create data model instances. All properties have valid defaults, so they don't need to be +# specified unless relevant for the test. def actor_fixture(actor_type=ActorType.PERSON, name="actorName", email="some@mail.com") -> Actor: @@ -39,125 +44,270 @@ def checksum_fixture(algorithm=ChecksumAlgorithm.SHA1, value="71c4025dd9897b364f return Checksum(algorithm, value) -def package_verification_code_fixture(value="85ed0817af83a24ad8da68c2b5094de69833983c", - excluded_files=None) -> PackageVerificationCode: +def package_verification_code_fixture( + value="85ed0817af83a24ad8da68c2b5094de69833983c", excluded_files=None +) -> PackageVerificationCode: excluded_files = ["./exclude.py"] if excluded_files is None else excluded_files return PackageVerificationCode(value, excluded_files) -def creation_info_fixture(spdx_version="SPDX-2.3", spdx_id="SPDXRef-DOCUMENT", name="documentName", - document_namespace="https://some.namespace", creators=None, created=datetime(2022, 12, 1), - creator_comment="creatorComment", data_license="CC0-1.0", external_document_refs=None, - license_list_version=Version(3, 19), document_comment="documentComment") -> CreationInfo: +def creation_info_fixture( + spdx_version="SPDX-2.3", + spdx_id="SPDXRef-DOCUMENT", + name="documentName", + document_namespace="https://some.namespace", + creators=None, + created=datetime(2022, 12, 1), + creator_comment="creatorComment", + data_license="CC0-1.0", + external_document_refs=None, + license_list_version=Version(3, 19), + document_comment="documentComment", +) -> CreationInfo: creators = [actor_fixture(name="creatorName")] if creators is None else creators - external_document_refs = [ - external_document_ref_fixture()] if external_document_refs is None else external_document_refs - return CreationInfo(spdx_version, spdx_id, name, document_namespace, creators, created, creator_comment, - data_license, - external_document_refs, license_list_version, document_comment) + external_document_refs = ( + [external_document_ref_fixture()] if external_document_refs is None else external_document_refs + ) + return CreationInfo( + spdx_version, + spdx_id, + name, + document_namespace, + creators, + created, + creator_comment, + data_license, + external_document_refs, + license_list_version, + document_comment, + ) -def file_fixture(name="./fileName.py", spdx_id="SPDXRef-File", checksums=None, file_types=None, - license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), license_info_in_file=None, - license_comment="licenseComment", copyright_text="copyrightText", comment="fileComment", - notice="fileNotice", contributors=None, attribution_texts=None) -> File: +def file_fixture( + name="./fileName.py", + spdx_id="SPDXRef-File", + checksums=None, + file_types=None, + license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), + license_info_in_file=None, + license_comment="licenseComment", + copyright_text="copyrightText", + comment="fileComment", + notice="fileNotice", + contributors=None, + attribution_texts=None, +) -> File: checksums = [checksum_fixture()] if checksums is None else checksums file_types = [FileType.TEXT] if file_types is None else file_types - license_info_in_file = [get_spdx_licensing().parse("MIT"), - get_spdx_licensing().parse("GPL-2.0"), - SpdxNoAssertion()] if license_info_in_file is None else license_info_in_file + license_info_in_file = ( + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNoAssertion()] + if license_info_in_file is None + else license_info_in_file + ) contributors = ["fileContributor"] if contributors is None else contributors attribution_texts = ["fileAttributionText"] if attribution_texts is None else attribution_texts - return File(name=name, spdx_id=spdx_id, checksums=checksums, file_types=file_types, - license_concluded=license_concluded, license_info_in_file=license_info_in_file, - license_comment=license_comment, copyright_text=copyright_text, comment=comment, notice=notice, - contributors=contributors, attribution_texts=attribution_texts) - - -def package_fixture(spdx_id="SPDXRef-Package", name="packageName", download_location="https://download.com", - version="12.2", file_name="./packageFileName", - supplier=actor_fixture(name="supplierName"), originator=actor_fixture(name="originatorName"), - files_analyzed=True, verification_code=package_verification_code_fixture(), checksums=None, - homepage="https://homepage.com", source_info="sourceInfo", - license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), license_info_from_files=None, - license_declared=get_spdx_licensing().parse("MIT and GPL-2.0"), - license_comment="packageLicenseComment", copyright_text="packageCopyrightText", - summary="packageSummary", description="packageDescription", comment="packageComment", - external_references=None, attribution_texts=None, primary_package_purpose=PackagePurpose.SOURCE, - release_date=datetime(2022, 12, 1), built_date=datetime(2022, 12, 2), - valid_until_date=datetime(2022, 12, 3)) -> Package: + return File( + name=name, + spdx_id=spdx_id, + checksums=checksums, + file_types=file_types, + license_concluded=license_concluded, + license_info_in_file=license_info_in_file, + license_comment=license_comment, + copyright_text=copyright_text, + comment=comment, + notice=notice, + contributors=contributors, + attribution_texts=attribution_texts, + ) + + +def package_fixture( + spdx_id="SPDXRef-Package", + name="packageName", + download_location="https://download.com", + version="12.2", + file_name="./packageFileName", + supplier=actor_fixture(name="supplierName"), + originator=actor_fixture(name="originatorName"), + files_analyzed=True, + verification_code=package_verification_code_fixture(), + checksums=None, + homepage="https://homepage.com", + source_info="sourceInfo", + license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), + license_info_from_files=None, + license_declared=get_spdx_licensing().parse("MIT and GPL-2.0"), + license_comment="packageLicenseComment", + copyright_text="packageCopyrightText", + summary="packageSummary", + description="packageDescription", + comment="packageComment", + external_references=None, + attribution_texts=None, + primary_package_purpose=PackagePurpose.SOURCE, + release_date=datetime(2022, 12, 1), + built_date=datetime(2022, 12, 2), + valid_until_date=datetime(2022, 12, 3), +) -> Package: checksums = [checksum_fixture()] if checksums is None else checksums - license_info_from_files = [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse( - "GPL-2.0"), SpdxNoAssertion()] if license_info_from_files is None else license_info_from_files + license_info_from_files = ( + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNoAssertion()] + if license_info_from_files is None + else license_info_from_files + ) external_references = [external_package_ref_fixture()] if external_references is None else external_references attribution_texts = ["packageAttributionText"] if attribution_texts is None else attribution_texts - return Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version, - file_name=file_name, supplier=supplier, originator=originator, files_analyzed=files_analyzed, - verification_code=verification_code, checksums=checksums, homepage=homepage, source_info=source_info, - license_concluded=license_concluded, license_info_from_files=license_info_from_files, - license_declared=license_declared, license_comment=license_comment, copyright_text=copyright_text, - summary=summary, description=description, comment=comment, external_references=external_references, - attribution_texts=attribution_texts, primary_package_purpose=primary_package_purpose, - release_date=release_date, built_date=built_date, valid_until_date=valid_until_date) - - -def external_document_ref_fixture(document_ref_id="DocumentRef-external", document_uri="https://namespace.com", - checksum=checksum_fixture()) -> ExternalDocumentRef: + return Package( + spdx_id=spdx_id, + name=name, + download_location=download_location, + version=version, + file_name=file_name, + supplier=supplier, + originator=originator, + files_analyzed=files_analyzed, + verification_code=verification_code, + checksums=checksums, + homepage=homepage, + source_info=source_info, + license_concluded=license_concluded, + license_info_from_files=license_info_from_files, + license_declared=license_declared, + license_comment=license_comment, + copyright_text=copyright_text, + summary=summary, + description=description, + comment=comment, + external_references=external_references, + attribution_texts=attribution_texts, + primary_package_purpose=primary_package_purpose, + release_date=release_date, + built_date=built_date, + valid_until_date=valid_until_date, + ) + + +def external_document_ref_fixture( + document_ref_id="DocumentRef-external", document_uri="https://namespace.com", checksum=checksum_fixture() +) -> ExternalDocumentRef: return ExternalDocumentRef(document_ref_id=document_ref_id, document_uri=document_uri, checksum=checksum) -def external_package_ref_fixture(category=ExternalPackageRefCategory.PACKAGE_MANAGER, - reference_type="maven-central", - locator="org.apache.tomcat:tomcat:9.0.0.M4", - comment="externalPackageRefComment") -> ExternalPackageRef: +def external_package_ref_fixture( + category=ExternalPackageRefCategory.PACKAGE_MANAGER, + reference_type="maven-central", + locator="org.apache.tomcat:tomcat:9.0.0.M4", + comment="externalPackageRefComment", +) -> ExternalPackageRef: return ExternalPackageRef(category=category, reference_type=reference_type, locator=locator, comment=comment) -def snippet_fixture(spdx_id="SPDXRef-Snippet", file_spdx_id="SPDXRef-File", byte_range=(1, 2), - line_range=(3, 4), license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), - license_info_in_snippet=None, license_comment="snippetLicenseComment", - copyright_text="licenseCopyrightText", comment="snippetComment", name="snippetName", - attribution_texts=None) -> Snippet: - license_info_in_snippet = [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse( - "GPL-2.0"), SpdxNone()] if license_info_in_snippet is None else license_info_in_snippet +def snippet_fixture( + spdx_id="SPDXRef-Snippet", + file_spdx_id="SPDXRef-File", + byte_range=(1, 2), + line_range=(3, 4), + license_concluded=get_spdx_licensing().parse("MIT and GPL-2.0"), + license_info_in_snippet=None, + license_comment="snippetLicenseComment", + copyright_text="licenseCopyrightText", + comment="snippetComment", + name="snippetName", + attribution_texts=None, +) -> Snippet: + license_info_in_snippet = ( + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNone()] + if license_info_in_snippet is None + else license_info_in_snippet + ) attribution_texts = ["snippetAttributionText"] if attribution_texts is None else attribution_texts - return Snippet(spdx_id=spdx_id, file_spdx_id=file_spdx_id, byte_range=byte_range, line_range=line_range, - license_concluded=license_concluded, license_info_in_snippet=license_info_in_snippet, - license_comment=license_comment, copyright_text=copyright_text, comment=comment, name=name, - attribution_texts=attribution_texts) + return Snippet( + spdx_id=spdx_id, + file_spdx_id=file_spdx_id, + byte_range=byte_range, + line_range=line_range, + license_concluded=license_concluded, + license_info_in_snippet=license_info_in_snippet, + license_comment=license_comment, + copyright_text=copyright_text, + comment=comment, + name=name, + attribution_texts=attribution_texts, + ) -def annotation_fixture(spdx_id="SPDXRef-File", annotation_type=AnnotationType.REVIEW, - annotator=actor_fixture(name="annotatorName"), annotation_date=datetime(2022, 12, 1), - annotation_comment="annotationComment") -> Annotation: - return Annotation(spdx_id=spdx_id, annotation_type=annotation_type, annotator=annotator, - annotation_date=annotation_date, annotation_comment=annotation_comment) +def annotation_fixture( + spdx_id="SPDXRef-File", + annotation_type=AnnotationType.REVIEW, + annotator=actor_fixture(name="annotatorName"), + annotation_date=datetime(2022, 12, 1), + annotation_comment="annotationComment", +) -> Annotation: + return Annotation( + spdx_id=spdx_id, + annotation_type=annotation_type, + annotator=annotator, + annotation_date=annotation_date, + annotation_comment=annotation_comment, + ) -def extracted_licensing_info_fixture(license_id="LicenseRef-1", extracted_text="extractedText", - license_name="licenseName", - cross_references=None, comment="licenseComment") -> ExtractedLicensingInfo: +def extracted_licensing_info_fixture( + license_id="LicenseRef-1", + extracted_text="extractedText", + license_name="licenseName", + cross_references=None, + comment="licenseComment", +) -> ExtractedLicensingInfo: cross_references = ["https://see.also"] if cross_references is None else cross_references - return ExtractedLicensingInfo(license_id=license_id, extracted_text=extracted_text, license_name=license_name, - cross_references=cross_references, comment=comment) + return ExtractedLicensingInfo( + license_id=license_id, + extracted_text=extracted_text, + license_name=license_name, + cross_references=cross_references, + comment=comment, + ) -def relationship_fixture(spdx_element_id="SPDXRef-DOCUMENT", relationship_type=RelationshipType.DESCRIBES, - related_spdx_element_id="SPDXRef-File", comment="relationshipComment") -> Relationship: - return Relationship(spdx_element_id=spdx_element_id, relationship_type=relationship_type, - related_spdx_element_id=related_spdx_element_id, comment=comment) +def relationship_fixture( + spdx_element_id="SPDXRef-DOCUMENT", + relationship_type=RelationshipType.DESCRIBES, + related_spdx_element_id="SPDXRef-File", + comment="relationshipComment", +) -> Relationship: + return Relationship( + spdx_element_id=spdx_element_id, + relationship_type=relationship_type, + related_spdx_element_id=related_spdx_element_id, + comment=comment, + ) -def document_fixture(creation_info=None, packages=None, files=None, snippets=None, annotations=None, relationships=None, - extracted_licensing_info=None) -> Document: +def document_fixture( + creation_info=None, + packages=None, + files=None, + snippets=None, + annotations=None, + relationships=None, + extracted_licensing_info=None, +) -> Document: creation_info = creation_info_fixture() if creation_info is None else creation_info packages = [package_fixture()] if packages is None else packages files = [file_fixture()] if files is None else files snippets = [snippet_fixture()] if snippets is None else snippets annotations = [annotation_fixture()] if annotations is None else annotations relationships = [relationship_fixture()] if relationships is None else relationships - extracted_licensing_info = [ - extracted_licensing_info_fixture()] if extracted_licensing_info is None else extracted_licensing_info - return Document(creation_info=creation_info, packages=packages, files=files, snippets=snippets, - annotations=annotations, relationships=relationships, - extracted_licensing_info=extracted_licensing_info) + extracted_licensing_info = ( + [extracted_licensing_info_fixture()] if extracted_licensing_info is None else extracted_licensing_info + ) + return Document( + creation_info=creation_info, + packages=packages, + files=files, + snippets=snippets, + annotations=annotations, + relationships=relationships, + extracted_licensing_info=extracted_licensing_info, + ) diff --git a/tests/spdx/jsonschema/test_annotation_converter.py b/tests/spdx/jsonschema/test_annotation_converter.py index b843ff275..15b2d17f8 100644 --- a/tests/spdx/jsonschema/test_annotation_converter.py +++ b/tests/spdx/jsonschema/test_annotation_converter.py @@ -24,10 +24,15 @@ def converter() -> AnnotationConverter: return AnnotationConverter() -@pytest.mark.parametrize("annotation_property,expected", [(AnnotationProperty.ANNOTATION_DATE, "annotationDate"), - (AnnotationProperty.ANNOTATION_TYPE, "annotationType"), - (AnnotationProperty.ANNOTATOR, "annotator"), - (AnnotationProperty.COMMENT, "comment")]) +@pytest.mark.parametrize( + "annotation_property,expected", + [ + (AnnotationProperty.ANNOTATION_DATE, "annotationDate"), + (AnnotationProperty.ANNOTATION_TYPE, "annotationType"), + (AnnotationProperty.ANNOTATOR, "annotator"), + (AnnotationProperty.COMMENT, "comment"), + ], +) def test_json_property_names(converter: AnnotationConverter, annotation_property: AnnotationProperty, expected: str): assert converter.json_property_name(annotation_property) == expected @@ -43,8 +48,7 @@ def test_data_model_type(converter: AnnotationConverter): def test_successful_conversion(converter: AnnotationConverter): date = datetime(2022, 12, 1) annotator = Actor(ActorType.PERSON, "actorName") - annotation = Annotation("spdxId", AnnotationType.REVIEW, annotator, - date, "comment") + annotation = Annotation("spdxId", AnnotationType.REVIEW, annotator, date, "comment") converted_dict = converter.convert(annotation) @@ -52,5 +56,5 @@ def test_successful_conversion(converter: AnnotationConverter): converter.json_property_name(AnnotationProperty.ANNOTATION_DATE): datetime_to_iso_string(date), converter.json_property_name(AnnotationProperty.ANNOTATION_TYPE): "REVIEW", converter.json_property_name(AnnotationProperty.ANNOTATOR): annotator.to_serialized_string(), - converter.json_property_name(AnnotationProperty.COMMENT): "comment" + converter.json_property_name(AnnotationProperty.COMMENT): "comment", } diff --git a/tests/spdx/jsonschema/test_checksum_converter.py b/tests/spdx/jsonschema/test_checksum_converter.py index 857745b7c..60393d7e6 100644 --- a/tests/spdx/jsonschema/test_checksum_converter.py +++ b/tests/spdx/jsonschema/test_checksum_converter.py @@ -20,8 +20,10 @@ def converter() -> ChecksumConverter: return ChecksumConverter() -@pytest.mark.parametrize("checksum_property,expected", [(ChecksumProperty.ALGORITHM, "algorithm"), - (ChecksumProperty.CHECKSUM_VALUE, "checksumValue")]) +@pytest.mark.parametrize( + "checksum_property,expected", + [(ChecksumProperty.ALGORITHM, "algorithm"), (ChecksumProperty.CHECKSUM_VALUE, "checksumValue")], +) def test_json_property_names(converter: ChecksumConverter, checksum_property: ChecksumProperty, expected: str): assert converter.json_property_name(checksum_property) == expected @@ -33,7 +35,7 @@ def test_successful_conversion(converter: ChecksumConverter): assert converted_dict == { converter.json_property_name(ChecksumProperty.ALGORITHM): "SHA1", - converter.json_property_name(ChecksumProperty.CHECKSUM_VALUE): "123" + converter.json_property_name(ChecksumProperty.CHECKSUM_VALUE): "123", } diff --git a/tests/spdx/jsonschema/test_converter.py b/tests/spdx/jsonschema/test_converter.py index daf337491..e5dff510b 100644 --- a/tests/spdx/jsonschema/test_converter.py +++ b/tests/spdx/jsonschema/test_converter.py @@ -9,16 +9,16 @@ # See the License for the specific language governing permissions and # limitations under the License. from enum import auto -from typing import Type, Any +from typing import Any, Type import pytest +from common.typing.dataclass_with_properties import dataclass_with_properties +from common.typing.type_checks import check_types_and_set_values from spdx.jsonschema.converter import TypedConverter from spdx.jsonschema.json_property import JsonProperty from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.model.document import Document -from common.typing.dataclass_with_properties import dataclass_with_properties -from common.typing.type_checks import check_types_and_set_values class TestPropertyType(JsonProperty): @@ -43,8 +43,9 @@ def json_property_name(self, test_property: TestPropertyType) -> str: else: return "jsonSecondName" - def _get_property_value(self, instance: TestDataModelType, test_property: TestPropertyType, - _document: Document = None) -> Any: + def _get_property_value( + self, instance: TestDataModelType, test_property: TestPropertyType, _document: Document = None + ) -> Any: if test_property == TestPropertyType.FIRST_NAME: return instance.first_property elif test_property == TestPropertyType.SECOND_NAME: @@ -63,10 +64,7 @@ def test_conversion(): converted_dict = converter.convert(test_instance) - assert converted_dict == { - "jsonFirstName": "firstPropertyValue", - "jsonSecondName": 3 - } + assert converted_dict == {"jsonFirstName": "firstPropertyValue", "jsonSecondName": 3} def test_wrong_type(): diff --git a/tests/spdx/jsonschema/test_creation_info_converter.py b/tests/spdx/jsonschema/test_creation_info_converter.py index 7e20cbbbe..f527b586f 100644 --- a/tests/spdx/jsonschema/test_creation_info_converter.py +++ b/tests/spdx/jsonschema/test_creation_info_converter.py @@ -26,12 +26,18 @@ def converter() -> CreationInfoConverter: return CreationInfoConverter() -@pytest.mark.parametrize("creation_info_property,expected", - [(CreationInfoProperty.CREATED, "created"), (CreationInfoProperty.CREATORS, "creators"), - (CreationInfoProperty.LICENSE_LIST_VERSION, "licenseListVersion"), - (CreationInfoProperty.COMMENT, "comment")]) -def test_json_property_names(converter: CreationInfoConverter, creation_info_property: CreationInfoProperty, - expected: str): +@pytest.mark.parametrize( + "creation_info_property,expected", + [ + (CreationInfoProperty.CREATED, "created"), + (CreationInfoProperty.CREATORS, "creators"), + (CreationInfoProperty.LICENSE_LIST_VERSION, "licenseListVersion"), + (CreationInfoProperty.COMMENT, "comment"), + ], +) +def test_json_property_names( + converter: CreationInfoConverter, creation_info_property: CreationInfoProperty, expected: str +): assert converter.json_property_name(creation_info_property) == expected @@ -40,14 +46,16 @@ def test_successful_conversion(converter: CreationInfoConverter): created = datetime(2022, 12, 1) converted_dict = converter.convert( - creation_info_fixture(creators=creators, created=created, creator_comment="comment", - license_list_version=Version(1, 2))) + creation_info_fixture( + creators=creators, created=created, creator_comment="comment", license_list_version=Version(1, 2) + ) + ) assert converted_dict == { converter.json_property_name(CreationInfoProperty.CREATED): datetime_to_iso_string(created), converter.json_property_name(CreationInfoProperty.CREATORS): ["Person: personName", "Tool: toolName"], converter.json_property_name(CreationInfoProperty.LICENSE_LIST_VERSION): "1.2", - converter.json_property_name(CreationInfoProperty.COMMENT): "comment" + converter.json_property_name(CreationInfoProperty.COMMENT): "comment", } diff --git a/tests/spdx/jsonschema/test_document_converter.py b/tests/spdx/jsonschema/test_document_converter.py index 0d5603fb4..8832b852f 100644 --- a/tests/spdx/jsonschema/test_document_converter.py +++ b/tests/spdx/jsonschema/test_document_converter.py @@ -24,24 +24,38 @@ from spdx.model.document import Document from spdx.model.extracted_licensing_info import ExtractedLicensingInfo from spdx.model.relationship import Relationship, RelationshipType -from tests.spdx.fixtures import creation_info_fixture, file_fixture, package_fixture, external_document_ref_fixture, \ - snippet_fixture, annotation_fixture, document_fixture, relationship_fixture +from tests.spdx.fixtures import ( + annotation_fixture, + creation_info_fixture, + document_fixture, + external_document_ref_fixture, + file_fixture, + package_fixture, + relationship_fixture, + snippet_fixture, +) from tests.spdx.mock_utils import assert_mock_method_called_with_arguments, assert_no_mock_methods_called @pytest.fixture -@mock.patch('spdx.jsonschema.creation_info_converter.CreationInfoConverter', autospec=True) -@mock.patch('spdx.jsonschema.external_document_ref_converter.ExternalDocumentRefConverter', autospec=True) -@mock.patch('spdx.jsonschema.package_converter.PackageConverter', autospec=True) -@mock.patch('spdx.jsonschema.annotation_converter.AnnotationConverter', autospec=True) -@mock.patch('spdx.jsonschema.extracted_licensing_info_converter.ExtractedLicensingInfoConverter', autospec=True) -@mock.patch('spdx.jsonschema.file_converter.FileConverter', autospec=True) -@mock.patch('spdx.jsonschema.snippet_converter.SnippetConverter', autospec=True) -@mock.patch('spdx.jsonschema.relationship_converter.RelationshipConverter', autospec=True) -def converter(relationship_converter_mock: MagicMock, snippet_converter_mock: MagicMock, file_converter_mock: MagicMock, - extracted_licensing_info_converter_mock: MagicMock, annotation_converter_mock: MagicMock, - package_converter_mock: MagicMock, external_ref_converter_mock: MagicMock, - creation_info_converter_mock: MagicMock) -> DocumentConverter: +@mock.patch("spdx.jsonschema.creation_info_converter.CreationInfoConverter", autospec=True) +@mock.patch("spdx.jsonschema.external_document_ref_converter.ExternalDocumentRefConverter", autospec=True) +@mock.patch("spdx.jsonschema.package_converter.PackageConverter", autospec=True) +@mock.patch("spdx.jsonschema.annotation_converter.AnnotationConverter", autospec=True) +@mock.patch("spdx.jsonschema.extracted_licensing_info_converter.ExtractedLicensingInfoConverter", autospec=True) +@mock.patch("spdx.jsonschema.file_converter.FileConverter", autospec=True) +@mock.patch("spdx.jsonschema.snippet_converter.SnippetConverter", autospec=True) +@mock.patch("spdx.jsonschema.relationship_converter.RelationshipConverter", autospec=True) +def converter( + relationship_converter_mock: MagicMock, + snippet_converter_mock: MagicMock, + file_converter_mock: MagicMock, + extracted_licensing_info_converter_mock: MagicMock, + annotation_converter_mock: MagicMock, + package_converter_mock: MagicMock, + external_ref_converter_mock: MagicMock, + creation_info_converter_mock: MagicMock, +) -> DocumentConverter: converter = DocumentConverter() converter.creation_info_converter = creation_info_converter_mock() converter.external_document_ref_converter = external_ref_converter_mock() @@ -54,32 +68,59 @@ def converter(relationship_converter_mock: MagicMock, snippet_converter_mock: Ma return converter -@pytest.mark.parametrize("document_property,expected", - [(DocumentProperty.SPDX_VERSION, "spdxVersion"), (DocumentProperty.SPDX_ID, "SPDXID"), - (DocumentProperty.NAME, "name"), (DocumentProperty.DOCUMENT_NAMESPACE, "documentNamespace"), - (DocumentProperty.DATA_LICENSE, "dataLicense"), - (DocumentProperty.EXTERNAL_DOCUMENT_REFS, "externalDocumentRefs"), - (DocumentProperty.COMMENT, "comment"), (DocumentProperty.CREATION_INFO, "creationInfo"), - (DocumentProperty.PACKAGES, "packages"), (DocumentProperty.FILES, "files"), - (DocumentProperty.SNIPPETS, "snippets"), (DocumentProperty.ANNOTATIONS, "annotations"), - (DocumentProperty.RELATIONSHIPS, "relationships"), - (DocumentProperty.HAS_EXTRACTED_LICENSING_INFOS, "hasExtractedLicensingInfos")]) -def test_json_property_names(converter: DocumentConverter, document_property: DocumentProperty, - expected: str): +@pytest.mark.parametrize( + "document_property,expected", + [ + (DocumentProperty.SPDX_VERSION, "spdxVersion"), + (DocumentProperty.SPDX_ID, "SPDXID"), + (DocumentProperty.NAME, "name"), + (DocumentProperty.DOCUMENT_NAMESPACE, "documentNamespace"), + (DocumentProperty.DATA_LICENSE, "dataLicense"), + (DocumentProperty.EXTERNAL_DOCUMENT_REFS, "externalDocumentRefs"), + (DocumentProperty.COMMENT, "comment"), + (DocumentProperty.CREATION_INFO, "creationInfo"), + (DocumentProperty.PACKAGES, "packages"), + (DocumentProperty.FILES, "files"), + (DocumentProperty.SNIPPETS, "snippets"), + (DocumentProperty.ANNOTATIONS, "annotations"), + (DocumentProperty.RELATIONSHIPS, "relationships"), + (DocumentProperty.HAS_EXTRACTED_LICENSING_INFOS, "hasExtractedLicensingInfos"), + ], +) +def test_json_property_names(converter: DocumentConverter, document_property: DocumentProperty, expected: str): assert converter.json_property_name(document_property) == expected def test_successful_conversion(converter: DocumentConverter): - creation_info = creation_info_fixture(spdx_version="spdxVersion", spdx_id="spdxId", name="name", - document_namespace="namespace", document_comment="comment", data_license="dataLicense", - external_document_refs=[external_document_ref_fixture()]) - document = Document(creation_info, annotations=[ - Annotation("annotationId", AnnotationType.REVIEW, Actor(ActorType.PERSON, "reviewerName"), - datetime(2022, 12, 1), "reviewComment")], - extracted_licensing_info=[ExtractedLicensingInfo("licenseId", "licenseText")], relationships=[ + creation_info = creation_info_fixture( + spdx_version="spdxVersion", + spdx_id="spdxId", + name="name", + document_namespace="namespace", + document_comment="comment", + data_license="dataLicense", + external_document_refs=[external_document_ref_fixture()], + ) + document = Document( + creation_info, + annotations=[ + Annotation( + "annotationId", + AnnotationType.REVIEW, + Actor(ActorType.PERSON, "reviewerName"), + datetime(2022, 12, 1), + "reviewComment", + ) + ], + extracted_licensing_info=[ExtractedLicensingInfo("licenseId", "licenseText")], + relationships=[ Relationship(creation_info.spdx_id, RelationshipType.DESCRIBES, "describedElementId"), - Relationship("relationshipOriginId", RelationshipType.AMENDS, "relationShipTargetId")], - packages=[package_fixture()], files=[file_fixture()], snippets=[snippet_fixture()]) + Relationship("relationshipOriginId", RelationshipType.AMENDS, "relationShipTargetId"), + ], + packages=[package_fixture()], + files=[file_fixture()], + snippets=[snippet_fixture()], + ) converter.external_document_ref_converter.convert.return_value = "mock_converted_external_ref" converter.creation_info_converter.convert.return_value = "mock_converted_creation_info" converter.package_converter.convert.return_value = "mock_converted_package" @@ -100,7 +141,8 @@ def test_successful_conversion(converter: DocumentConverter): converter.json_property_name(DocumentProperty.DATA_LICENSE): "dataLicense", converter.json_property_name(DocumentProperty.EXTERNAL_DOCUMENT_REFS): ["mock_converted_external_ref"], converter.json_property_name(DocumentProperty.HAS_EXTRACTED_LICENSING_INFOS): [ - "mock_converted_extracted_licensing_info"], + "mock_converted_extracted_licensing_info" + ], converter.json_property_name(DocumentProperty.NAME): "name", converter.json_property_name(DocumentProperty.SPDX_VERSION): "spdxVersion", converter.json_property_name(DocumentProperty.DOCUMENT_NAMESPACE): "namespace", @@ -108,7 +150,7 @@ def test_successful_conversion(converter: DocumentConverter): converter.json_property_name(DocumentProperty.PACKAGES): ["mock_converted_package"], converter.json_property_name(DocumentProperty.FILES): ["mock_converted_file"], converter.json_property_name(DocumentProperty.SNIPPETS): ["mock_converted_snippet"], - converter.json_property_name(DocumentProperty.RELATIONSHIPS): ["mock_converted_relationship"] + converter.json_property_name(DocumentProperty.RELATIONSHIPS): ["mock_converted_relationship"], } @@ -146,11 +188,20 @@ def test_document_annotations(converter: DocumentConverter): # those elements, so the document should receive the other two. document_annotation = annotation_fixture(spdx_id=document_id) other_annotation = annotation_fixture(spdx_id="otherId") - annotations = [annotation_fixture(spdx_id=file.spdx_id), annotation_fixture(spdx_id=package.spdx_id), - annotation_fixture(spdx_id=snippet.spdx_id), document_annotation, - other_annotation] - document = Document(creation_info_fixture(spdx_id=document_id), files=[file], packages=[package], - snippets=[snippet], annotations=annotations) + annotations = [ + annotation_fixture(spdx_id=file.spdx_id), + annotation_fixture(spdx_id=package.spdx_id), + annotation_fixture(spdx_id=snippet.spdx_id), + document_annotation, + other_annotation, + ] + document = Document( + creation_info_fixture(spdx_id=document_id), + files=[file], + packages=[package], + snippets=[snippet], + annotations=annotations, + ) # Weird type hint to make warnings about unresolved references from the mock class disappear annotation_converter: Union[AnnotationConverter, NonCallableMagicMock] = converter.annotation_converter @@ -166,23 +217,34 @@ def test_document_annotations(converter: DocumentConverter): def test_document_describes(converter: DocumentConverter): document = document_fixture() document_id = document.creation_info.spdx_id - document_describes_relationship = relationship_fixture(spdx_element_id=document_id, - relationship_type=RelationshipType.DESCRIBES, - related_spdx_element_id="describesId") - described_by_document_relationship = relationship_fixture(related_spdx_element_id=document_id, - relationship_type=RelationshipType.DESCRIBED_BY, - spdx_element_id="describedById") - other_describes_relationship = relationship_fixture(spdx_element_id="DocumentRef-external", - relationship_type=RelationshipType.DESCRIBES) + document_describes_relationship = relationship_fixture( + spdx_element_id=document_id, + relationship_type=RelationshipType.DESCRIBES, + related_spdx_element_id="describesId", + ) + described_by_document_relationship = relationship_fixture( + related_spdx_element_id=document_id, + relationship_type=RelationshipType.DESCRIBED_BY, + spdx_element_id="describedById", + ) + other_describes_relationship = relationship_fixture( + spdx_element_id="DocumentRef-external", relationship_type=RelationshipType.DESCRIBES + ) other_relationship = relationship_fixture(spdx_element_id=document_id, relationship_type=RelationshipType.CONTAINS) - document.relationships = [document_describes_relationship, described_by_document_relationship, - other_describes_relationship, other_relationship] + document.relationships = [ + document_describes_relationship, + described_by_document_relationship, + other_describes_relationship, + other_relationship, + ] converted_dict = converter.convert(document) document_describes = converted_dict.get(converter.json_property_name(DocumentProperty.DOCUMENT_DESCRIBES)) - assert document_describes == [document_describes_relationship.related_spdx_element_id, - described_by_document_relationship.spdx_element_id] + assert document_describes == [ + document_describes_relationship.related_spdx_element_id, + described_by_document_relationship.spdx_element_id, + ] DOCUMENT_ID = "docConverterTestDocumentId" @@ -190,26 +252,36 @@ def test_document_describes(converter: DocumentConverter): FILE_ID = "docConverterTestFileId" -@pytest.mark.parametrize("relationship,should_be_written", - [(relationship_fixture(DOCUMENT_ID, RelationshipType.DESCRIBES), True), - (relationship_fixture(DOCUMENT_ID, RelationshipType.DESCRIBES, comment=None), False), - (relationship_fixture(relationship_type=RelationshipType.DESCRIBED_BY, - related_spdx_element_id=DOCUMENT_ID), True), - (relationship_fixture(relationship_type=RelationshipType.DESCRIBED_BY, - related_spdx_element_id=DOCUMENT_ID, comment=None), False), - (relationship_fixture(DOCUMENT_ID, RelationshipType.AMENDS, comment=None), True), - (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, FILE_ID), True), - (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, FILE_ID, comment=None), False), - (relationship_fixture(FILE_ID, RelationshipType.CONTAINED_BY, PACKAGE_ID), True), - (relationship_fixture(FILE_ID, RelationshipType.CONTAINED_BY, PACKAGE_ID, comment=None), - False), - (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, comment=None), True), - (relationship_fixture(PACKAGE_ID, RelationshipType.COPY_OF, FILE_ID, comment=None), True)]) +@pytest.mark.parametrize( + "relationship,should_be_written", + [ + (relationship_fixture(DOCUMENT_ID, RelationshipType.DESCRIBES), True), + (relationship_fixture(DOCUMENT_ID, RelationshipType.DESCRIBES, comment=None), False), + ( + relationship_fixture(relationship_type=RelationshipType.DESCRIBED_BY, related_spdx_element_id=DOCUMENT_ID), + True, + ), + ( + relationship_fixture( + relationship_type=RelationshipType.DESCRIBED_BY, related_spdx_element_id=DOCUMENT_ID, comment=None + ), + False, + ), + (relationship_fixture(DOCUMENT_ID, RelationshipType.AMENDS, comment=None), True), + (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, FILE_ID), True), + (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, FILE_ID, comment=None), False), + (relationship_fixture(FILE_ID, RelationshipType.CONTAINED_BY, PACKAGE_ID), True), + (relationship_fixture(FILE_ID, RelationshipType.CONTAINED_BY, PACKAGE_ID, comment=None), False), + (relationship_fixture(PACKAGE_ID, RelationshipType.CONTAINS, comment=None), True), + (relationship_fixture(PACKAGE_ID, RelationshipType.COPY_OF, FILE_ID, comment=None), True), + ], +) def test_document_relationships(converter: DocumentConverter, relationship: Relationship, should_be_written: bool): package = package_fixture(spdx_id=PACKAGE_ID) file = file_fixture(spdx_id=FILE_ID) - document = document_fixture(creation_info_fixture(spdx_id=DOCUMENT_ID), packages=[package], files=[file], - relationships=[relationship]) + document = document_fixture( + creation_info_fixture(spdx_id=DOCUMENT_ID), packages=[package], files=[file], relationships=[relationship] + ) # Weird type hint to make warnings about unresolved references from the mock class disappear relationship_converter: Union[RelationshipConverter, NonCallableMagicMock] = converter.relationship_converter diff --git a/tests/spdx/jsonschema/test_external_document_ref_converter.py b/tests/spdx/jsonschema/test_external_document_ref_converter.py index dc85c42b9..53bfb3bd4 100644 --- a/tests/spdx/jsonschema/test_external_document_ref_converter.py +++ b/tests/spdx/jsonschema/test_external_document_ref_converter.py @@ -20,7 +20,7 @@ @pytest.fixture -@mock.patch('spdx.jsonschema.checksum_converter.ChecksumConverter', autospec=True) +@mock.patch("spdx.jsonschema.checksum_converter.ChecksumConverter", autospec=True) def converter(checksum_converter_magic_mock: MagicMock) -> ExternalDocumentRefConverter: mocked_checksum_converter = checksum_converter_magic_mock() converter = ExternalDocumentRefConverter() @@ -28,12 +28,17 @@ def converter(checksum_converter_magic_mock: MagicMock) -> ExternalDocumentRefCo return converter -@pytest.mark.parametrize("external_document_ref_property,expected", - [(ExternalDocumentRefProperty.EXTERNAL_DOCUMENT_ID, "externalDocumentId"), - (ExternalDocumentRefProperty.SPDX_DOCUMENT, "spdxDocument"), - (ExternalDocumentRefProperty.CHECKSUM, "checksum")]) -def test_json_property_names(converter: ExternalDocumentRefConverter, - external_document_ref_property: ExternalDocumentRefProperty, expected: str): +@pytest.mark.parametrize( + "external_document_ref_property,expected", + [ + (ExternalDocumentRefProperty.EXTERNAL_DOCUMENT_ID, "externalDocumentId"), + (ExternalDocumentRefProperty.SPDX_DOCUMENT, "spdxDocument"), + (ExternalDocumentRefProperty.CHECKSUM, "checksum"), + ], +) +def test_json_property_names( + converter: ExternalDocumentRefConverter, external_document_ref_property: ExternalDocumentRefProperty, expected: str +): assert converter.json_property_name(external_document_ref_property) == expected @@ -47,7 +52,7 @@ def test_successful_conversion(converter: ExternalDocumentRefConverter): assert converted_dict == { converter.json_property_name(ExternalDocumentRefProperty.EXTERNAL_DOCUMENT_ID): "document_ref_id", converter.json_property_name(ExternalDocumentRefProperty.SPDX_DOCUMENT): "document_uri", - converter.json_property_name(ExternalDocumentRefProperty.CHECKSUM): "mock_converted_checksum" + converter.json_property_name(ExternalDocumentRefProperty.CHECKSUM): "mock_converted_checksum", } diff --git a/tests/spdx/jsonschema/test_external_package_ref_converter.py b/tests/spdx/jsonschema/test_external_package_ref_converter.py index 64c61228e..323df18d4 100644 --- a/tests/spdx/jsonschema/test_external_package_ref_converter.py +++ b/tests/spdx/jsonschema/test_external_package_ref_converter.py @@ -20,13 +20,18 @@ def converter() -> ExternalPackageRefConverter: return ExternalPackageRefConverter() -@pytest.mark.parametrize("external_package_ref_property,expected", - [(ExternalPackageRefProperty.COMMENT, "comment"), - (ExternalPackageRefProperty.REFERENCE_CATEGORY, "referenceCategory"), - (ExternalPackageRefProperty.REFERENCE_LOCATOR, "referenceLocator"), - (ExternalPackageRefProperty.REFERENCE_TYPE, "referenceType")]) -def test_json_property_names(converter: ExternalPackageRefConverter, - external_package_ref_property: ExternalPackageRefProperty, expected: str): +@pytest.mark.parametrize( + "external_package_ref_property,expected", + [ + (ExternalPackageRefProperty.COMMENT, "comment"), + (ExternalPackageRefProperty.REFERENCE_CATEGORY, "referenceCategory"), + (ExternalPackageRefProperty.REFERENCE_LOCATOR, "referenceLocator"), + (ExternalPackageRefProperty.REFERENCE_TYPE, "referenceType"), + ], +) +def test_json_property_names( + converter: ExternalPackageRefConverter, external_package_ref_property: ExternalPackageRefProperty, expected: str +): assert converter.json_property_name(external_package_ref_property) == expected @@ -47,5 +52,5 @@ def test_successful_conversion(converter: ExternalPackageRefConverter): converter.json_property_name(ExternalPackageRefProperty.COMMENT): "comment", converter.json_property_name(ExternalPackageRefProperty.REFERENCE_CATEGORY): "PACKAGE_MANAGER", converter.json_property_name(ExternalPackageRefProperty.REFERENCE_LOCATOR): "locator", - converter.json_property_name(ExternalPackageRefProperty.REFERENCE_TYPE): "type" + converter.json_property_name(ExternalPackageRefProperty.REFERENCE_TYPE): "type", } diff --git a/tests/spdx/jsonschema/test_extracted_licensing_info_converter.py b/tests/spdx/jsonschema/test_extracted_licensing_info_converter.py index 05ec55a5f..7d62fa150 100644 --- a/tests/spdx/jsonschema/test_extracted_licensing_info_converter.py +++ b/tests/spdx/jsonschema/test_extracted_licensing_info_converter.py @@ -13,7 +13,7 @@ from spdx.jsonschema.extracted_licensing_info_converter import ExtractedLicensingInfoConverter from spdx.jsonschema.extracted_licensing_info_properties import ExtractedLicensingInfoProperty from spdx.model.extracted_licensing_info import ExtractedLicensingInfo -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion from tests.spdx.fixtures import extracted_licensing_info_fixture @@ -22,14 +22,21 @@ def converter() -> ExtractedLicensingInfoConverter: return ExtractedLicensingInfoConverter() -@pytest.mark.parametrize("extracted_licensing_info_property,expected", - [(ExtractedLicensingInfoProperty.LICENSE_ID, "licenseId"), - (ExtractedLicensingInfoProperty.EXTRACTED_TEXT, "extractedText"), - (ExtractedLicensingInfoProperty.NAME, "name"), - (ExtractedLicensingInfoProperty.COMMENT, "comment"), - (ExtractedLicensingInfoProperty.SEE_ALSOS, "seeAlsos")]) -def test_json_property_names(converter: ExtractedLicensingInfoConverter, - extracted_licensing_info_property: ExtractedLicensingInfoProperty, expected: str): +@pytest.mark.parametrize( + "extracted_licensing_info_property,expected", + [ + (ExtractedLicensingInfoProperty.LICENSE_ID, "licenseId"), + (ExtractedLicensingInfoProperty.EXTRACTED_TEXT, "extractedText"), + (ExtractedLicensingInfoProperty.NAME, "name"), + (ExtractedLicensingInfoProperty.COMMENT, "comment"), + (ExtractedLicensingInfoProperty.SEE_ALSOS, "seeAlsos"), + ], +) +def test_json_property_names( + converter: ExtractedLicensingInfoConverter, + extracted_licensing_info_property: ExtractedLicensingInfoProperty, + expected: str, +): assert converter.json_property_name(extracted_licensing_info_property) == expected @@ -42,9 +49,13 @@ def test_data_model_type(converter: ExtractedLicensingInfoConverter): def test_successful_conversion(converter: ExtractedLicensingInfoConverter): - extracted_licensing_info = ExtractedLicensingInfo(license_id="licenseId", extracted_text="Extracted text", - license_name="license name", - cross_references=["reference1", "reference2"], comment="comment") + extracted_licensing_info = ExtractedLicensingInfo( + license_id="licenseId", + extracted_text="Extracted text", + license_name="license name", + cross_references=["reference1", "reference2"], + comment="comment", + ) converted_dict = converter.convert(extracted_licensing_info) @@ -53,7 +64,7 @@ def test_successful_conversion(converter: ExtractedLicensingInfoConverter): converter.json_property_name(ExtractedLicensingInfoProperty.EXTRACTED_TEXT): "Extracted text", converter.json_property_name(ExtractedLicensingInfoProperty.NAME): "license name", converter.json_property_name(ExtractedLicensingInfoProperty.SEE_ALSOS): ["reference1", "reference2"], - converter.json_property_name(ExtractedLicensingInfoProperty.COMMENT): "comment" + converter.json_property_name(ExtractedLicensingInfoProperty.COMMENT): "comment", } @@ -74,4 +85,6 @@ def test_spdx_no_assertion(converter: ExtractedLicensingInfoConverter): converted_dict = converter.convert(extracted_licensing_info) - assert converted_dict[converter.json_property_name(ExtractedLicensingInfoProperty.NAME)] == SPDX_NO_ASSERTION_STRING + assert ( + converted_dict[converter.json_property_name(ExtractedLicensingInfoProperty.NAME)] == SPDX_NO_ASSERTION_STRING + ) diff --git a/tests/spdx/jsonschema/test_file_converter.py b/tests/spdx/jsonschema/test_file_converter.py index 51dd84ed0..e78e63681 100644 --- a/tests/spdx/jsonschema/test_file_converter.py +++ b/tests/spdx/jsonschema/test_file_converter.py @@ -14,6 +14,7 @@ from unittest.mock import MagicMock, NonCallableMagicMock import pytest +from license_expression import Licensing from spdx.jsonschema.annotation_converter import AnnotationConverter from spdx.jsonschema.file_converter import FileConverter @@ -23,16 +24,15 @@ from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.model.document import Document from spdx.model.file import File, FileType -from license_expression import Licensing -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING -from spdx.model.spdx_none import SpdxNone, SPDX_NONE_STRING -from tests.spdx.fixtures import creation_info_fixture, file_fixture, annotation_fixture, document_fixture +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion +from spdx.model.spdx_none import SPDX_NONE_STRING, SpdxNone +from tests.spdx.fixtures import annotation_fixture, creation_info_fixture, document_fixture, file_fixture from tests.spdx.mock_utils import assert_mock_method_called_with_arguments @pytest.fixture -@mock.patch('spdx.jsonschema.checksum_converter.ChecksumConverter', autospec=True) -@mock.patch('spdx.jsonschema.annotation_converter.AnnotationConverter', autospec=True) +@mock.patch("spdx.jsonschema.checksum_converter.ChecksumConverter", autospec=True) +@mock.patch("spdx.jsonschema.annotation_converter.AnnotationConverter", autospec=True) def converter(annotation_converter_mock: MagicMock, checksum_converter_mock: MagicMock) -> FileConverter: converter = FileConverter() converter.checksum_converter = checksum_converter_mock() @@ -40,22 +40,26 @@ def converter(annotation_converter_mock: MagicMock, checksum_converter_mock: Mag return converter -@pytest.mark.parametrize("file_property,expected", - [(FileProperty.SPDX_ID, "SPDXID"), - (FileProperty.ANNOTATIONS, "annotations"), - (FileProperty.ARTIFACT_OFS, "artifactOfs"), - (FileProperty.ATTRIBUTION_TEXTS, "attributionTexts"), - (FileProperty.CHECKSUMS, "checksums"), - (FileProperty.COMMENT, "comment"), - (FileProperty.COPYRIGHT_TEXT, "copyrightText"), - (FileProperty.FILE_CONTRIBUTORS, "fileContributors"), - (FileProperty.FILE_DEPENDENCIES, "fileDependencies"), - (FileProperty.FILE_NAME, "fileName"), - (FileProperty.FILE_TYPES, "fileTypes"), - (FileProperty.LICENSE_COMMENTS, "licenseComments"), - (FileProperty.LICENSE_CONCLUDED, "licenseConcluded"), - (FileProperty.LICENSE_INFO_IN_FILES, "licenseInfoInFiles"), - (FileProperty.NOTICE_TEXT, "noticeText")]) +@pytest.mark.parametrize( + "file_property,expected", + [ + (FileProperty.SPDX_ID, "SPDXID"), + (FileProperty.ANNOTATIONS, "annotations"), + (FileProperty.ARTIFACT_OFS, "artifactOfs"), + (FileProperty.ATTRIBUTION_TEXTS, "attributionTexts"), + (FileProperty.CHECKSUMS, "checksums"), + (FileProperty.COMMENT, "comment"), + (FileProperty.COPYRIGHT_TEXT, "copyrightText"), + (FileProperty.FILE_CONTRIBUTORS, "fileContributors"), + (FileProperty.FILE_DEPENDENCIES, "fileDependencies"), + (FileProperty.FILE_NAME, "fileName"), + (FileProperty.FILE_TYPES, "fileTypes"), + (FileProperty.LICENSE_COMMENTS, "licenseComments"), + (FileProperty.LICENSE_CONCLUDED, "licenseConcluded"), + (FileProperty.LICENSE_INFO_IN_FILES, "licenseInfoInFiles"), + (FileProperty.NOTICE_TEXT, "noticeText"), + ], +) def test_json_property_names(converter: FileConverter, file_property: FileProperty, expected: str): assert converter.json_property_name(file_property) == expected @@ -71,16 +75,30 @@ def test_data_model_type(converter: FileConverter): def test_successful_conversion(converter: FileConverter): converter.checksum_converter.convert.return_value = "mock_converted_checksum" converter.annotation_converter.convert.return_value = "mock_converted_annotation" - file = File(name="name", spdx_id="spdxId", - checksums=[Checksum(ChecksumAlgorithm.SHA224, "sha224"), Checksum(ChecksumAlgorithm.MD2, "md2")], - file_types=[FileType.SPDX, FileType.OTHER], license_concluded=Licensing().parse("MIT and GPL-2.0"), - license_info_in_file=[Licensing().parse("MIT"), Licensing().parse("GPL-2.0"), SpdxNoAssertion()], - license_comment="licenseComment", copyright_text="copyrightText", comment="comment", notice="notice", - contributors=["contributor1", "contributor2"], - attribution_texts=["attributionText1", "attributionText2"]) - - annotations = [Annotation(file.spdx_id, AnnotationType.REVIEW, Actor(ActorType.PERSON, "annotatorName"), - datetime(2022, 12, 5), "review comment")] + file = File( + name="name", + spdx_id="spdxId", + checksums=[Checksum(ChecksumAlgorithm.SHA224, "sha224"), Checksum(ChecksumAlgorithm.MD2, "md2")], + file_types=[FileType.SPDX, FileType.OTHER], + license_concluded=Licensing().parse("MIT and GPL-2.0"), + license_info_in_file=[Licensing().parse("MIT"), Licensing().parse("GPL-2.0"), SpdxNoAssertion()], + license_comment="licenseComment", + copyright_text="copyrightText", + comment="comment", + notice="notice", + contributors=["contributor1", "contributor2"], + attribution_texts=["attributionText1", "attributionText2"], + ) + + annotations = [ + Annotation( + file.spdx_id, + AnnotationType.REVIEW, + Actor(ActorType.PERSON, "annotatorName"), + datetime(2022, 12, 5), + "review comment", + ) + ] document = Document(creation_info_fixture(), files=[file], annotations=annotations) converted_dict = converter.convert(file, document) @@ -98,13 +116,23 @@ def test_successful_conversion(converter: FileConverter): converter.json_property_name(FileProperty.LICENSE_COMMENTS): "licenseComment", converter.json_property_name(FileProperty.LICENSE_CONCLUDED): "MIT AND GPL-2.0", converter.json_property_name(FileProperty.LICENSE_INFO_IN_FILES): ["MIT", "GPL-2.0", "NOASSERTION"], - converter.json_property_name(FileProperty.NOTICE_TEXT): "notice" + converter.json_property_name(FileProperty.NOTICE_TEXT): "notice", } def test_null_values(converter: FileConverter): - file = file_fixture(copyright_text=None, license_concluded=None, license_comment=None, comment=None, notice=None, - attribution_texts=[], checksums=[], contributors=[], file_types=[], license_info_in_file=[]) + file = file_fixture( + copyright_text=None, + license_concluded=None, + license_comment=None, + comment=None, + notice=None, + attribution_texts=[], + checksums=[], + contributors=[], + file_types=[], + license_info_in_file=[], + ) document = Document(creation_info_fixture(), files=[file]) converted_dict = converter.convert(file, document) @@ -123,16 +151,18 @@ def test_null_values(converter: FileConverter): def test_spdx_no_assertion(converter: FileConverter): - file = file_fixture(license_concluded=SpdxNoAssertion(), license_info_in_file=[SpdxNoAssertion()], - copyright_text=SpdxNoAssertion()) + file = file_fixture( + license_concluded=SpdxNoAssertion(), license_info_in_file=[SpdxNoAssertion()], copyright_text=SpdxNoAssertion() + ) document = Document(creation_info_fixture(), files=[file]) converted_dict = converter.convert(file, document) - assert converted_dict[ - converter.json_property_name(FileProperty.COPYRIGHT_TEXT)] == SPDX_NO_ASSERTION_STRING + assert converted_dict[converter.json_property_name(FileProperty.COPYRIGHT_TEXT)] == SPDX_NO_ASSERTION_STRING assert converted_dict[converter.json_property_name(FileProperty.LICENSE_CONCLUDED)] == SPDX_NO_ASSERTION_STRING - assert converted_dict[converter.json_property_name(FileProperty.LICENSE_INFO_IN_FILES)] == [SPDX_NO_ASSERTION_STRING] + assert converted_dict[converter.json_property_name(FileProperty.LICENSE_INFO_IN_FILES)] == [ + SPDX_NO_ASSERTION_STRING + ] def test_spdx_none(converter: FileConverter): @@ -141,8 +171,7 @@ def test_spdx_none(converter: FileConverter): converted_dict = converter.convert(file, document) - assert converted_dict[ - converter.json_property_name(FileProperty.COPYRIGHT_TEXT)] == SPDX_NONE_STRING + assert converted_dict[converter.json_property_name(FileProperty.COPYRIGHT_TEXT)] == SPDX_NONE_STRING assert converted_dict[converter.json_property_name(FileProperty.LICENSE_CONCLUDED)] == SPDX_NONE_STRING assert converted_dict[converter.json_property_name(FileProperty.LICENSE_INFO_IN_FILES)] == [SPDX_NONE_STRING] @@ -156,8 +185,14 @@ def test_file_annotations(converter: FileConverter): package_annotation = annotation_fixture(spdx_id=document.packages[0].spdx_id) snippet_annotation = annotation_fixture(spdx_id=document.snippets[0].spdx_id) other_annotation = annotation_fixture(spdx_id="otherId") - annotations = [first_file_annotation, second_file_annotation, document_annotation, package_annotation, - snippet_annotation, other_annotation] + annotations = [ + first_file_annotation, + second_file_annotation, + document_annotation, + package_annotation, + snippet_annotation, + other_annotation, + ] document.annotations = annotations # Weird type hint to make warnings about unresolved references from the mock class disappear @@ -166,7 +201,8 @@ def test_file_annotations(converter: FileConverter): converted_dict = converter.convert(file, document) - assert_mock_method_called_with_arguments(annotation_converter, "convert", first_file_annotation, - second_file_annotation) + assert_mock_method_called_with_arguments( + annotation_converter, "convert", first_file_annotation, second_file_annotation + ) converted_file_annotations = converted_dict.get(converter.json_property_name(FileProperty.ANNOTATIONS)) assert converted_file_annotations == ["mock_converted_annotation", "mock_converted_annotation"] diff --git a/tests/spdx/jsonschema/test_package_converter.py b/tests/spdx/jsonschema/test_package_converter.py index 4c2b18b37..31516fa0f 100644 --- a/tests/spdx/jsonschema/test_package_converter.py +++ b/tests/spdx/jsonschema/test_package_converter.py @@ -14,6 +14,7 @@ from unittest.mock import MagicMock, NonCallableMagicMock import pytest +from license_expression import Licensing from spdx.jsonschema.annotation_converter import AnnotationConverter from spdx.jsonschema.package_converter import PackageConverter @@ -22,23 +23,34 @@ from spdx.model.annotation import Annotation, AnnotationType from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.model.document import Document -from license_expression import Licensing -from spdx.model.package import Package, PackageVerificationCode, PackagePurpose +from spdx.model.package import Package, PackagePurpose, PackageVerificationCode from spdx.model.relationship import RelationshipType -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING -from spdx.model.spdx_none import SpdxNone, SPDX_NONE_STRING -from tests.spdx.fixtures import creation_info_fixture, package_fixture, external_package_ref_fixture, document_fixture, \ - annotation_fixture, file_fixture, relationship_fixture, snippet_fixture +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion +from spdx.model.spdx_none import SPDX_NONE_STRING, SpdxNone +from tests.spdx.fixtures import ( + annotation_fixture, + creation_info_fixture, + document_fixture, + external_package_ref_fixture, + file_fixture, + package_fixture, + relationship_fixture, + snippet_fixture, +) from tests.spdx.mock_utils import assert_mock_method_called_with_arguments @pytest.fixture -@mock.patch('spdx.jsonschema.checksum_converter.ChecksumConverter', autospec=True) -@mock.patch('spdx.jsonschema.annotation_converter.AnnotationConverter', autospec=True) -@mock.patch('spdx.jsonschema.package_verification_code_converter.PackageVerificationCodeConverter', autospec=True) -@mock.patch('spdx.jsonschema.external_package_ref_converter.ExternalPackageRefConverter', autospec=True) -def converter(package_ref_converter_mock: MagicMock, verification_code_converter_mock: MagicMock, - annotation_converter_mock: MagicMock, checksum_converter_mock: MagicMock) -> PackageConverter: +@mock.patch("spdx.jsonschema.checksum_converter.ChecksumConverter", autospec=True) +@mock.patch("spdx.jsonschema.annotation_converter.AnnotationConverter", autospec=True) +@mock.patch("spdx.jsonschema.package_verification_code_converter.PackageVerificationCodeConverter", autospec=True) +@mock.patch("spdx.jsonschema.external_package_ref_converter.ExternalPackageRefConverter", autospec=True) +def converter( + package_ref_converter_mock: MagicMock, + verification_code_converter_mock: MagicMock, + annotation_converter_mock: MagicMock, + checksum_converter_mock: MagicMock, +) -> PackageConverter: converter = PackageConverter() converter.checksum_converter = checksum_converter_mock() converter.annotation_converter = annotation_converter_mock() @@ -47,37 +59,42 @@ def converter(package_ref_converter_mock: MagicMock, verification_code_converter return converter -@pytest.mark.parametrize("external_package_ref_property,expected", - [(PackageProperty.SPDX_ID, "SPDXID"), - (PackageProperty.ANNOTATIONS, "annotations"), - (PackageProperty.ATTRIBUTION_TEXTS, "attributionTexts"), - (PackageProperty.BUILT_DATE, "builtDate"), - (PackageProperty.CHECKSUMS, "checksums"), - (PackageProperty.COMMENT, "comment"), - (PackageProperty.COPYRIGHT_TEXT, "copyrightText"), - (PackageProperty.DESCRIPTION, "description"), - (PackageProperty.DOWNLOAD_LOCATION, "downloadLocation"), - (PackageProperty.EXTERNAL_REFS, "externalRefs"), - (PackageProperty.FILES_ANALYZED, "filesAnalyzed"), - (PackageProperty.HAS_FILES, "hasFiles"), - (PackageProperty.HOMEPAGE, "homepage"), - (PackageProperty.LICENSE_COMMENTS, "licenseComments"), - (PackageProperty.LICENSE_CONCLUDED, "licenseConcluded"), - (PackageProperty.LICENSE_DECLARED, "licenseDeclared"), - (PackageProperty.LICENSE_INFO_FROM_FILES, "licenseInfoFromFiles"), - (PackageProperty.NAME, "name"), - (PackageProperty.ORIGINATOR, "originator"), - (PackageProperty.PACKAGE_FILE_NAME, "packageFileName"), - (PackageProperty.PACKAGE_VERIFICATION_CODE, "packageVerificationCode"), - (PackageProperty.PRIMARY_PACKAGE_PURPOSE, "primaryPackagePurpose"), - (PackageProperty.RELEASE_DATE, "releaseDate"), - (PackageProperty.SOURCE_INFO, "sourceInfo"), - (PackageProperty.SUMMARY, "summary"), - (PackageProperty.SUPPLIER, "supplier"), - (PackageProperty.VALID_UNTIL_DATE, "validUntilDate"), - (PackageProperty.VERSION_INFO, "versionInfo")]) -def test_json_property_names(converter: PackageConverter, - external_package_ref_property: PackageProperty, expected: str): +@pytest.mark.parametrize( + "external_package_ref_property,expected", + [ + (PackageProperty.SPDX_ID, "SPDXID"), + (PackageProperty.ANNOTATIONS, "annotations"), + (PackageProperty.ATTRIBUTION_TEXTS, "attributionTexts"), + (PackageProperty.BUILT_DATE, "builtDate"), + (PackageProperty.CHECKSUMS, "checksums"), + (PackageProperty.COMMENT, "comment"), + (PackageProperty.COPYRIGHT_TEXT, "copyrightText"), + (PackageProperty.DESCRIPTION, "description"), + (PackageProperty.DOWNLOAD_LOCATION, "downloadLocation"), + (PackageProperty.EXTERNAL_REFS, "externalRefs"), + (PackageProperty.FILES_ANALYZED, "filesAnalyzed"), + (PackageProperty.HAS_FILES, "hasFiles"), + (PackageProperty.HOMEPAGE, "homepage"), + (PackageProperty.LICENSE_COMMENTS, "licenseComments"), + (PackageProperty.LICENSE_CONCLUDED, "licenseConcluded"), + (PackageProperty.LICENSE_DECLARED, "licenseDeclared"), + (PackageProperty.LICENSE_INFO_FROM_FILES, "licenseInfoFromFiles"), + (PackageProperty.NAME, "name"), + (PackageProperty.ORIGINATOR, "originator"), + (PackageProperty.PACKAGE_FILE_NAME, "packageFileName"), + (PackageProperty.PACKAGE_VERIFICATION_CODE, "packageVerificationCode"), + (PackageProperty.PRIMARY_PACKAGE_PURPOSE, "primaryPackagePurpose"), + (PackageProperty.RELEASE_DATE, "releaseDate"), + (PackageProperty.SOURCE_INFO, "sourceInfo"), + (PackageProperty.SUMMARY, "summary"), + (PackageProperty.SUPPLIER, "supplier"), + (PackageProperty.VALID_UNTIL_DATE, "validUntilDate"), + (PackageProperty.VERSION_INFO, "versionInfo"), + ], +) +def test_json_property_names( + converter: PackageConverter, external_package_ref_property: PackageProperty, expected: str +): assert converter.json_property_name(external_package_ref_property) == expected @@ -94,24 +111,42 @@ def test_successful_conversion(converter: PackageConverter): converter.annotation_converter.convert.return_value = "mock_converted_annotation" converter.package_verification_code_converter.convert.return_value = "mock_converted_verification_code" converter.external_package_ref_converter.convert.return_value = "mock_package_ref" - package = Package(spdx_id="packageId", name="name", download_location="downloadLocation", version="version", - file_name="fileName", supplier=Actor(ActorType.PERSON, "supplierName"), - originator=Actor(ActorType.PERSON, "originatorName"), files_analyzed=True, - verification_code=PackageVerificationCode("value"), - checksums=[Checksum(ChecksumAlgorithm.SHA1, "sha1"), - Checksum(ChecksumAlgorithm.BLAKE2B_256, "blake")], homepage="homepage", - source_info="sourceInfo", license_concluded=Licensing().parse("MIT and GPL-2.0"), - license_info_from_files=[Licensing().parse("MIT"), - Licensing().parse("GPL-2.0")], - license_declared=Licensing().parse("MIT or GPL-2.0 "), license_comment="licenseComment", - copyright_text="copyrightText", summary="summary", description="description", comment="comment", - external_references=[external_package_ref_fixture()], - attribution_texts=["attributionText1", "attributionText2"], - primary_package_purpose=PackagePurpose.APPLICATION, release_date=datetime(2022, 12, 1), - built_date=datetime(2022, 12, 2), valid_until_date=datetime(2022, 12, 3)) - - annotation = Annotation(package.spdx_id, AnnotationType.REVIEW, Actor(ActorType.TOOL, "toolName"), - datetime(2022, 12, 5), "review comment") + package = Package( + spdx_id="packageId", + name="name", + download_location="downloadLocation", + version="version", + file_name="fileName", + supplier=Actor(ActorType.PERSON, "supplierName"), + originator=Actor(ActorType.PERSON, "originatorName"), + files_analyzed=True, + verification_code=PackageVerificationCode("value"), + checksums=[Checksum(ChecksumAlgorithm.SHA1, "sha1"), Checksum(ChecksumAlgorithm.BLAKE2B_256, "blake")], + homepage="homepage", + source_info="sourceInfo", + license_concluded=Licensing().parse("MIT and GPL-2.0"), + license_info_from_files=[Licensing().parse("MIT"), Licensing().parse("GPL-2.0")], + license_declared=Licensing().parse("MIT or GPL-2.0 "), + license_comment="licenseComment", + copyright_text="copyrightText", + summary="summary", + description="description", + comment="comment", + external_references=[external_package_ref_fixture()], + attribution_texts=["attributionText1", "attributionText2"], + primary_package_purpose=PackagePurpose.APPLICATION, + release_date=datetime(2022, 12, 1), + built_date=datetime(2022, 12, 2), + valid_until_date=datetime(2022, 12, 3), + ) + + annotation = Annotation( + package.spdx_id, + AnnotationType.REVIEW, + Actor(ActorType.TOOL, "toolName"), + datetime(2022, 12, 5), + "review comment", + ) document = Document(creation_info_fixture(), packages=[package], annotations=[annotation]) converted_dict = converter.convert(package, document) @@ -128,7 +163,10 @@ def test_successful_conversion(converter: PackageConverter): converter.json_property_name(PackageProperty.ORIGINATOR): "Person: originatorName", converter.json_property_name(PackageProperty.FILES_ANALYZED): True, converter.json_property_name(PackageProperty.PACKAGE_VERIFICATION_CODE): "mock_converted_verification_code", - converter.json_property_name(PackageProperty.CHECKSUMS): ["mock_converted_checksum", "mock_converted_checksum"], + converter.json_property_name(PackageProperty.CHECKSUMS): [ + "mock_converted_checksum", + "mock_converted_checksum", + ], converter.json_property_name(PackageProperty.HOMEPAGE): "homepage", converter.json_property_name(PackageProperty.SOURCE_INFO): "sourceInfo", converter.json_property_name(PackageProperty.LICENSE_CONCLUDED): "MIT AND GPL-2.0", @@ -143,17 +181,35 @@ def test_successful_conversion(converter: PackageConverter): converter.json_property_name(PackageProperty.PRIMARY_PACKAGE_PURPOSE): "APPLICATION", converter.json_property_name(PackageProperty.RELEASE_DATE): "2022-12-01T00:00:00Z", converter.json_property_name(PackageProperty.BUILT_DATE): "2022-12-02T00:00:00Z", - converter.json_property_name(PackageProperty.VALID_UNTIL_DATE): "2022-12-03T00:00:00Z" + converter.json_property_name(PackageProperty.VALID_UNTIL_DATE): "2022-12-03T00:00:00Z", } def test_null_values(converter: PackageConverter): - package = package_fixture(built_date=None, release_date=None, valid_until_date=None, homepage=None, - license_concluded=None, license_declared=None, originator=None, verification_code=None, - primary_package_purpose=None, supplier=None, version=None, file_name=None, - source_info=None, license_comment=None, copyright_text=None, summary=None, - description=None, comment=None, attribution_texts=[], checksums=[], - external_references=[], license_info_from_files=[]) + package = package_fixture( + built_date=None, + release_date=None, + valid_until_date=None, + homepage=None, + license_concluded=None, + license_declared=None, + originator=None, + verification_code=None, + primary_package_purpose=None, + supplier=None, + version=None, + file_name=None, + source_info=None, + license_comment=None, + copyright_text=None, + summary=None, + description=None, + comment=None, + attribution_texts=[], + checksums=[], + external_references=[], + license_info_from_files=[], + ) document = Document(creation_info_fixture(), packages=[package]) @@ -186,10 +242,16 @@ def test_null_values(converter: PackageConverter): def test_spdx_no_assertion(converter: PackageConverter): - package = package_fixture(download_location=SpdxNoAssertion(), supplier=SpdxNoAssertion(), - originator=SpdxNoAssertion(), homepage=SpdxNoAssertion(), - license_concluded=SpdxNoAssertion(), license_info_from_files=[SpdxNoAssertion()], - license_declared=SpdxNoAssertion(), copyright_text=SpdxNoAssertion()) + package = package_fixture( + download_location=SpdxNoAssertion(), + supplier=SpdxNoAssertion(), + originator=SpdxNoAssertion(), + homepage=SpdxNoAssertion(), + license_concluded=SpdxNoAssertion(), + license_info_from_files=[SpdxNoAssertion()], + license_declared=SpdxNoAssertion(), + copyright_text=SpdxNoAssertion(), + ) document = Document(creation_info_fixture(), packages=[package]) @@ -200,16 +262,22 @@ def test_spdx_no_assertion(converter: PackageConverter): assert converted_dict[converter.json_property_name(PackageProperty.ORIGINATOR)] == SPDX_NO_ASSERTION_STRING assert converted_dict[converter.json_property_name(PackageProperty.HOMEPAGE)] == SPDX_NO_ASSERTION_STRING assert converted_dict[converter.json_property_name(PackageProperty.LICENSE_CONCLUDED)] == SPDX_NO_ASSERTION_STRING - assert converted_dict[ - converter.json_property_name(PackageProperty.LICENSE_INFO_FROM_FILES)] == [SPDX_NO_ASSERTION_STRING] + assert converted_dict[converter.json_property_name(PackageProperty.LICENSE_INFO_FROM_FILES)] == [ + SPDX_NO_ASSERTION_STRING + ] assert converted_dict[converter.json_property_name(PackageProperty.LICENSE_DECLARED)] == SPDX_NO_ASSERTION_STRING assert converted_dict[converter.json_property_name(PackageProperty.COPYRIGHT_TEXT)] == SPDX_NO_ASSERTION_STRING def test_spdx_none(converter: PackageConverter): - package = package_fixture(download_location=SpdxNone(), homepage=SpdxNone(), - license_concluded=SpdxNone(), license_info_from_files=[SpdxNone()], - license_declared=SpdxNone(), copyright_text=SpdxNone()) + package = package_fixture( + download_location=SpdxNone(), + homepage=SpdxNone(), + license_concluded=SpdxNone(), + license_info_from_files=[SpdxNone()], + license_declared=SpdxNone(), + copyright_text=SpdxNone(), + ) document = Document(creation_info_fixture(), packages=[package]) @@ -232,8 +300,14 @@ def test_package_annotations(converter: PackageConverter): file_annotation = annotation_fixture(spdx_id=document.files[0].spdx_id) snippet_annotation = annotation_fixture(spdx_id=document.snippets[0].spdx_id) other_annotation = annotation_fixture(spdx_id="otherId") - annotations = [first_package_annotation, second_package_annotation, document_annotation, file_annotation, - snippet_annotation, other_annotation] + annotations = [ + first_package_annotation, + second_package_annotation, + document_annotation, + file_annotation, + snippet_annotation, + other_annotation, + ] document.annotations = annotations # Weird type hint to make warnings about unresolved references from the mock class disappear @@ -242,8 +316,9 @@ def test_package_annotations(converter: PackageConverter): converted_dict = converter.convert(package, document) - assert_mock_method_called_with_arguments(annotation_converter, "convert", first_package_annotation, - second_package_annotation) + assert_mock_method_called_with_arguments( + annotation_converter, "convert", first_package_annotation, second_package_annotation + ) converted_file_annotations = converted_dict.get(converter.json_property_name(PackageProperty.ANNOTATIONS)) assert converted_file_annotations == ["mock_converted_annotation", "mock_converted_annotation"] @@ -254,23 +329,35 @@ def test_has_files(converter: PackageConverter): second_contained_file = file_fixture(spdx_id="secondFileId") non_contained_file = file_fixture(spdx_id="otherFileId") snippet = snippet_fixture() - document = document_fixture(packages=[package], - files=[first_contained_file, second_contained_file, non_contained_file], - snippets=[snippet]) - package_contains_file_relationship = relationship_fixture(spdx_element_id=package.spdx_id, - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id=first_contained_file.spdx_id) - file_contained_in_package_relationship = relationship_fixture(spdx_element_id=second_contained_file.spdx_id, - relationship_type=RelationshipType.CONTAINED_BY, - related_spdx_element_id=package.spdx_id) - package_contains_snippet_relationship = relationship_fixture(spdx_element_id=package.spdx_id, - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id=snippet.spdx_id) - package_describes_file_relationship = relationship_fixture(spdx_element_id=package.spdx_id, - relationship_type=RelationshipType.DESCRIBES, - related_spdx_element_id=non_contained_file.spdx_id) - document.relationships = [package_contains_file_relationship, file_contained_in_package_relationship, - package_contains_snippet_relationship, package_describes_file_relationship] + document = document_fixture( + packages=[package], files=[first_contained_file, second_contained_file, non_contained_file], snippets=[snippet] + ) + package_contains_file_relationship = relationship_fixture( + spdx_element_id=package.spdx_id, + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id=first_contained_file.spdx_id, + ) + file_contained_in_package_relationship = relationship_fixture( + spdx_element_id=second_contained_file.spdx_id, + relationship_type=RelationshipType.CONTAINED_BY, + related_spdx_element_id=package.spdx_id, + ) + package_contains_snippet_relationship = relationship_fixture( + spdx_element_id=package.spdx_id, + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id=snippet.spdx_id, + ) + package_describes_file_relationship = relationship_fixture( + spdx_element_id=package.spdx_id, + relationship_type=RelationshipType.DESCRIBES, + related_spdx_element_id=non_contained_file.spdx_id, + ) + document.relationships = [ + package_contains_file_relationship, + file_contained_in_package_relationship, + package_contains_snippet_relationship, + package_describes_file_relationship, + ] converted_dict = converter.convert(package, document) diff --git a/tests/spdx/jsonschema/test_package_verification_code_converter.py b/tests/spdx/jsonschema/test_package_verification_code_converter.py index 2ee715484..66daf34e0 100644 --- a/tests/spdx/jsonschema/test_package_verification_code_converter.py +++ b/tests/spdx/jsonschema/test_package_verification_code_converter.py @@ -20,13 +20,21 @@ def converter() -> PackageVerificationCodeConverter: return PackageVerificationCodeConverter() -@pytest.mark.parametrize("package_verification_code_property,expected", - [(PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES, - "packageVerificationCodeExcludedFiles"), - (PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE, - "packageVerificationCodeValue")]) -def test_json_property_names(converter: PackageVerificationCodeConverter, - package_verification_code_property: PackageVerificationCodeProperty, expected: str): +@pytest.mark.parametrize( + "package_verification_code_property,expected", + [ + ( + PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES, + "packageVerificationCodeExcludedFiles", + ), + (PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE, "packageVerificationCodeValue"), + ], +) +def test_json_property_names( + converter: PackageVerificationCodeConverter, + package_verification_code_property: PackageVerificationCodeProperty, + expected: str, +): assert converter.json_property_name(package_verification_code_property) == expected @@ -45,8 +53,10 @@ def test_successful_conversion(converter: PackageVerificationCodeConverter): assert converted_dict == { converter.json_property_name(PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES): [ - "file1", "file2"], - converter.json_property_name(PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE): "value" + "file1", + "file2", + ], + converter.json_property_name(PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_VALUE): "value", } @@ -55,5 +65,7 @@ def test_null_values(converter: PackageVerificationCodeConverter): converted_dict = converter.convert(package_verification_code) - assert converter.json_property_name( - PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES) not in converted_dict + assert ( + converter.json_property_name(PackageVerificationCodeProperty.PACKAGE_VERIFICATION_CODE_EXCLUDED_FILES) + not in converted_dict + ) diff --git a/tests/spdx/jsonschema/test_relationship_converter.py b/tests/spdx/jsonschema/test_relationship_converter.py index f6d3d5050..d03d6271d 100644 --- a/tests/spdx/jsonschema/test_relationship_converter.py +++ b/tests/spdx/jsonschema/test_relationship_converter.py @@ -13,8 +13,8 @@ from spdx.jsonschema.relationship_converter import RelationshipConverter from spdx.jsonschema.relationship_properties import RelationshipProperty from spdx.model.relationship import Relationship, RelationshipType -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING -from spdx.model.spdx_none import SpdxNone, SPDX_NONE_STRING +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion +from spdx.model.spdx_none import SPDX_NONE_STRING, SpdxNone from tests.spdx.fixtures import relationship_fixture @@ -23,13 +23,18 @@ def converter() -> RelationshipConverter: return RelationshipConverter() -@pytest.mark.parametrize("relationship_property,expected", - [(RelationshipProperty.SPDX_ELEMENT_ID, "spdxElementId"), - (RelationshipProperty.COMMENT, "comment"), - (RelationshipProperty.RELATED_SPDX_ELEMENT, "relatedSpdxElement"), - (RelationshipProperty.RELATIONSHIP_TYPE, "relationshipType")]) -def test_json_property_names(converter: RelationshipConverter, relationship_property: RelationshipProperty, - expected: str): +@pytest.mark.parametrize( + "relationship_property,expected", + [ + (RelationshipProperty.SPDX_ELEMENT_ID, "spdxElementId"), + (RelationshipProperty.COMMENT, "comment"), + (RelationshipProperty.RELATED_SPDX_ELEMENT, "relatedSpdxElement"), + (RelationshipProperty.RELATIONSHIP_TYPE, "relationshipType"), + ], +) +def test_json_property_names( + converter: RelationshipConverter, relationship_property: RelationshipProperty, expected: str +): assert converter.json_property_name(relationship_property) == expected @@ -50,7 +55,7 @@ def test_successful_conversion(converter: RelationshipConverter): converter.json_property_name(RelationshipProperty.SPDX_ELEMENT_ID): "spdxElementId", converter.json_property_name(RelationshipProperty.COMMENT): "comment", converter.json_property_name(RelationshipProperty.RELATED_SPDX_ELEMENT): "relatedElementId", - converter.json_property_name(RelationshipProperty.RELATIONSHIP_TYPE): "COPY_OF" + converter.json_property_name(RelationshipProperty.RELATIONSHIP_TYPE): "COPY_OF", } @@ -59,8 +64,10 @@ def test_spdx_no_assertion(converter: RelationshipConverter): converted_dict = converter.convert(relationship) - assert converted_dict[ - converter.json_property_name(RelationshipProperty.RELATED_SPDX_ELEMENT)] == SPDX_NO_ASSERTION_STRING + assert ( + converted_dict[converter.json_property_name(RelationshipProperty.RELATED_SPDX_ELEMENT)] + == SPDX_NO_ASSERTION_STRING + ) def test_spdx_none(converter: RelationshipConverter): diff --git a/tests/spdx/jsonschema/test_snippet_converter.py b/tests/spdx/jsonschema/test_snippet_converter.py index 7752a2a6b..a77b70ea0 100644 --- a/tests/spdx/jsonschema/test_snippet_converter.py +++ b/tests/spdx/jsonschema/test_snippet_converter.py @@ -14,6 +14,7 @@ from unittest.mock import MagicMock, NonCallableMagicMock import pytest +from license_expression import Licensing from spdx.jsonschema.annotation_converter import AnnotationConverter from spdx.jsonschema.snippet_converter import SnippetConverter @@ -21,36 +22,38 @@ from spdx.model.actor import Actor, ActorType from spdx.model.annotation import Annotation, AnnotationType from spdx.model.document import Document -from license_expression import Licensing from spdx.model.snippet import Snippet -from spdx.model.spdx_no_assertion import SpdxNoAssertion, SPDX_NO_ASSERTION_STRING -from spdx.model.spdx_none import SpdxNone, SPDX_NONE_STRING -from tests.spdx.fixtures import creation_info_fixture, snippet_fixture, document_fixture, annotation_fixture +from spdx.model.spdx_no_assertion import SPDX_NO_ASSERTION_STRING, SpdxNoAssertion +from spdx.model.spdx_none import SPDX_NONE_STRING, SpdxNone +from tests.spdx.fixtures import annotation_fixture, creation_info_fixture, document_fixture, snippet_fixture from tests.spdx.mock_utils import assert_mock_method_called_with_arguments @pytest.fixture -@mock.patch('spdx.jsonschema.annotation_converter.AnnotationConverter', autospec=True) +@mock.patch("spdx.jsonschema.annotation_converter.AnnotationConverter", autospec=True) def converter(annotation_converter_mock: MagicMock) -> SnippetConverter: converter = SnippetConverter() converter.annotation_converter = annotation_converter_mock() return converter -@pytest.mark.parametrize("snippet_property,expected", - [(SnippetProperty.SPDX_ID, "SPDXID"), - (SnippetProperty.ANNOTATIONS, "annotations"), - (SnippetProperty.ATTRIBUTION_TEXTS, "attributionTexts"), - (SnippetProperty.COMMENT, "comment"), - (SnippetProperty.COPYRIGHT_TEXT, "copyrightText"), - (SnippetProperty.LICENSE_COMMENTS, "licenseComments"), - (SnippetProperty.LICENSE_CONCLUDED, "licenseConcluded"), - (SnippetProperty.LICENSE_INFO_IN_SNIPPETS, "licenseInfoInSnippets"), - (SnippetProperty.NAME, "name"), - (SnippetProperty.RANGES, "ranges"), - (SnippetProperty.SNIPPET_FROM_FILE, "snippetFromFile")]) -def test_json_property_names(converter: SnippetConverter, snippet_property: SnippetProperty, - expected: str): +@pytest.mark.parametrize( + "snippet_property,expected", + [ + (SnippetProperty.SPDX_ID, "SPDXID"), + (SnippetProperty.ANNOTATIONS, "annotations"), + (SnippetProperty.ATTRIBUTION_TEXTS, "attributionTexts"), + (SnippetProperty.COMMENT, "comment"), + (SnippetProperty.COPYRIGHT_TEXT, "copyrightText"), + (SnippetProperty.LICENSE_COMMENTS, "licenseComments"), + (SnippetProperty.LICENSE_CONCLUDED, "licenseConcluded"), + (SnippetProperty.LICENSE_INFO_IN_SNIPPETS, "licenseInfoInSnippets"), + (SnippetProperty.NAME, "name"), + (SnippetProperty.RANGES, "ranges"), + (SnippetProperty.SNIPPET_FROM_FILE, "snippetFromFile"), + ], +) +def test_json_property_names(converter: SnippetConverter, snippet_property: SnippetProperty, expected: str): assert converter.json_property_name(snippet_property) == expected @@ -65,15 +68,27 @@ def test_data_model_type(converter: SnippetConverter): def test_successful_conversion(converter: SnippetConverter): converter.annotation_converter.convert.return_value = "mock_converted_annotation" file_spdx_id = "fileSpdxId" - snippet = Snippet("spdxId", file_spdx_id=file_spdx_id, byte_range=(1, 2), line_range=(3, 4), - license_concluded=Licensing().parse("MIT and GPL-2.0"), - license_info_in_snippet=[Licensing().parse("MIT"), - Licensing().parse("GPL-2.0")], - license_comment="licenseComment", copyright_text="copyrightText", comment="comment", name="name", - attribution_texts=["attributionText1", "attributionText2"]) - - annotation = Annotation(snippet.spdx_id, AnnotationType.OTHER, Actor(ActorType.PERSON, "annotatorName"), - datetime(2022, 12, 5), "other comment") + snippet = Snippet( + "spdxId", + file_spdx_id=file_spdx_id, + byte_range=(1, 2), + line_range=(3, 4), + license_concluded=Licensing().parse("MIT and GPL-2.0"), + license_info_in_snippet=[Licensing().parse("MIT"), Licensing().parse("GPL-2.0")], + license_comment="licenseComment", + copyright_text="copyrightText", + comment="comment", + name="name", + attribution_texts=["attributionText1", "attributionText2"], + ) + + annotation = Annotation( + snippet.spdx_id, + AnnotationType.OTHER, + Actor(ActorType.PERSON, "annotatorName"), + datetime(2022, 12, 5), + "other comment", + ) document = Document(creation_info_fixture(), snippets=[snippet], annotations=[annotation]) converted_dict = converter.convert(snippet, document) @@ -88,17 +103,29 @@ def test_successful_conversion(converter: SnippetConverter): converter.json_property_name(SnippetProperty.LICENSE_INFO_IN_SNIPPETS): ["MIT", "GPL-2.0"], converter.json_property_name(SnippetProperty.NAME): "name", converter.json_property_name(SnippetProperty.RANGES): [ - {"startPointer": {"reference": file_spdx_id, "offset": 1}, - "endPointer": {"reference": file_spdx_id, "offset": 2}}, - {"startPointer": {"reference": file_spdx_id, "lineNumber": 3}, - "endPointer": {"reference": file_spdx_id, "lineNumber": 4}}], - converter.json_property_name(SnippetProperty.SNIPPET_FROM_FILE): file_spdx_id + { + "startPointer": {"reference": file_spdx_id, "offset": 1}, + "endPointer": {"reference": file_spdx_id, "offset": 2}, + }, + { + "startPointer": {"reference": file_spdx_id, "lineNumber": 3}, + "endPointer": {"reference": file_spdx_id, "lineNumber": 4}, + }, + ], + converter.json_property_name(SnippetProperty.SNIPPET_FROM_FILE): file_spdx_id, } def test_null_values(converter: SnippetConverter): - snippet = snippet_fixture(license_concluded=None, license_comment=None, copyright_text=None, comment=None, - name=None, attribution_texts=[], license_info_in_snippet=[]) + snippet = snippet_fixture( + license_concluded=None, + license_comment=None, + copyright_text=None, + comment=None, + name=None, + attribution_texts=[], + license_info_in_snippet=[], + ) document = Document(creation_info_fixture(), snippets=[snippet]) converted_dict = converter.convert(snippet, document) @@ -121,7 +148,8 @@ def test_spdx_no_assertion(converter: SnippetConverter): assert converted_dict[converter.json_property_name(SnippetProperty.LICENSE_CONCLUDED)] == SPDX_NO_ASSERTION_STRING assert converted_dict[converter.json_property_name(SnippetProperty.LICENSE_INFO_IN_SNIPPETS)] == [ - SPDX_NO_ASSERTION_STRING] + SPDX_NO_ASSERTION_STRING + ] def test_spdx_none(converter: SnippetConverter): @@ -143,8 +171,14 @@ def test_snippet_annotations(converter: SnippetConverter): package_annotation = annotation_fixture(spdx_id=document.packages[0].spdx_id) file_annotation = annotation_fixture(spdx_id=document.files[0].spdx_id) other_annotation = annotation_fixture(spdx_id="otherId") - annotations = [first_snippet_annotation, second_snippet_annotation, document_annotation, package_annotation, - file_annotation, other_annotation] + annotations = [ + first_snippet_annotation, + second_snippet_annotation, + document_annotation, + package_annotation, + file_annotation, + other_annotation, + ] document.annotations = annotations # Weird type hint to make warnings about unresolved references from the mock class disappear @@ -153,7 +187,8 @@ def test_snippet_annotations(converter: SnippetConverter): converted_dict = converter.convert(snippet, document) - assert_mock_method_called_with_arguments(annotation_converter, "convert", first_snippet_annotation, - second_snippet_annotation) + assert_mock_method_called_with_arguments( + annotation_converter, "convert", first_snippet_annotation, second_snippet_annotation + ) converted_file_annotations = converted_dict.get(converter.json_property_name(SnippetProperty.ANNOTATIONS)) assert converted_file_annotations == ["mock_converted_annotation", "mock_converted_annotation"] diff --git a/tests/spdx/model/test_actor.py b/tests/spdx/model/test_actor.py index 9a0ba5a14..ff8398ebf 100644 --- a/tests/spdx/model/test_actor.py +++ b/tests/spdx/model/test_actor.py @@ -38,14 +38,16 @@ def test_wrong_type_in_email_after_initializing(): actor.email = [] -@pytest.mark.parametrize("actor,expected_string", [(Actor(ActorType.PERSON, "personName"), "Person: personName"), - (Actor(ActorType.PERSON, "personName", "personEmail"), - "Person: personName (personEmail)"), - (Actor(ActorType.ORGANIZATION, "orgName"), "Organization: orgName"), - (Actor(ActorType.ORGANIZATION, "orgName", "orgEmail"), - "Organization: orgName (orgEmail)"), - (Actor(ActorType.TOOL, "toolName"), "Tool: toolName"), - (Actor(ActorType.TOOL, "toolName", "toolEmail"), - "Tool: toolName (toolEmail)")]) +@pytest.mark.parametrize( + "actor,expected_string", + [ + (Actor(ActorType.PERSON, "personName"), "Person: personName"), + (Actor(ActorType.PERSON, "personName", "personEmail"), "Person: personName (personEmail)"), + (Actor(ActorType.ORGANIZATION, "orgName"), "Organization: orgName"), + (Actor(ActorType.ORGANIZATION, "orgName", "orgEmail"), "Organization: orgName (orgEmail)"), + (Actor(ActorType.TOOL, "toolName"), "Tool: toolName"), + (Actor(ActorType.TOOL, "toolName", "toolEmail"), "Tool: toolName (toolEmail)"), + ], +) def test_serialization(actor: Actor, expected_string: str): assert actor.to_serialized_string() == expected_string diff --git a/tests/spdx/model/test_annotation.py b/tests/spdx/model/test_annotation.py index c2d357c43..1caab2ccb 100644 --- a/tests/spdx/model/test_annotation.py +++ b/tests/spdx/model/test_annotation.py @@ -6,7 +6,7 @@ from spdx.model.annotation import Annotation, AnnotationType -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_correct_initialization(actor): annotation = Annotation("id", AnnotationType.OTHER, actor, datetime(2022, 1, 1), "comment") assert annotation.spdx_id == "id" @@ -16,31 +16,31 @@ def test_correct_initialization(actor): assert annotation.annotation_comment == "comment" -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_spdx_id(actor): with pytest.raises(TypeError): Annotation(42, AnnotationType.OTHER, actor, datetime(2022, 1, 1), "comment") -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_annotation_type(actor): with pytest.raises(TypeError): Annotation("id", 42, actor, datetime(2022, 1, 1), "comment") -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_annotator(actor): with pytest.raises(TypeError): Annotation("id", AnnotationType.OTHER, 42, datetime(2022, 1, 1), "comment") -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_annotation_date(actor): with pytest.raises(TypeError): Annotation("id", AnnotationType.OTHER, actor, 42, "comment") -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_annotation_comment(actor): with pytest.raises(TypeError): Annotation("id", AnnotationType.OTHER, actor, datetime(2022, 1, 1), 42) diff --git a/tests/spdx/model/test_creation_info.py b/tests/spdx/model/test_creation_info.py index 70be62dc7..0d7213135 100644 --- a/tests/spdx/model/test_creation_info.py +++ b/tests/spdx/model/test_creation_info.py @@ -7,11 +7,22 @@ from spdx.model.version import Version -@mock.patch('spdx.model.external_document_ref.ExternalDocumentRef', autospec=True) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.external_document_ref.ExternalDocumentRef", autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_correct_initialization(actor, ext_ref): - creation_info = CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), - "creator_comment", "CC0-1.1", [ext_ref, ext_ref], Version(6, 3), "doc_comment") + creation_info = CreationInfo( + "version", + "id", + "name", + "namespace", + [actor, actor], + datetime(2022, 1, 1), + "creator_comment", + "CC0-1.1", + [ext_ref, ext_ref], + Version(6, 3), + "doc_comment", + ) assert creation_info.spdx_version == "version" assert creation_info.spdx_id == "id" assert creation_info.name == "name" @@ -25,25 +36,25 @@ def test_correct_initialization(actor, ext_ref): assert creation_info.document_comment == "doc_comment" -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_spdx_version(actor): with pytest.raises(TypeError): CreationInfo(42, "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1)) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_spdx_id(actor): with pytest.raises(TypeError): CreationInfo("version", 42, "name", "namespace", [actor, actor], datetime(2022, 1, 1)) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_name(actor): with pytest.raises(TypeError): CreationInfo("version", "id", 42, "namespace", [actor, actor], datetime(2022, 1, 1)) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_document_namespace(actor): with pytest.raises(TypeError): CreationInfo("version", "id", "name", 42, [actor, actor], datetime(2022, 1, 1)) @@ -54,40 +65,45 @@ def test_wrong_type_in_creators(): CreationInfo("version", "id", "name", "namespace", ["person"], datetime(2022, 1, 1)) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_created(actor): with pytest.raises(TypeError): CreationInfo("version", "id", "name", "namespace", [actor, actor], "2022-01-01") -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_creator_comment(actor): with pytest.raises(TypeError): - CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), - creator_comment=["string"]) + CreationInfo( + "version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), creator_comment=["string"] + ) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_data_license(actor): with pytest.raises(TypeError): CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), data_license=42) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_external_document_refs(actor): with pytest.raises(TypeError): - CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), - external_document_refs=()) + CreationInfo( + "version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), external_document_refs=() + ) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_license_list_version(actor): with pytest.raises(TypeError): - CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), - license_list_version="6.4") + CreationInfo( + "version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), license_list_version="6.4" + ) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_wrong_type_in_document_comment(actor): with pytest.raises(TypeError): - CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), document_comment=["1"]) + CreationInfo( + "version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), document_comment=["1"] + ) diff --git a/tests/spdx/model/test_document.py b/tests/spdx/model/test_document.py index c60742587..35fa3f176 100644 --- a/tests/spdx/model/test_document.py +++ b/tests/spdx/model/test_document.py @@ -5,17 +5,23 @@ from spdx.model.document import Document -@mock.patch('spdx.model.extracted_licensing_info.ExtractedLicensingInfo', autospec=True) -@mock.patch('spdx.model.relationship.Relationship', autospec=True) -@mock.patch('spdx.model.annotation.Annotation', autospec=True) -@mock.patch('spdx.model.snippet.Snippet', autospec=True) -@mock.patch('spdx.model.file.File', autospec=True) -@mock.patch('spdx.model.package.Package', autospec=True) -@mock.patch('spdx.model.document.CreationInfo', autospec=True) -def test_correct_initialization(creation_info, package, file, snippet, annotation, relationship, - extracted_lic): - document = Document(creation_info, [package, package], [file, file], [snippet, snippet], [annotation, annotation], - [relationship, relationship], [extracted_lic, extracted_lic]) +@mock.patch("spdx.model.extracted_licensing_info.ExtractedLicensingInfo", autospec=True) +@mock.patch("spdx.model.relationship.Relationship", autospec=True) +@mock.patch("spdx.model.annotation.Annotation", autospec=True) +@mock.patch("spdx.model.snippet.Snippet", autospec=True) +@mock.patch("spdx.model.file.File", autospec=True) +@mock.patch("spdx.model.package.Package", autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) +def test_correct_initialization(creation_info, package, file, snippet, annotation, relationship, extracted_lic): + document = Document( + creation_info, + [package, package], + [file, file], + [snippet, snippet], + [annotation, annotation], + [relationship, relationship], + [extracted_lic, extracted_lic], + ) assert document.creation_info == creation_info assert document.packages == [package, package] assert document.files == [file, file] @@ -25,7 +31,7 @@ def test_correct_initialization(creation_info, package, file, snippet, annotatio assert document.extracted_licensing_info == [extracted_lic, extracted_lic] -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_correct_initialization_with_default_values(creation_info): document = Document(creation_info) assert document.creation_info == creation_info @@ -42,37 +48,37 @@ def test_wrong_type_in_creation_info(): Document("string") -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_packages(creation_info): with pytest.raises(TypeError): Document(creation_info, packages=["string"]) -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_files(creation_info): with pytest.raises(TypeError): Document(creation_info, files={}) -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_snippets(creation_info): with pytest.raises(TypeError): Document(creation_info, snippets=()) -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_annotations(creation_info): with pytest.raises(TypeError): Document(creation_info, annotations=["string"]) -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_relationships(creation_info): with pytest.raises(TypeError): Document(creation_info, relationships="string") -@mock.patch('spdx.model.document.CreationInfo', autospec=True) +@mock.patch("spdx.model.document.CreationInfo", autospec=True) def test_wrong_type_in_extracted_licensing_info(creation_info): with pytest.raises(TypeError): Document(creation_info, extracted_licensing_info=42) diff --git a/tests/spdx/model/test_external_document_ref.py b/tests/spdx/model/test_external_document_ref.py index c210910af..28c2829cf 100644 --- a/tests/spdx/model/test_external_document_ref.py +++ b/tests/spdx/model/test_external_document_ref.py @@ -5,7 +5,7 @@ from spdx.model.external_document_ref import ExternalDocumentRef -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_correct_initialization(checksum): external_document_ref = ExternalDocumentRef("id", "uri", checksum) assert external_document_ref.document_ref_id == "id" @@ -13,13 +13,13 @@ def test_correct_initialization(checksum): assert external_document_ref.checksum == checksum -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_spdx_id(checksum): with pytest.raises(TypeError): ExternalDocumentRef(42, "uri", checksum) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_document_uri(checksum): with pytest.raises(TypeError): ExternalDocumentRef("id", 42, checksum) diff --git a/tests/spdx/model/test_external_package_reference.py b/tests/spdx/model/test_external_package_reference.py index 768e56329..74027bd9f 100644 --- a/tests/spdx/model/test_external_package_reference.py +++ b/tests/spdx/model/test_external_package_reference.py @@ -4,8 +4,7 @@ def test_correct_initialization(): - external_package_reference = ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator", - "comment") + external_package_reference = ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator", "comment") assert external_package_reference.category == ExternalPackageRefCategory.OTHER assert external_package_reference.reference_type == "type" assert external_package_reference.locator == "locator" diff --git a/tests/spdx/model/test_file.py b/tests/spdx/model/test_file.py index 70ecab4a6..d6ea58e74 100644 --- a/tests/spdx/model/test_file.py +++ b/tests/spdx/model/test_file.py @@ -8,10 +8,22 @@ from spdx.model.spdx_none import SpdxNone -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_correct_initialization(checksum): - file = File("name", "id", [checksum, checksum], [FileType.OTHER, FileType.SPDX], SpdxNone(), [SpdxNoAssertion()], - "comment on license", "copyright", "comment", "notice", ["contributor"], ["attribution"]) + file = File( + "name", + "id", + [checksum, checksum], + [FileType.OTHER, FileType.SPDX], + SpdxNone(), + [SpdxNoAssertion()], + "comment on license", + "copyright", + "comment", + "notice", + ["contributor"], + ["attribution"], + ) assert file.name == "name" assert file.spdx_id == "id" assert file.checksums == [checksum, checksum] @@ -26,7 +38,7 @@ def test_correct_initialization(checksum): assert file.attribution_texts == ["attribution"] -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_correct_initialization_with_default_values(checksum): file = File("name", "id", [checksum, checksum]) assert file.name == "name" @@ -43,13 +55,13 @@ def test_correct_initialization_with_default_values(checksum): assert file.attribution_texts == [] -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_name(checksum): with pytest.raises(TypeError): File(42, "id", [checksum]) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_spdx_id(checksum): with pytest.raises(TypeError): File("name", 42, [checksum]) @@ -61,55 +73,55 @@ def test_wrong_type_in_checksum(): File("name", "id", checksum) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_file_type(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], file_types=FileType.OTHER) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_license_concluded(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], license_concluded="NONE") -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_license_info_in_file(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], license_info_in_file=[SpdxNone]) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_license_comment(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], license_comment=42) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_copyright_text(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], copyright_text=[SpdxNone()]) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_comment(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], comment=42) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_notice(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], notice=["notice"]) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_contributors(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], contributors="contributor") -@mock.patch('spdx.model.checksum.Checksum', autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) def test_wrong_type_in_attribution_texts(checksum): with pytest.raises(TypeError): File("name", "id", [checksum], attribution_texts=["attribution", 42]) diff --git a/tests/spdx/model/test_package.py b/tests/spdx/model/test_package.py index a2fcf7961..193924df2 100644 --- a/tests/spdx/model/test_package.py +++ b/tests/spdx/model/test_package.py @@ -2,24 +2,47 @@ from unittest import mock import pytest +from license_expression import LicenseExpression, Licensing from spdx.model.checksum import Checksum, ChecksumAlgorithm -from license_expression import LicenseExpression, Licensing from spdx.model.package import Package, PackagePurpose from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -@mock.patch('spdx.model.package.ExternalPackageRef', autospec=True) -@mock.patch('spdx.model.checksum.Checksum', autospec=True) -@mock.patch('spdx.model.package.PackageVerificationCode', autospec=True) -@mock.patch('spdx.model.actor.Actor', autospec=True) +@mock.patch("spdx.model.package.ExternalPackageRef", autospec=True) +@mock.patch("spdx.model.checksum.Checksum", autospec=True) +@mock.patch("spdx.model.package.PackageVerificationCode", autospec=True) +@mock.patch("spdx.model.actor.Actor", autospec=True) def test_correct_initialization(actor, verif_code, checksum, ext_ref): - package = Package("id", "name", SpdxNoAssertion(), "version", "file_name", SpdxNoAssertion(), actor, True, - verif_code, [checksum], "homepage", "source_info", None, - [Licensing().parse("license and expression"), SpdxNoAssertion()], SpdxNone(), - "comment on license", "copyright", "summary", "description", "comment", [ext_ref, ext_ref], - ["text"], PackagePurpose.OTHER, datetime(2022, 1, 1), None, None) + package = Package( + "id", + "name", + SpdxNoAssertion(), + "version", + "file_name", + SpdxNoAssertion(), + actor, + True, + verif_code, + [checksum], + "homepage", + "source_info", + None, + [Licensing().parse("license and expression"), SpdxNoAssertion()], + SpdxNone(), + "comment on license", + "copyright", + "summary", + "description", + "comment", + [ext_ref, ext_ref], + ["text"], + PackagePurpose.OTHER, + datetime(2022, 1, 1), + None, + None, + ) assert package.spdx_id == "id" assert package.name == "name" assert package.download_location == SpdxNoAssertion() diff --git a/tests/spdx/model/test_snippet.py b/tests/spdx/model/test_snippet.py index 77219c5de..8b5d3b556 100644 --- a/tests/spdx/model/test_snippet.py +++ b/tests/spdx/model/test_snippet.py @@ -6,8 +6,19 @@ def test_correct_initialization(): - snippet = Snippet("id", "file_id", (200, 400), (20, 40), SpdxNone(), [SpdxNoAssertion()], "comment on license", - "copyright", "comment", "name", ["attribution"]) + snippet = Snippet( + "id", + "file_id", + (200, 400), + (20, 40), + SpdxNone(), + [SpdxNoAssertion()], + "comment on license", + "copyright", + "comment", + "name", + ["attribution"], + ) assert snippet.spdx_id == "id" assert snippet.file_spdx_id == "file_id" assert snippet.byte_range == (200, 400) diff --git a/tests/spdx/parser/json/test_json_parser.py b/tests/spdx/parser/json/test_json_parser.py index d547332f0..b61a01ad8 100644 --- a/tests/spdx/parser/json/test_json_parser.py +++ b/tests/spdx/parser/json/test_json_parser.py @@ -10,38 +10,42 @@ # limitations under the License. import os + import pytest from spdx.model.document import Document from spdx.parser.json import json_parser + def test_parse_json_file_not_found(): with pytest.raises(FileNotFoundError) as err: - wrong_file_path = os.path.join(os.path.dirname(__file__), 'hnjfkjsedhnflsiafg.json') + wrong_file_path = os.path.join(os.path.dirname(__file__), "hnjfkjsedhnflsiafg.json") json_parser.parse_from_file(wrong_file_path) assert err.value.args[1] == "No such file or directory" def test_parse_json_with_2_3_example(): - doc = json_parser.parse_from_file(os.path.join(os.path.dirname(__file__), - "../../data/formats/SPDXJSONExample-v2.3.spdx.json")) + doc = json_parser.parse_from_file( + os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXJSONExample-v2.3.spdx.json") + ) assert type(doc) == Document assert len(doc.annotations) == 5 assert len(doc.files) == 5 assert len(doc.packages) == 4 - assert len(doc.snippets) == 1 + assert len(doc.snippets) == 1 assert len(doc.relationships) == 13 assert len(doc.extracted_licensing_info) == 5 + def test_parse_json_with_2_2_example(): - doc = json_parser.parse_from_file(os.path.join(os.path.dirname(__file__), - "../../data/formats/SPDXJSONExample-v2.2.spdx.json")) + doc = json_parser.parse_from_file( + os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXJSONExample-v2.2.spdx.json") + ) assert type(doc) == Document assert len(doc.annotations) == 5 assert len(doc.files) == 4 assert len(doc.packages) == 4 - assert len(doc.snippets) == 1 + assert len(doc.snippets) == 1 assert len(doc.relationships) == 11 assert len(doc.extracted_licensing_info) == 5 - diff --git a/tests/spdx/parser/jsonlikedict/test_annotation_parser.py b/tests/spdx/parser/jsonlikedict/test_annotation_parser.py index 7bf6b66f8..439883433 100644 --- a/tests/spdx/parser/jsonlikedict/test_annotation_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_annotation_parser.py @@ -14,7 +14,7 @@ import pytest from spdx.model.actor import Actor, ActorType -from spdx.model.annotation import AnnotationType, Annotation +from spdx.model.annotation import Annotation, AnnotationType from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.annotation_parser import AnnotationParser @@ -25,7 +25,7 @@ def test_parse_annotation(): "annotationDate": "2010-01-29T18:30:22Z", "annotationType": "OTHER", "annotator": "Person: Jane Doe ()", - "comment": "Document level annotation" + "comment": "Document level annotation", } annotation = annotation_parser.parse_annotation(annotation_dict, spdx_id="SPDXRef-DOCUMENT") @@ -42,36 +42,47 @@ def test_parse_all_annotations(): doc_dict = { "SPDXID": "SPDXRef-DOCUMENT", "packages": [ - {"SPDXID": "SPDXRef-Package", - "annotations": [ - {"annotationDate": "2010-01-29T17:30:22Z", - "annotationType": "REVIEW", - "annotator": "Person: Mick Doe ()", - "comment": "Package level annotation"} - ]}], + { + "SPDXID": "SPDXRef-Package", + "annotations": [ + { + "annotationDate": "2010-01-29T17:30:22Z", + "annotationType": "REVIEW", + "annotator": "Person: Mick Doe ()", + "comment": "Package level annotation", + } + ], + } + ], "files": [ - {"SPDXID": "SPDXRef-File", - "annotations": [ - {"annotationDate": "2010-01-29T18:30:22Z", - "annotationType": "OTHER", - "annotator": "Person: Jane Doe ()", - "comment": "File level annotation"} - ]} + { + "SPDXID": "SPDXRef-File", + "annotations": [ + { + "annotationDate": "2010-01-29T18:30:22Z", + "annotationType": "OTHER", + "annotator": "Person: Jane Doe ()", + "comment": "File level annotation", + } + ], + } ], "snippets": [ - {"SPDXID": "SPDXRef-Snippet", - "annotations": [ - {"annotationDate": "2022-01-29T18:30:32Z", - "annotationType": "REVIEW", - "annotator": "Person: Jonas Rie (jonas@example.com)", - "comment": "Snippet level annotation"} - ]}], - "revieweds": - [{ - "reviewDate": "2010-01-29T18:30:22Z", - "reviewer": "Person: Jane Doe ()", - "comment": "Review annotation" - }] + { + "SPDXID": "SPDXRef-Snippet", + "annotations": [ + { + "annotationDate": "2022-01-29T18:30:32Z", + "annotationType": "REVIEW", + "annotator": "Person: Jonas Rie (jonas@example.com)", + "comment": "Snippet level annotation", + } + ], + } + ], + "revieweds": [ + {"reviewDate": "2010-01-29T18:30:22Z", "reviewer": "Person: Jane Doe ()", "comment": "Review annotation"} + ], } annotations = annotation_parser.parse_all_annotations(input_doc_dict=doc_dict) @@ -79,34 +90,72 @@ def test_parse_all_annotations(): assert len(annotations) == 4 test_case = TestCase() test_case.maxDiff = None - test_case.assertCountEqual(annotations, [Annotation(spdx_id="SPDXRef-DOCUMENT", - annotation_type=AnnotationType.REVIEW, - annotator=Actor(actor_type=ActorType.PERSON, name="Jane Doe", - email=None), - annotation_date=datetime.datetime(2010, 1, 29, 18, 30, 22), - annotation_comment="Review annotation"), - Annotation(spdx_id="SPDXRef-Package", - annotation_type=AnnotationType.REVIEW, - annotator=Actor(actor_type=ActorType.PERSON, name="Mick Doe", - email=None), - annotation_date=datetime.datetime(2010, 1, 29, 17, 30, 22), - annotation_comment="Package level annotation"), - Annotation(spdx_id="SPDXRef-File", annotation_type=AnnotationType.OTHER, - annotator=Actor(actor_type=ActorType.PERSON, name="Jane Doe", - email=None), - annotation_date=datetime.datetime(2010, 1, 29, 18, 30, 22), - annotation_comment="File level annotation"), - Annotation(spdx_id="SPDXRef-Snippet", - annotation_type=AnnotationType.REVIEW, - annotator=Actor(actor_type=ActorType.PERSON, name="Jonas Rie", - email="jonas@example.com"), - annotation_date=datetime.datetime(2022, 1, 29, 18, 30, 32), - annotation_comment="Snippet level annotation")]) + test_case.assertCountEqual( + annotations, + [ + Annotation( + spdx_id="SPDXRef-DOCUMENT", + annotation_type=AnnotationType.REVIEW, + annotator=Actor(actor_type=ActorType.PERSON, name="Jane Doe", email=None), + annotation_date=datetime.datetime(2010, 1, 29, 18, 30, 22), + annotation_comment="Review annotation", + ), + Annotation( + spdx_id="SPDXRef-Package", + annotation_type=AnnotationType.REVIEW, + annotator=Actor(actor_type=ActorType.PERSON, name="Mick Doe", email=None), + annotation_date=datetime.datetime(2010, 1, 29, 17, 30, 22), + annotation_comment="Package level annotation", + ), + Annotation( + spdx_id="SPDXRef-File", + annotation_type=AnnotationType.OTHER, + annotator=Actor(actor_type=ActorType.PERSON, name="Jane Doe", email=None), + annotation_date=datetime.datetime(2010, 1, 29, 18, 30, 22), + annotation_comment="File level annotation", + ), + Annotation( + spdx_id="SPDXRef-Snippet", + annotation_type=AnnotationType.REVIEW, + annotator=Actor(actor_type=ActorType.PERSON, name="Jonas Rie", email="jonas@example.com"), + annotation_date=datetime.datetime(2022, 1, 29, 18, 30, 32), + annotation_comment="Snippet level annotation", + ), + ], + ) -@pytest.mark.parametrize("incomplete_annotation_dict,expected_message", [({"annotator": "Person: Jane Doe ()"}, [ - "Error while constructing Annotation: ['SetterError Annotation: type of " 'argument "spdx_id" must be str; got NoneType instead: None\', \'SetterError Annotation: type of argument "annotation_type" must be ' "spdx.model.annotation.AnnotationType; got NoneType instead: None', " '\'SetterError Annotation: type of argument "annotation_date" must be ' "datetime.datetime; got NoneType instead: None', 'SetterError Annotation: " 'type of argument "annotation_comment" must be str; got NoneType instead: ' "None']"]), - ({"annotationDate": "2010-01-29T18:30:22Z"}, ["Error while constructing Annotation: ['SetterError Annotation: type of " 'argument "spdx_id" must be str; got NoneType instead: None\', \'SetterError Annotation: type of argument "annotation_type" must be ' "spdx.model.annotation.AnnotationType; got NoneType instead: None', " '\'SetterError Annotation: type of argument "annotator" must be ' "spdx.model.actor.Actor; got NoneType instead: None', 'SetterError Annotation: " 'type of argument "annotation_comment" must be str; got NoneType instead: ' "None']"])]) +@pytest.mark.parametrize( + "incomplete_annotation_dict,expected_message", + [ + ( + {"annotator": "Person: Jane Doe ()"}, + [ + "Error while constructing Annotation: ['SetterError Annotation: type of " + 'argument "spdx_id" must be str; got NoneType instead: None\', ' + '\'SetterError Annotation: type of argument "annotation_type" must be ' + "spdx.model.annotation.AnnotationType; got NoneType instead: None', " + '\'SetterError Annotation: type of argument "annotation_date" must be ' + "datetime.datetime; got NoneType instead: None', 'SetterError Annotation: " + 'type of argument "annotation_comment" must be str; got NoneType instead: ' + "None']" + ], + ), + ( + {"annotationDate": "2010-01-29T18:30:22Z"}, + [ + "Error while constructing Annotation: ['SetterError Annotation: type of " + 'argument "spdx_id" must be str; got NoneType instead: None\', ' + '\'SetterError Annotation: type of argument "annotation_type" must be ' + "spdx.model.annotation.AnnotationType; got NoneType instead: None', " + '\'SetterError Annotation: type of argument "annotator" must be ' + "spdx.model.actor.Actor; got NoneType instead: None', 'SetterError Annotation: " + 'type of argument "annotation_comment" must be str; got NoneType instead: ' + "None']" + ], + ), + ], +) def test_parse_incomplete_annotation(incomplete_annotation_dict, expected_message): annotation_parser = AnnotationParser() diff --git a/tests/spdx/parser/jsonlikedict/test_checksum_parser.py b/tests/spdx/parser/jsonlikedict/test_checksum_parser.py index a60249787..536b02040 100644 --- a/tests/spdx/parser/jsonlikedict/test_checksum_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_checksum_parser.py @@ -19,10 +19,7 @@ def test_parse_checksum(): checksum_parser = ChecksumParser() - checksum_dict = { - "algorithm": "SHA1", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759" - } + checksum_dict = {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759"} checksum = checksum_parser.parse_checksum(checksum_dict) @@ -32,26 +29,27 @@ def test_parse_checksum(): def test_parse_invalid_checksum(): checksum_parser = ChecksumParser() - checksum_dict = { - "algorithm": "SHA", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759" - } + checksum_dict = {"algorithm": "SHA", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759"} with pytest.raises(SPDXParsingError) as err: checksum_parser.parse_checksum(checksum_dict) - TestCase().assertCountEqual(err.value.get_messages(), - ["Error while parsing Checksum: ['Invalid ChecksumAlgorithm: SHA']"]) + TestCase().assertCountEqual( + err.value.get_messages(), ["Error while parsing Checksum: ['Invalid ChecksumAlgorithm: SHA']"] + ) def test_parse_incomplete_checksum(): checksum_parser = ChecksumParser() - checksum_dict = { - "algorithm": "SHA1" - } + checksum_dict = {"algorithm": "SHA1"} with pytest.raises(SPDXParsingError) as err: checksum_parser.parse_checksum(checksum_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing Checksum: ['SetterError Checksum: type of argument \"value\" must be str; got NoneType instead: None']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + 'Error while constructing Checksum: [\'SetterError Checksum: type of argument "value" must be str; ' + "got NoneType instead: None']" + ], + ) diff --git a/tests/spdx/parser/jsonlikedict/test_creation_info_parser.py b/tests/spdx/parser/jsonlikedict/test_creation_info_parser.py index a45f204b6..219daecb3 100644 --- a/tests/spdx/parser/jsonlikedict/test_creation_info_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_creation_info_parser.py @@ -29,20 +29,19 @@ def test_parse_creation_info(): "name": "Example Document", "dataLicense": "CC0-1.0", "documentNamespace": "namespace", - "externalDocumentRefs": [{ - "externalDocumentId": "DocumentRef-spdx-tool-1.2", - "checksum": { - "algorithm": "SHA1", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759" - }, - "spdxDocument": "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301" - }], + "externalDocumentRefs": [ + { + "externalDocumentId": "DocumentRef-spdx-tool-1.2", + "checksum": {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759"}, + "spdxDocument": "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", + } + ], "creationInfo": { "created": "2010-01-29T18:30:22Z", "creators": ["Tool: LicenseFind-1.0", "Organization: ExampleCodeInspect ()", "Person: Jane Doe ()"], "licenseListVersion": "3.7", - "comment": "Some comment." - } + "comment": "Some comment.", + }, } creation_info = creation_info_parser.parse_creation_info(doc_dict) @@ -51,31 +50,48 @@ def test_parse_creation_info(): assert creation_info.name == "Example Document" assert creation_info.document_namespace == "namespace" assert creation_info.created == datetime(2010, 1, 29, 18, 30, 22) - TestCase().assertCountEqual(creation_info.creators, [Actor(ActorType.TOOL, "LicenseFind-1.0"), - Actor(ActorType.ORGANIZATION, "ExampleCodeInspect"), - Actor(ActorType.PERSON, "Jane Doe")]) + TestCase().assertCountEqual( + creation_info.creators, + [ + Actor(ActorType.TOOL, "LicenseFind-1.0"), + Actor(ActorType.ORGANIZATION, "ExampleCodeInspect"), + Actor(ActorType.PERSON, "Jane Doe"), + ], + ) assert creation_info.license_list_version == Version(3, 7) - assert creation_info.external_document_refs == [ExternalDocumentRef(document_ref_id="DocumentRef-spdx-tool-1.2", - checksum=Checksum( - algorithm=ChecksumAlgorithm.SHA1, - value="d6a770ba38583ed4bb4525bd96e50461655d2759"), - document_uri="http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301")] + assert creation_info.external_document_refs == [ + ExternalDocumentRef( + document_ref_id="DocumentRef-spdx-tool-1.2", + checksum=Checksum(algorithm=ChecksumAlgorithm.SHA1, value="d6a770ba38583ed4bb4525bd96e50461655d2759"), + document_uri="http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", + ) + ] -@pytest.mark.parametrize("incomplete_dict,expected_message", - [({"spdxVersion": "2.3", "SPDXID": "SPDXRef-DOCUMENT", "name": "Example Document"}, - ["Error while parsing document Example Document: ['CreationInfo does not exist.']"]), - ({"creationInfo": {"created": "2019-02-01T11:30:40Z"}}, - ["Error while constructing CreationInfo: ['SetterError CreationInfo: type of " - 'argument "spdx_version" must be str; got NoneType instead: None\', ' - '\'SetterError CreationInfo: type of argument "spdx_id" must be str; got ' - "NoneType instead: None', 'SetterError CreationInfo: type of argument " - '"name" must be str; got NoneType instead: None\', \'SetterError ' - 'CreationInfo: type of argument "document_namespace" must be str; got ' - "NoneType instead: None', 'SetterError CreationInfo: type of argument " - '"creators" must be a list; got NoneType instead: None\', \'SetterError ' - 'CreationInfo: type of argument "data_license" must be str; got NoneType ' - "instead: None']"])]) +@pytest.mark.parametrize( + "incomplete_dict,expected_message", + [ + ( + {"spdxVersion": "2.3", "SPDXID": "SPDXRef-DOCUMENT", "name": "Example Document"}, + ["Error while parsing document Example Document: ['CreationInfo does not exist.']"], + ), + ( + {"creationInfo": {"created": "2019-02-01T11:30:40Z"}}, + [ + "Error while constructing CreationInfo: ['SetterError CreationInfo: type of " + 'argument "spdx_version" must be str; got NoneType instead: None\', ' + '\'SetterError CreationInfo: type of argument "spdx_id" must be str; got ' + "NoneType instead: None', 'SetterError CreationInfo: type of argument " + "\"name\" must be str; got NoneType instead: None', 'SetterError " + 'CreationInfo: type of argument "document_namespace" must be str; got ' + "NoneType instead: None', 'SetterError CreationInfo: type of argument " + "\"creators\" must be a list; got NoneType instead: None', 'SetterError " + 'CreationInfo: type of argument "data_license" must be str; got NoneType ' + "instead: None']" + ], + ), + ], +) def test_parse_incomplete_document_info(incomplete_dict, expected_message): creation_info_parser = CreationInfoParser() @@ -95,11 +111,18 @@ def test_parse_invalid_creation_info(): "created": "2010-01-29T18:30:22Z", "creators": ["Tool: LicenseFind-1.0", "Organization: ExampleCodeInspect ()", "Person: Jane Doe ()"], }, - "dataLicense": None + "dataLicense": None, } with pytest.raises(SPDXParsingError) as err: creation_info_parser.parse_creation_info(doc_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing CreationInfo: ['SetterError CreationInfo: type of " 'argument "document_namespace" must be str; got NoneType instead: None\', \'SetterError CreationInfo: type of argument "data_license" must be str; got ' "NoneType instead: None']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing CreationInfo: ['SetterError CreationInfo: type of " + 'argument "document_namespace" must be str; got NoneType instead: None\', ' + '\'SetterError CreationInfo: type of argument "data_license" must be str; got ' + "NoneType instead: None']" + ], + ) diff --git a/tests/spdx/parser/jsonlikedict/test_dict_parsing_functions.py b/tests/spdx/parser/jsonlikedict/test_dict_parsing_functions.py index 93b569362..66babca5d 100644 --- a/tests/spdx/parser/jsonlikedict/test_dict_parsing_functions.py +++ b/tests/spdx/parser/jsonlikedict/test_dict_parsing_functions.py @@ -15,8 +15,11 @@ from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.parser.error import SPDXParsingError -from spdx.parser.jsonlikedict.dict_parsing_functions import json_str_to_enum_name, \ - parse_field_or_no_assertion, parse_field_or_no_assertion_or_none +from spdx.parser.jsonlikedict.dict_parsing_functions import ( + json_str_to_enum_name, + parse_field_or_no_assertion, + parse_field_or_no_assertion_or_none, +) def test_json_str_to_enum(): @@ -27,8 +30,7 @@ def test_json_str_to_enum(): assert enum_name == "BLAKE2B_256" -@pytest.mark.parametrize("invalid_json_str,expected_message", - [(5, ["Type for enum must be str not int"])]) +@pytest.mark.parametrize("invalid_json_str,expected_message", [(5, ["Type for enum must be str not int"])]) def test_invalid_json_str_to_enum(invalid_json_str, expected_message): with pytest.raises(SPDXParsingError) as err: json_str_to_enum_name(invalid_json_str) @@ -43,8 +45,9 @@ def test_parse_field_or_no_assertion(input_str, expected_type): assert type(resulting_value) == expected_type -@pytest.mark.parametrize("input_str,expected_type", - [("NOASSERTION", SpdxNoAssertion), ("NONE", SpdxNone), ("example string", str)]) +@pytest.mark.parametrize( + "input_str,expected_type", [("NOASSERTION", SpdxNoAssertion), ("NONE", SpdxNone), ("example string", str)] +) def test_parse_field_or_no_assertion_or_none(input_str, expected_type): resulting_value = parse_field_or_no_assertion_or_none(input_str, lambda x: x) diff --git a/tests/spdx/parser/jsonlikedict/test_extracted_licensing_info_parser.py b/tests/spdx/parser/jsonlikedict/test_extracted_licensing_info_parser.py index d73ed5c0e..b7abde4ae 100644 --- a/tests/spdx/parser/jsonlikedict/test_extracted_licensing_info_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_extracted_licensing_info_parser.py @@ -20,21 +20,27 @@ def test_parse_extracted_licensing_info(): extracted_licensing_info_parser = ExtractedLicensingInfoParser() extracted_licensing_infos_dict = { - "licenseId": "LicenseRef-Beerware-4.2", "comment": "The beerware license has a couple of other standard variants.", - "extractedText": "\"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", + "extractedText": '"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", "name": "Beer-Ware License (Version 42)", - "seeAlsos": ["http://people.freebsd.org/~phk/"] - + "seeAlsos": ["http://people.freebsd.org/~phk/"], } extracted_licensing_info = extracted_licensing_info_parser.parse_extracted_licensing_info( - extracted_licensing_infos_dict) + extracted_licensing_infos_dict + ) assert extracted_licensing_info.license_id == "LicenseRef-Beerware-4.2" assert extracted_licensing_info.comment == "The beerware license has a couple of other standard variants." - assert extracted_licensing_info.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" + assert ( + extracted_licensing_info.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" + ) assert extracted_licensing_info.license_name == "Beer-Ware License (Version 42)" assert extracted_licensing_info.cross_references == ["http://people.freebsd.org/~phk/"] @@ -45,15 +51,21 @@ def test_parse_invalid_extracted_licensing_info(): extracted_licensing_infos_dict = { "licenseId": "LicenseRef-Beerware-4.2", "comment": 56, - "extractedText": "\"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", + "extractedText": '"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", "name": "Beer-Ware License (Version 42)", - "seeAlsos": ["http://people.freebsd.org/~phk/"] - + "seeAlsos": ["http://people.freebsd.org/~phk/"], } with pytest.raises(SPDXParsingError) as err: extracted_licensing_info_parser.parse_extracted_licensing_info(extracted_licensing_infos_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing ExtractedLicensingInfo: ['SetterError " 'ExtractedLicensingInfo: type of argument "comment" must be one of (str, ' "NoneType); got int instead: 56']"]) - + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing ExtractedLicensingInfo: ['SetterError " + 'ExtractedLicensingInfo: type of argument "comment" must be one of (str, ' + "NoneType); got int instead: 56']" + ], + ) diff --git a/tests/spdx/parser/jsonlikedict/test_file_parser.py b/tests/spdx/parser/jsonlikedict/test_file_parser.py index d08262dd4..3cf41e6e5 100644 --- a/tests/spdx/parser/jsonlikedict/test_file_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_file_parser.py @@ -11,11 +11,10 @@ from unittest import TestCase import pytest +from license_expression import Licensing from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.model.file import FileType -from license_expression import Licensing - from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.dict_parsing_functions import parse_list_of_elements @@ -27,90 +26,124 @@ def test_parse_file(): file_dict = { "SPDXID": "SPDXRef-File", "attributionTexts": ["Some attribution text."], - "checksums": [{ - "algorithm": "SHA1", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758" - }, { - "algorithm": "MD5", - "checksumValue": "624c1abb3664f4b35547e7c73864ad24" - }], - "comment": "The concluded license was taken from the package level that the file was included in.\nThis information was found in the COPYING.txt file in the xyz directory.", + "checksums": [ + {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758"}, + {"algorithm": "MD5", "checksumValue": "624c1abb3664f4b35547e7c73864ad24"}, + ], + "comment": "The concluded license was taken from the package level that the file was included in.\nThis " + "information was found in the COPYING.txt file in the xyz directory.", "copyrightText": "Copyright 2008-2010 John Smith", - "fileContributors": ["The Regents of the University of California", - "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation"], + "fileContributors": [ + "The Regents of the University of California", + "Modified by Paul Mundt lethal@linux-sh.org", + "IBM Corporation", + ], "fileName": "./package/foo.c", "fileTypes": ["SOURCE"], "licenseComments": "The concluded license was taken from the package level that the file was included in.", "licenseConcluded": "(LGPL-2.0-only OR LicenseRef-2)", "licenseInfoInFiles": ["GPL-2.0-only", "LicenseRef-2", "NOASSERTION"], - "noticeText": "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: \nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + "noticeText": "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is hereby granted, free of " + "charge, to any person obtaining a copy of this software and associated documentation files " + '(the "Software"), to deal in the Software without restriction, including without limitation ' + "the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of " + "the Software, and to permit persons to whom the Software is furnished to do so, subject to the " + "following conditions: \nThe above copyright notice and this permission notice shall be " + "included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED " + '"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ' + "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO " + "EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER " + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", } file = file_parser.parse_file(file_dict) assert file.name == "./package/foo.c" assert file.spdx_id == "SPDXRef-File" - TestCase().assertCountEqual(file.checksums, - [Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"), - Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24")]) - assert file.comment == "The concluded license was taken from the package level that the file was included in.\nThis information was found in the COPYING.txt file in the xyz directory." + TestCase().assertCountEqual( + file.checksums, + [ + Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"), + Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"), + ], + ) + assert ( + file.comment + == "The concluded license was taken from the package level that the file was included in.\nThis information " + "was found in the COPYING.txt file in the xyz directory." + ) assert file.copyright_text == "Copyright 2008-2010 John Smith" assert file.file_types == [FileType.SOURCE] - TestCase().assertCountEqual(file.contributors, ["The Regents of the University of California", - "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation"]) + TestCase().assertCountEqual( + file.contributors, + [ + "The Regents of the University of California", + "Modified by Paul Mundt lethal@linux-sh.org", + "IBM Corporation", + ], + ) assert file.license_concluded == Licensing().parse("(LGPL-2.0-only OR LicenseRef-2)") - TestCase().assertCountEqual(file.license_info_in_file, - [Licensing().parse("GPL-2.0-only"), Licensing().parse("LicenseRef-2"), - SpdxNoAssertion()]) - assert file.license_comment == "The concluded license was taken from the package level that the file was included in." + TestCase().assertCountEqual( + file.license_info_in_file, + [Licensing().parse("GPL-2.0-only"), Licensing().parse("LicenseRef-2"), SpdxNoAssertion()], + ) + assert ( + file.license_comment == "The concluded license was taken from the package level that the file was included in." + ) assert file.attribution_texts == ["Some attribution text."] def test_parse_incomplete_file(): file_parser = FileParser() - file_dict = { - "SPDXID": "SPDXRef-File", - "fileName": "Incomplete File" - } + file_dict = {"SPDXID": "SPDXRef-File", "fileName": "Incomplete File"} with pytest.raises(SPDXParsingError) as err: file_parser.parse_file(file_dict) - TestCase().assertCountEqual(err.value.get_messages(), - ["Error while constructing File: ['SetterError File: type of argument " - '"checksums" must be a list; got NoneType instead: None\']']) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing File: ['SetterError File: type of argument " + '"checksums" must be a list; got NoneType instead: None\']' + ], + ) def test_parse_invalid_files(): file_parser = FileParser() - files = [{"SPDXID": "SPDXRef-File", - "fileName": "Incomplete File"}, - {"SPDXID": "SPDXRef-File", - "attributionTexts": ["Some attribution text."], - "checksums": [{ - "algorithm": "SHA1", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758" - }, { - "algorithm": "MD5", - "checksumValue": "624c1abb3664f4b35547e7c73864ad24" - }]}, - {"SPDXID": "SPDXRef-File", - "attributionTexts": ["Some attribution text."], - "checksums": [{ - "algorithm": "SHA1", - "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758" - }, { - "algorithm": "MD", - "checksumValue": "624c1abb3664f4b35547e7c73864ad24" - }]}, - ] + files = [ + {"SPDXID": "SPDXRef-File", "fileName": "Incomplete File"}, + { + "SPDXID": "SPDXRef-File", + "attributionTexts": ["Some attribution text."], + "checksums": [ + {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758"}, + {"algorithm": "MD5", "checksumValue": "624c1abb3664f4b35547e7c73864ad24"}, + ], + }, + { + "SPDXID": "SPDXRef-File", + "attributionTexts": ["Some attribution text."], + "checksums": [ + {"algorithm": "SHA1", "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758"}, + {"algorithm": "MD", "checksumValue": "624c1abb3664f4b35547e7c73864ad24"}, + ], + }, + ] with pytest.raises(SPDXParsingError) as err: parse_list_of_elements(files, file_parser.parse_file) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing File: ['SetterError File: type of argument " '"checksums" must be a list; got NoneType instead: None\']', - 'Error while constructing File: [\'SetterError File: type of argument "name" ' "must be str; got NoneType instead: None']", - 'Error while parsing File: ["Error while parsing Checksum: [\'Invalid ChecksumAlgorithm: MD\']"]']) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing File: ['SetterError File: type of argument " + '"checksums" must be a list; got NoneType instead: None\']', + 'Error while constructing File: [\'SetterError File: type of argument "name" ' + "must be str; got NoneType instead: None']", + "Error while parsing File: [\"Error while parsing Checksum: ['Invalid ChecksumAlgorithm: MD']\"]", + ], + ) def test_parse_file_types(): @@ -129,5 +162,6 @@ def test_parse_invalid_file_types(): with pytest.raises(SPDXParsingError) as err: file_parser.parse_file_types(file_types_list) - TestCase().assertCountEqual(err.value.get_messages(), - ["Error while parsing FileType: ['Invalid FileType: APPLICAON']"]) + TestCase().assertCountEqual( + err.value.get_messages(), ["Error while parsing FileType: ['Invalid FileType: APPLICAON']"] + ) diff --git a/tests/spdx/parser/jsonlikedict/test_license_expression_parser.py b/tests/spdx/parser/jsonlikedict/test_license_expression_parser.py index b6d45e486..8157afcdf 100644 --- a/tests/spdx/parser/jsonlikedict/test_license_expression_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_license_expression_parser.py @@ -19,11 +19,15 @@ from spdx.parser.jsonlikedict.license_expression_parser import LicenseExpressionParser -@pytest.mark.parametrize("license_expression_str, expected_license", - [("First License", get_spdx_licensing().parse("First License")), - ("Second License", get_spdx_licensing().parse("Second License")), - ("NOASSERTION", SpdxNoAssertion()), - ("NONE", SpdxNone())]) +@pytest.mark.parametrize( + "license_expression_str, expected_license", + [ + ("First License", get_spdx_licensing().parse("First License")), + ("Second License", get_spdx_licensing().parse("Second License")), + ("NOASSERTION", SpdxNoAssertion()), + ("NONE", SpdxNone()), + ], +) def test_parse_license_expression(license_expression_str, expected_license): license_expression_parser = LicenseExpressionParser() license_expression = license_expression_parser.parse_license_expression(license_expression_str) @@ -31,10 +35,12 @@ def test_parse_license_expression(license_expression_str, expected_license): assert license_expression == expected_license -@pytest.mark.parametrize("invalid_license_expression,expected_message", - [(56, - ["Error parsing LicenseExpression: expression must be a string and not: : 56"]), - ]) +@pytest.mark.parametrize( + "invalid_license_expression,expected_message", + [ + (56, ["Error parsing LicenseExpression: expression must be a string and not: : 56"]), + ], +) def test_parse_invalid_license_expression(invalid_license_expression, expected_message): license_expression_parser = LicenseExpressionParser() diff --git a/tests/spdx/parser/jsonlikedict/test_package_parser.py b/tests/spdx/parser/jsonlikedict/test_package_parser.py index 809bab34c..e4d6c9028 100644 --- a/tests/spdx/parser/jsonlikedict/test_package_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_package_parser.py @@ -12,11 +12,11 @@ from unittest import TestCase import pytest +from license_expression import Licensing from spdx.model.actor import Actor, ActorType from spdx.model.checksum import Checksum, ChecksumAlgorithm -from license_expression import Licensing -from spdx.model.package import PackageVerificationCode, ExternalPackageRef, ExternalPackageRefCategory, PackagePurpose +from spdx.model.package import ExternalPackageRef, ExternalPackageRefCategory, PackagePurpose, PackageVerificationCode from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.dict_parsing_functions import parse_list_of_elements @@ -29,38 +29,49 @@ def test_parse_package(): package_dict = { "SPDXID": "SPDXRef-Package", "attributionTexts": [ - "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."], + "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." + ], "builtDate": "2011-01-29T18:30:22Z", - "checksums": [{ - "algorithm": "MD5", - "checksumValue": "624c1abb3664f4b35547e7c73864ad24" - }, { - "algorithm": "SHA1", - "checksumValue": "85ed0817af83a24ad8da68c2b5094de69833983c" - }, { - "algorithm": "SHA256", - "checksumValue": "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd" - }, { - "algorithm": "BLAKE2b-384", - "checksumValue": "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706" - }], + "checksums": [ + {"algorithm": "MD5", "checksumValue": "624c1abb3664f4b35547e7c73864ad24"}, + {"algorithm": "SHA1", "checksumValue": "85ed0817af83a24ad8da68c2b5094de69833983c"}, + { + "algorithm": "SHA256", + "checksumValue": "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd", + }, + { + "algorithm": "BLAKE2b-384", + "checksumValue": "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8" + "086984af8706", + }, + ], "comment": "This is a comment.", "copyrightText": "Copyright 2008-2010 John Smith", - "description": "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.", + "description": "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.", "downloadLocation": "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz", - "externalRefs": [{ - "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*", - "referenceType": "cpe23Type" - }, { - "comment": "This is the external ref for Acme", - "referenceCategory": "OTHER", - "referenceLocator": "acmecorp/acmenator/4.1.3-alpha", - "referenceType": "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge" - }], + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*", + "referenceType": "cpe23Type", + }, + { + "comment": "This is the external ref for Acme", + "referenceCategory": "OTHER", + "referenceLocator": "acmecorp/acmenator/4.1.3-alpha", + "referenceType": "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301" + "#LocationRef-acmeforge", + }, + ], "filesAnalyzed": True, "homepage": "http://ftp.gnu.org/gnu/glibc", - "licenseComments": "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.", + "licenseComments": "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.", "licenseConcluded": "(LGPL-2.0-only OR LicenseRef-3)", "licenseDeclared": "(LGPL-2.0-only AND LicenseRef-3)", "licenseInfoFromFiles": ["GPL-2.0-only", "LicenseRef-2", "LicenseRef-1", "NOASSERTION"], @@ -69,7 +80,7 @@ def test_parse_package(): "packageFileName": "glibc-2.11.1.tar.gz", "packageVerificationCode": { "packageVerificationCodeExcludedFiles": ["./package.spdx"], - "packageVerificationCodeValue": "d6a770ba38583ed4bb4525bd96e50461655d2758" + "packageVerificationCodeValue": "d6a770ba38583ed4bb4525bd96e50461655d2758", }, "primaryPackagePurpose": "SOURCE", "releaseDate": "2012-01-29T18:30:22Z", @@ -77,7 +88,7 @@ def test_parse_package(): "summary": "GNU C library.", "supplier": "Person: Jane Doe (jane.doe@example.com)", "validUntilDate": "2014-01-29T18:30:22Z", - "versionInfo": "2.11.1" + "versionInfo": "2.11.1", } package = package_parser.parse_package(package_dict) @@ -89,50 +100,101 @@ def test_parse_package(): assert package.file_name == "glibc-2.11.1.tar.gz" assert package.supplier == Actor(ActorType.PERSON, "Jane Doe", "jane.doe@example.com") assert package.originator == Actor(ActorType.ORGANIZATION, "ExampleCodeInspect", "contact@example.com") - assert package.files_analyzed == True - assert package.verification_code == PackageVerificationCode(value="d6a770ba38583ed4bb4525bd96e50461655d2758", - excluded_files=["./package.spdx"]) + assert package.files_analyzed is True + assert package.verification_code == PackageVerificationCode( + value="d6a770ba38583ed4bb4525bd96e50461655d2758", excluded_files=["./package.spdx"] + ) assert len(package.checksums) == 4 - TestCase().assertCountEqual(package.checksums, [Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"), - Checksum(ChecksumAlgorithm.SHA1, - "85ed0817af83a24ad8da68c2b5094de69833983c"), - Checksum(ChecksumAlgorithm.SHA256, - "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"), - Checksum(ChecksumAlgorithm.BLAKE2B_384, - "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706")]) + TestCase().assertCountEqual( + package.checksums, + [ + Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"), + Checksum(ChecksumAlgorithm.SHA1, "85ed0817af83a24ad8da68c2b5094de69833983c"), + Checksum(ChecksumAlgorithm.SHA256, "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"), + Checksum( + ChecksumAlgorithm.BLAKE2B_384, + "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", + ), + ], + ) assert package.homepage == "http://ftp.gnu.org/gnu/glibc" assert package.source_info == "uses glibc-2_11-branch from git://sourceware.org/git/glibc.git." assert package.license_concluded == Licensing().parse("(LGPL-2.0-only OR LicenseRef-3)") - TestCase().assertCountEqual(package.license_info_from_files, - [Licensing().parse("GPL-2.0-only"), Licensing().parse("LicenseRef-2"), - Licensing().parse("LicenseRef-1"), SpdxNoAssertion()]) + TestCase().assertCountEqual( + package.license_info_from_files, + [ + Licensing().parse("GPL-2.0-only"), + Licensing().parse("LicenseRef-2"), + Licensing().parse("LicenseRef-1"), + SpdxNoAssertion(), + ], + ) assert package.license_declared == Licensing().parse("(LGPL-2.0-only AND LicenseRef-3)") - assert package.license_comment == "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." + assert ( + package.license_comment + == "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." + ) assert package.copyright_text == "Copyright 2008-2010 John Smith" assert package.summary == "GNU C library." - assert package.description == "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." + assert ( + package.description + == "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." + ) assert package.comment == "This is a comment." assert len(package.external_references) == 2 - TestCase().assertCountEqual(package.external_references, [ExternalPackageRef(ExternalPackageRefCategory.SECURITY, - "cpe23Type", - "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"), - ExternalPackageRef(ExternalPackageRefCategory.OTHER, - "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge", - locator="acmecorp/acmenator/4.1.3-alpha", - comment="This is the external ref for Acme")]) + TestCase().assertCountEqual( + package.external_references, + [ + ExternalPackageRef( + ExternalPackageRefCategory.SECURITY, + "cpe23Type", + "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*", + ), + ExternalPackageRef( + ExternalPackageRefCategory.OTHER, + "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge", + locator="acmecorp/acmenator/4.1.3-alpha", + comment="This is the external ref for Acme", + ), + ], + ) assert package.attribution_texts == [ - "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."] + "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." + ] assert package.primary_package_purpose == PackagePurpose.SOURCE assert package.release_date == datetime(2012, 1, 29, 18, 30, 22) assert package.built_date == datetime(2011, 1, 29, 18, 30, 22) assert package.valid_until_date == datetime(2014, 1, 29, 18, 30, 22) -@pytest.mark.parametrize("incomplete_package_dict,expected_message", [({"SPDXID": "SPDXRef-Package"}, [ - "Error while constructing Package: ['SetterError Package: type of " 'argument "name" must be str; got NoneType instead: None\', \'SetterError Package: type of argument "download_location" must be one of (str, spdx.model.spdx_no_assertion.SpdxNoAssertion, spdx.model.spdx_none.SpdxNone); ' "got NoneType instead: None']"]), - ({"SPDXID": "SPDXRef-Package", "name": 5, - "downloadLocation": "NONE"}, [ - "Error while constructing Package: ['SetterError Package: type of argument " '"name" must be str; got int instead: 5\']'])]) +@pytest.mark.parametrize( + "incomplete_package_dict,expected_message", + [ + ( + {"SPDXID": "SPDXRef-Package"}, + [ + "Error while constructing Package: ['SetterError Package: type of " + "argument \"name\" must be str; got NoneType instead: None', 'SetterError Package: type of argument " + '"download_location" must be one of (str, spdx.model.spdx_no_assertion.SpdxNoAssertion, ' + "spdx.model.spdx_none.SpdxNone); " + "got NoneType instead: None']" + ], + ), + ( + {"SPDXID": "SPDXRef-Package", "name": 5, "downloadLocation": "NONE"}, + [ + "Error while constructing Package: ['SetterError Package: type of argument " + '"name" must be str; got int instead: 5\']' + ], + ), + ], +) def test_parse_incomplete_package(incomplete_package_dict, expected_message): package_parser = PackageParser() @@ -148,59 +210,62 @@ def test_parse_invalid_package(): "SPDXID": "SPDXRef-Package", "name": "Example Package", "downloadLocation": "NONE", - "checksums": - [{"algorithm": "SHA", - "value": "1234"}] + "checksums": [{"algorithm": "SHA", "value": "1234"}], } with pytest.raises(SPDXParsingError) as err: package_parser.parse_package(package_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - 'Error while parsing Package: ["Error while parsing Checksum: [\'Invalid ChecksumAlgorithm: SHA\']"]']) + TestCase().assertCountEqual( + err.value.get_messages(), + ["Error while parsing Package: [\"Error while parsing Checksum: ['Invalid ChecksumAlgorithm: SHA']\"]"], + ) def test_parse_packages(): package_parser = PackageParser() - packages_list = [{ - "SPDXID": "SPDXRef-Package", - "name": "Example Package", - "downloadLocation": "NONE", - "checksums": - [{"algorithm": "SHA", - "value": "1234"}] - }, { - "SPDXID": "SPDXRef-Package", - "name": 5, - "downloadLocation": "NONE" - }, + packages_list = [ { "SPDXID": "SPDXRef-Package", "name": "Example Package", - "downloadLocation": "NONE"} + "downloadLocation": "NONE", + "checksums": [{"algorithm": "SHA", "value": "1234"}], + }, + {"SPDXID": "SPDXRef-Package", "name": 5, "downloadLocation": "NONE"}, + {"SPDXID": "SPDXRef-Package", "name": "Example Package", "downloadLocation": "NONE"}, ] with pytest.raises(SPDXParsingError) as err: parse_list_of_elements(packages_list, package_parser.parse_package) - TestCase().assertCountEqual(err.value.get_messages(), - ['Error while parsing Package: ["Error while parsing Checksum: ' - '[\'Invalid ChecksumAlgorithm: SHA\']"]', - "Error while constructing Package: ['SetterError Package: type of argument " - '"name" must be str; got int instead: 5\']']) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + 'Error while parsing Package: ["Error while parsing Checksum: ' "['Invalid ChecksumAlgorithm: SHA']\"]", + "Error while constructing Package: ['SetterError Package: type of argument " + '"name" must be str; got int instead: 5\']', + ], + ) def test_parse_external_ref(): package_parser = PackageParser() - external_ref = { - "referenceType": "fix" - } + external_ref = {"referenceType": "fix"} with pytest.raises(SPDXParsingError) as err: package_parser.parse_external_ref(external_ref) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing ExternalPackageRef: ['SetterError " 'ExternalPackageRef: type of argument "category" must be ' "spdx.model.package.ExternalPackageRefCategory; got NoneType instead: None', " '\'SetterError ExternalPackageRef: type of argument "locator" must be str; ' "got NoneType instead: None']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing ExternalPackageRef: ['SetterError " + 'ExternalPackageRef: type of argument "category" must be ' + "spdx.model.package.ExternalPackageRefCategory; got NoneType instead: None', " + '\'SetterError ExternalPackageRef: type of argument "locator" must be str; ' + "got NoneType instead: None']" + ], + ) + def test_parse_invalid_external_package_ref_category(): package_parser = PackageParser() diff --git a/tests/spdx/parser/jsonlikedict/test_relationship_parser.py b/tests/spdx/parser/jsonlikedict/test_relationship_parser.py index 79dae728c..01f67833a 100644 --- a/tests/spdx/parser/jsonlikedict/test_relationship_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_relationship_parser.py @@ -12,7 +12,7 @@ import pytest -from spdx.model.relationship import RelationshipType, Relationship +from spdx.model.relationship import Relationship, RelationshipType from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.error import SPDXParsingError from spdx.parser.jsonlikedict.relationship_parser import RelationshipParser @@ -25,7 +25,7 @@ def test_parse_relationship(): "spdxElementId": "SPDXRef-DOCUMENT", "relationshipType": "CONTAINS", "relatedSpdxElement": "NOASSERTION", - "comment": "Comment." + "comment": "Comment.", } relationship = relationship_parser.parse_relationship(relationship_dict) @@ -41,14 +41,20 @@ def test_parse_incomplete_relationship(): relationship_dict = { "spdxElementId": "SPDXRef-DOCUMENT", "relatedSpdxElement": "SPDXRef-Package", - "comment": "Comment." + "comment": "Comment.", } with pytest.raises(SPDXParsingError) as err: relationship_parser.parse_relationship(relationship_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing Relationship: ['SetterError Relationship: type of " 'argument "relationship_type" must be ' "spdx.model.relationship.RelationshipType; got NoneType instead: None']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing Relationship: ['SetterError Relationship: type of " + 'argument "relationship_type" must be ' + "spdx.model.relationship.RelationshipType; got NoneType instead: None']" + ], + ) def test_parse_relationship_type(): @@ -64,49 +70,87 @@ def test_parse_document_describes(): document_dict = { "SPDXID": "SPDXRef-DOCUMENT", - "documentDescribes": ["SPDXRef-Package", "SPDXRef-File", "SPDXRef-Snippet"] + "documentDescribes": ["SPDXRef-Package", "SPDXRef-File", "SPDXRef-Snippet"], } - relationships = relationship_parser.parse_document_describes(doc_spdx_id="SPDXRef-DOCUMENT", - described_spdx_ids=document_dict.get( - "documentDescribes"), - existing_relationships=[]) + relationships = relationship_parser.parse_document_describes( + doc_spdx_id="SPDXRef-DOCUMENT", + described_spdx_ids=document_dict.get("documentDescribes"), + existing_relationships=[], + ) assert len(relationships) == 3 - TestCase().assertCountEqual(relationships, - [Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-Package"), - Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-File"), - Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-Snippet")]) - - -@pytest.mark.parametrize("document_describes,relationships,parsed_relationships", - [(["SPDXRef-Package", "SPDXRef-File"], [ - {"spdxElementId": "SPDXRef-DOCUMENT", "relatedSpdxElement": "SPDXRef-Package", - "relationshipType": "DESCRIBES", "comment": "This relationship has a comment."}, - {"spdxElementId": "SPDXRef-File", "relatedSpdxElement": "SPDXRef-DOCUMENT", - "relationshipType": "DESCRIBED_BY", "comment": "This relationship has a comment."}], [ - Relationship(related_spdx_element_id="SPDXRef-Package", - relationship_type=RelationshipType.DESCRIBES, - spdx_element_id="SPDXRef-DOCUMENT", - comment="This relationship has a comment."), - Relationship(related_spdx_element_id="SPDXRef-DOCUMENT", - relationship_type=RelationshipType.DESCRIBED_BY, - spdx_element_id="SPDXRef-File", - comment="This relationship has a comment.")]), - (["SPDXRef-Package", "SPDXRef-File", "SPDXRef-Package"], [], [ - Relationship(related_spdx_element_id="SPDXRef-Package", - relationship_type=RelationshipType.DESCRIBES, - spdx_element_id="SPDXRef-DOCUMENT"), - Relationship(related_spdx_element_id="SPDXRef-File", - relationship_type=RelationshipType.DESCRIBES, - spdx_element_id="SPDXRef-DOCUMENT")])]) -def test_parse_document_describes_without_duplicating_relationships(document_describes, relationships, - parsed_relationships): + TestCase().assertCountEqual( + relationships, + [ + Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-Package"), + Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-File"), + Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-Snippet"), + ], + ) + + +@pytest.mark.parametrize( + "document_describes,relationships,parsed_relationships", + [ + ( + ["SPDXRef-Package", "SPDXRef-File"], + [ + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relatedSpdxElement": "SPDXRef-Package", + "relationshipType": "DESCRIBES", + "comment": "This relationship has a comment.", + }, + { + "spdxElementId": "SPDXRef-File", + "relatedSpdxElement": "SPDXRef-DOCUMENT", + "relationshipType": "DESCRIBED_BY", + "comment": "This relationship has a comment.", + }, + ], + [ + Relationship( + related_spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.DESCRIBES, + spdx_element_id="SPDXRef-DOCUMENT", + comment="This relationship has a comment.", + ), + Relationship( + related_spdx_element_id="SPDXRef-DOCUMENT", + relationship_type=RelationshipType.DESCRIBED_BY, + spdx_element_id="SPDXRef-File", + comment="This relationship has a comment.", + ), + ], + ), + ( + ["SPDXRef-Package", "SPDXRef-File", "SPDXRef-Package"], + [], + [ + Relationship( + related_spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.DESCRIBES, + spdx_element_id="SPDXRef-DOCUMENT", + ), + Relationship( + related_spdx_element_id="SPDXRef-File", + relationship_type=RelationshipType.DESCRIBES, + spdx_element_id="SPDXRef-DOCUMENT", + ), + ], + ), + ], +) +def test_parse_document_describes_without_duplicating_relationships( + document_describes, relationships, parsed_relationships +): relationship_parser = RelationshipParser() document_dict = { "SPDXID": "SPDXRef-DOCUMENT", "documentDescribes": document_describes, - "relationships": relationships} + "relationships": relationships, + } relationships = relationship_parser.parse_all_relationships(document_dict) @@ -116,52 +160,72 @@ def test_parse_document_describes_without_duplicating_relationships(document_des def test_parse_has_files(): relationship_parser = RelationshipParser() - document_dict = { - "packages": - [{ - "SPDXID": "SPDXRef-Package", - "hasFiles": ["SPDXRef-File1", "SPDXRef-File2"] - }] - } + document_dict = {"packages": [{"SPDXID": "SPDXRef-Package", "hasFiles": ["SPDXRef-File1", "SPDXRef-File2"]}]} relationships = relationship_parser.parse_has_files(document_dict.get("packages"), existing_relationships=[]) assert len(relationships) == 2 - TestCase().assertCountEqual(relationships, [ - Relationship(spdx_element_id="SPDXRef-Package", relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id="SPDXRef-File1"), - Relationship(spdx_element_id="SPDXRef-Package", relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id="SPDXRef-File2")]) - - -@pytest.mark.parametrize("has_files,existing_relationships,contains_relationships", - [(["SPDXRef-File1", "SPDXRef-File2"], [ - Relationship(spdx_element_id="SPDXRef-Package", - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id="SPDXRef-File1", - comment="This relationship has a comment."), - Relationship(spdx_element_id="SPDXRef-File2", - relationship_type=RelationshipType.CONTAINED_BY, - related_spdx_element_id="SPDXRef-Package")], []), - (["SPDXRef-File1", "SPDXRef-File2", "SPDXRef-File1"], [], [ - Relationship(spdx_element_id="SPDXRef-Package", - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id="SPDXRef-File1"), - Relationship(spdx_element_id="SPDXRef-Package", - relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id="SPDXRef-File2")])]) -def test_parse_has_files_without_duplicating_relationships(has_files, existing_relationships, - contains_relationships): + TestCase().assertCountEqual( + relationships, + [ + Relationship( + spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id="SPDXRef-File1", + ), + Relationship( + spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id="SPDXRef-File2", + ), + ], + ) + + +@pytest.mark.parametrize( + "has_files,existing_relationships,contains_relationships", + [ + ( + ["SPDXRef-File1", "SPDXRef-File2"], + [ + Relationship( + spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id="SPDXRef-File1", + comment="This relationship has a comment.", + ), + Relationship( + spdx_element_id="SPDXRef-File2", + relationship_type=RelationshipType.CONTAINED_BY, + related_spdx_element_id="SPDXRef-Package", + ), + ], + [], + ), + ( + ["SPDXRef-File1", "SPDXRef-File2", "SPDXRef-File1"], + [], + [ + Relationship( + spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id="SPDXRef-File1", + ), + Relationship( + spdx_element_id="SPDXRef-Package", + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id="SPDXRef-File2", + ), + ], + ), + ], +) +def test_parse_has_files_without_duplicating_relationships(has_files, existing_relationships, contains_relationships): relationship_parser = RelationshipParser() - document_dict = { - "packages": - [{ - "SPDXID": "SPDXRef-Package", - "hasFiles": has_files - }] - } - relationships = relationship_parser.parse_has_files(document_dict.get("packages"), - existing_relationships=existing_relationships) + document_dict = {"packages": [{"SPDXID": "SPDXRef-Package", "hasFiles": has_files}]} + relationships = relationship_parser.parse_has_files( + document_dict.get("packages"), existing_relationships=existing_relationships + ) assert len(relationships) == len(contains_relationships) TestCase().assertCountEqual(relationships, contains_relationships) diff --git a/tests/spdx/parser/jsonlikedict/test_snippet_parser.py b/tests/spdx/parser/jsonlikedict/test_snippet_parser.py index 27f778caa..f2b8909b0 100644 --- a/tests/spdx/parser/jsonlikedict/test_snippet_parser.py +++ b/tests/spdx/parser/jsonlikedict/test_snippet_parser.py @@ -11,7 +11,6 @@ from unittest import TestCase import pytest - from license_expression import Licensing from spdx.model.spdx_no_assertion import SpdxNoAssertion @@ -24,41 +23,44 @@ def test_parse_snippet(): snippet_dict = { "SPDXID": "SPDXRef-Snippet", - "comment": "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.", + "comment": "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.", "copyrightText": "Copyright 2008-2010 John Smith", - "licenseComments": "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.", + "licenseComments": "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.", "licenseConcluded": "GPL-2.0-only", "licenseInfoInSnippets": ["GPL-2.0-only", "NOASSERTION"], "name": "from linux kernel", - "ranges": [{ - "endPointer": { - "offset": 420, - "reference": "SPDXRef-DoapSource" + "ranges": [ + { + "endPointer": {"offset": 420, "reference": "SPDXRef-DoapSource"}, + "startPointer": {"offset": 310, "reference": "SPDXRef-DoapSource"}, }, - "startPointer": { - "offset": 310, - "reference": "SPDXRef-DoapSource" - } - }, { - "endPointer": { - "lineNumber": 23, - "reference": "SPDXRef-DoapSource" + { + "endPointer": {"lineNumber": 23, "reference": "SPDXRef-DoapSource"}, + "startPointer": {"lineNumber": 5, "reference": "SPDXRef-DoapSource"}, }, - "startPointer": { - "lineNumber": 5, - "reference": "SPDXRef-DoapSource" - } - }], + ], "snippetFromFile": "SPDXRef-DoapSource", - "attributionTexts": ["Some example attibution text."] + "attributionTexts": ["Some example attibution text."], } snippet = snippet_parser.parse_snippet(snippet_dict) assert snippet.spdx_id == "SPDXRef-Snippet" assert snippet.name == "from linux kernel" - assert snippet.comment == "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." + assert ( + snippet.comment + == "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." + ) assert snippet.copyright_text == "Copyright 2008-2010 John Smith" - assert snippet.license_comment == "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." + assert ( + snippet.license_comment + == "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." + ) assert snippet.byte_range == (310, 420) assert snippet.line_range == (5, 23) assert snippet.file_spdx_id == "SPDXRef-DoapSource" @@ -69,17 +71,20 @@ def test_parse_snippet(): def test_parse_incomplete_snippet(): snippet_parser = SnippetParser() - incomplete_snippet_dict = { - "SPDXID": "SPDXRef-Snippet", - "file_spdx_id": "SPDXRef-File" - } + incomplete_snippet_dict = {"SPDXID": "SPDXRef-Snippet", "file_spdx_id": "SPDXRef-File"} with pytest.raises(SPDXParsingError) as err: snippet_parser.parse_snippet(incomplete_snippet_dict) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while constructing Snippet: ['SetterError Snippet: type of argument " '"file_spdx_id" must be str; got NoneType instead: None\', \'SetterError Snippet: type of argument "byte_range" must be a tuple; got NoneType ' - "instead: None']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing Snippet: ['SetterError Snippet: type of argument " + "\"file_spdx_id\" must be str; got NoneType instead: None', 'SetterError Snippet: type of argument " + '"byte_range" must be a tuple; got NoneType ' + "instead: None']" + ], + ) def test_parse_snippet_with_invalid_snippet_range(): @@ -89,25 +94,24 @@ def test_parse_snippet_with_invalid_snippet_range(): "file_spdx_id": "SPDXRef-File", "ranges": [ { - "endPointer": { - "offset": 23, - "reference": "SPDXRef-DoapSource" - }, - "startPointer": { - "offset": "310s", - "reference": "SPDXRef-DoapSource" - } - }] + "endPointer": {"offset": 23, "reference": "SPDXRef-DoapSource"}, + "startPointer": {"offset": "310s", "reference": "SPDXRef-DoapSource"}, + } + ], } with pytest.raises(SPDXParsingError) as err: snippet_parser.parse_snippet(snippet_with_invalid_ranges_list) - TestCase().assertCountEqual(err.value.get_messages(), - ["Error while constructing Snippet: ['SetterError Snippet: type of argument " - '"file_spdx_id" must be str; got NoneType instead: None\', \'SetterError ' - 'Snippet: type of argument "byte_range"[0] must be int; got str instead: ' - "(\\'310s\\', 23)']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while constructing Snippet: ['SetterError Snippet: type of argument " + "\"file_spdx_id\" must be str; got NoneType instead: None', 'SetterError " + 'Snippet: type of argument "byte_range"[0] must be int; got str instead: ' + "(\\'310s\\', 23)']" + ], + ) def test_parse_invalid_snippet_range(): @@ -115,29 +119,22 @@ def test_parse_invalid_snippet_range(): ranges = [ { - "endPointer": { - "lineNumber": 23, - "reference": "SPDXRef-DoapSource" - }, - "startPointer": { - "offset": 310, - "reference": "SPDXRef-DoapSource" - } - }, { - "endPointer": { - "offset": 420, - "reference": "SPDXRef-DoapSource" - }, - "startPointer": { - "lineNumber": 5, - "reference": "SPDXRef-DoapSource" - } - } - + "endPointer": {"lineNumber": 23, "reference": "SPDXRef-DoapSource"}, + "startPointer": {"offset": 310, "reference": "SPDXRef-DoapSource"}, + }, + { + "endPointer": {"offset": 420, "reference": "SPDXRef-DoapSource"}, + "startPointer": {"lineNumber": 5, "reference": "SPDXRef-DoapSource"}, + }, ] with pytest.raises(SPDXParsingError) as err: snippet_parser.parse_ranges(ranges) - TestCase().assertCountEqual(err.value.get_messages(), [ - "Error while parsing snippet ranges: ['Type of startpointer is not the same as type of endpointer.', 'Type of startpointer is not the same as type of endpointer.']"]) + TestCase().assertCountEqual( + err.value.get_messages(), + [ + "Error while parsing snippet ranges: ['Type of startpointer is not the same as type of endpointer.', " + "'Type of startpointer is not the same as type of endpointer.']" + ], + ) diff --git a/tests/spdx/parser/rdf/test_checksum_parser.py b/tests/spdx/parser/rdf/test_checksum_parser.py index 26b8e0149..2597fd83f 100644 --- a/tests/spdx/parser/rdf/test_checksum_parser.py +++ b/tests/spdx/parser/rdf/test_checksum_parser.py @@ -12,18 +12,18 @@ import pytest from rdflib import Graph, URIRef -from spdx.parser.error import SPDXParsingError from spdx.model.checksum import ChecksumAlgorithm -from spdx.parser.rdf.checksum_parser import parse_checksum, convert_rdf_to_algorithm +from spdx.parser.error import SPDXParsingError +from spdx.parser.rdf.checksum_parser import convert_rdf_to_algorithm, parse_checksum from spdx.rdfschema.namespace import SPDX_NAMESPACE def test_parse_checksum(): - graph = Graph().parse(os.path.join(os.path.dirname(__file__), - "data/file_to_test_rdf_parser.rdf.xml")) - checksum_node = graph.value(subject=URIRef("https://some.namespace#DocumentRef-external"), - predicate=SPDX_NAMESPACE.checksum) + graph = Graph().parse(os.path.join(os.path.dirname(__file__), "data/file_to_test_rdf_parser.rdf.xml")) + checksum_node = graph.value( + subject=URIRef("https://some.namespace#DocumentRef-external"), predicate=SPDX_NAMESPACE.checksum + ) checksum = parse_checksum(checksum_node, graph) @@ -31,40 +31,44 @@ def test_parse_checksum(): assert checksum.value == "71c4025dd9897b364f3ebbb42c484ff43d00791c" -@pytest.mark.parametrize("rdf_element,expected", [(SPDX_NAMESPACE.checksumAlgorithm_sha1, ChecksumAlgorithm.SHA1), - (SPDX_NAMESPACE.checksumAlgorithm_sha224, ChecksumAlgorithm.SHA224), - (SPDX_NAMESPACE.checksumAlgorithm_sha256, ChecksumAlgorithm.SHA256), - (SPDX_NAMESPACE.checksumAlgorithm_sha384, ChecksumAlgorithm.SHA384), - (SPDX_NAMESPACE.checksumAlgorithm_sha512, ChecksumAlgorithm.SHA512), - (SPDX_NAMESPACE.checksumAlgorithm_sha3_256, - ChecksumAlgorithm.SHA3_256), - (SPDX_NAMESPACE.checksumAlgorithm_sha3_384, - ChecksumAlgorithm.SHA3_384), - (SPDX_NAMESPACE.checksumAlgorithm_sha3_512, - ChecksumAlgorithm.SHA3_512), - (SPDX_NAMESPACE.checksumAlgorithm_blake2b256, - ChecksumAlgorithm.BLAKE2B_256), - (SPDX_NAMESPACE.checksumAlgorithm_blake2b384, - ChecksumAlgorithm.BLAKE2B_384), - (SPDX_NAMESPACE.checksumAlgorithm_blake2b512, - ChecksumAlgorithm.BLAKE2B_512), - (SPDX_NAMESPACE.checksumAlgorithm_blake3, ChecksumAlgorithm.BLAKE3), - (SPDX_NAMESPACE.checksumAlgorithm_md2, ChecksumAlgorithm.MD2), - (SPDX_NAMESPACE.checksumAlgorithm_md4, ChecksumAlgorithm.MD4), - (SPDX_NAMESPACE.checksumAlgorithm_md5, ChecksumAlgorithm.MD5), - (SPDX_NAMESPACE.checksumAlgorithm_md6, ChecksumAlgorithm.MD6), - (SPDX_NAMESPACE.checksumAlgorithm_adler32, ChecksumAlgorithm.ADLER32) - ]) +@pytest.mark.parametrize( + "rdf_element,expected", + [ + (SPDX_NAMESPACE.checksumAlgorithm_sha1, ChecksumAlgorithm.SHA1), + (SPDX_NAMESPACE.checksumAlgorithm_sha224, ChecksumAlgorithm.SHA224), + (SPDX_NAMESPACE.checksumAlgorithm_sha256, ChecksumAlgorithm.SHA256), + (SPDX_NAMESPACE.checksumAlgorithm_sha384, ChecksumAlgorithm.SHA384), + (SPDX_NAMESPACE.checksumAlgorithm_sha512, ChecksumAlgorithm.SHA512), + (SPDX_NAMESPACE.checksumAlgorithm_sha3_256, ChecksumAlgorithm.SHA3_256), + (SPDX_NAMESPACE.checksumAlgorithm_sha3_384, ChecksumAlgorithm.SHA3_384), + (SPDX_NAMESPACE.checksumAlgorithm_sha3_512, ChecksumAlgorithm.SHA3_512), + (SPDX_NAMESPACE.checksumAlgorithm_blake2b256, ChecksumAlgorithm.BLAKE2B_256), + (SPDX_NAMESPACE.checksumAlgorithm_blake2b384, ChecksumAlgorithm.BLAKE2B_384), + (SPDX_NAMESPACE.checksumAlgorithm_blake2b512, ChecksumAlgorithm.BLAKE2B_512), + (SPDX_NAMESPACE.checksumAlgorithm_blake3, ChecksumAlgorithm.BLAKE3), + (SPDX_NAMESPACE.checksumAlgorithm_md2, ChecksumAlgorithm.MD2), + (SPDX_NAMESPACE.checksumAlgorithm_md4, ChecksumAlgorithm.MD4), + (SPDX_NAMESPACE.checksumAlgorithm_md5, ChecksumAlgorithm.MD5), + (SPDX_NAMESPACE.checksumAlgorithm_md6, ChecksumAlgorithm.MD6), + (SPDX_NAMESPACE.checksumAlgorithm_adler32, ChecksumAlgorithm.ADLER32), + ], +) def test_convert_rdf_to_algorithm(rdf_element, expected): algorithm = convert_rdf_to_algorithm(rdf_element) assert algorithm == expected -@pytest.mark.parametrize("invalid_rdf_element", - [SPDX_NAMESPACE.checksumAlgorithm_blake2b_512, SPDX_NAMESPACE.checksumAlgorithm_BLAKE2b_512, - SPDX_NAMESPACE.checksumAlgorithm_sha3512, SPDX_NAMESPACE.checksumAlgorithm_sha513, - SPDX_NAMESPACE.checksumalgorithm_blake2b_512]) +@pytest.mark.parametrize( + "invalid_rdf_element", + [ + SPDX_NAMESPACE.checksumAlgorithm_blake2b_512, + SPDX_NAMESPACE.checksumAlgorithm_BLAKE2b_512, + SPDX_NAMESPACE.checksumAlgorithm_sha3512, + SPDX_NAMESPACE.checksumAlgorithm_sha513, + SPDX_NAMESPACE.checksumalgorithm_blake2b_512, + ], +) def test_convert_invalid_rdf_to_algorithm(invalid_rdf_element): with pytest.raises(SPDXParsingError): convert_rdf_to_algorithm(invalid_rdf_element) diff --git a/tests/spdx/parser/rdf/test_creation_info_parser.py b/tests/spdx/parser/rdf/test_creation_info_parser.py index 71ee6ccd6..ba5cd19c2 100644 --- a/tests/spdx/parser/rdf/test_creation_info_parser.py +++ b/tests/spdx/parser/rdf/test_creation_info_parser.py @@ -10,19 +10,20 @@ # limitations under the License. import os from datetime import datetime -from typing import Tuple, List +from typing import List, Tuple import pytest -from rdflib import Graph, RDF, URIRef +from rdflib import RDF, Graph, URIRef from rdflib.term import Node -from spdx.model.checksum import Checksum, ChecksumAlgorithm - -from spdx.model.version import Version from spdx.model.actor import Actor, ActorType - -from spdx.parser.rdf.creation_info_parser import parse_creation_info, parse_namespace_and_spdx_id, \ - parse_external_document_refs +from spdx.model.checksum import Checksum, ChecksumAlgorithm +from spdx.model.version import Version +from spdx.parser.rdf.creation_info_parser import ( + parse_creation_info, + parse_external_document_refs, + parse_namespace_and_spdx_id, +) from spdx.rdfschema.namespace import SPDX_NAMESPACE @@ -51,16 +52,27 @@ def test_parse_namespace_and_spdx_id(): assert spdx_id == "spdxID" -@pytest.mark.parametrize("triples,error_message", - [([(URIRef("docNamespace"), RDF.type, SPDX_NAMESPACE.SpdxDocument)], - r"No '#' found in the URI of SpdxDocument"), - ([(URIRef(""), RDF.type, URIRef(""))], r"No SpdxDocument found, can't parse rdf file."), - ([(URIRef("#SPDXRef-DOCUMENT"), RDF.type, SPDX_NAMESPACE.SpdxDocument)], - "No namespace found"), - ([(URIRef("docNamespace1"), RDF.type, SPDX_NAMESPACE.SpdxDocument), - (URIRef("docNamespace2"), RDF.type, SPDX_NAMESPACE.SpdxDocument)], - "Multiple SpdxDocuments found")]) -def test_parse_namespace_and_spdx_id_with_system_exit(triples: List[Tuple[Node, Node, Node]], error_message: str, caplog): +@pytest.mark.parametrize( + "triples,error_message", + [ + ( + [(URIRef("docNamespace"), RDF.type, SPDX_NAMESPACE.SpdxDocument)], + r"No '#' found in the URI of SpdxDocument", + ), + ([(URIRef(""), RDF.type, URIRef(""))], r"No SpdxDocument found, can't parse rdf file."), + ([(URIRef("#SPDXRef-DOCUMENT"), RDF.type, SPDX_NAMESPACE.SpdxDocument)], "No namespace found"), + ( + [ + (URIRef("docNamespace1"), RDF.type, SPDX_NAMESPACE.SpdxDocument), + (URIRef("docNamespace2"), RDF.type, SPDX_NAMESPACE.SpdxDocument), + ], + "Multiple SpdxDocuments found", + ), + ], +) +def test_parse_namespace_and_spdx_id_with_system_exit( + triples: List[Tuple[Node, Node, Node]], error_message: str, caplog +): graph = Graph() for triple in triples: graph = graph.add(triple) @@ -74,12 +86,14 @@ def test_parse_namespace_and_spdx_id_with_system_exit(triples: List[Tuple[Node, def test_parse_external_document_refs(): graph = Graph().parse(os.path.join(os.path.dirname(__file__), "data/file_to_test_rdf_parser.rdf.xml")) doc_namespace = "https://some.namespace" - external_doc_ref_node = graph.value(subject=URIRef(f"{doc_namespace}#SPDXRef-DOCUMENT"), - predicate=SPDX_NAMESPACE.externalDocumentRef) + external_doc_ref_node = graph.value( + subject=URIRef(f"{doc_namespace}#SPDXRef-DOCUMENT"), predicate=SPDX_NAMESPACE.externalDocumentRef + ) external_document_ref = parse_external_document_refs(external_doc_ref_node, graph, doc_namespace) assert external_document_ref.document_ref_id == "DocumentRef-external" - assert external_document_ref.checksum == Checksum(ChecksumAlgorithm.SHA1, - "71c4025dd9897b364f3ebbb42c484ff43d00791c") + assert external_document_ref.checksum == Checksum( + ChecksumAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c" + ) assert external_document_ref.document_uri == "https://namespace.com" diff --git a/tests/spdx/parser/rdf/test_extracted_licensing_info_parser.py b/tests/spdx/parser/rdf/test_extracted_licensing_info_parser.py index eb3776f97..db09dd0ff 100644 --- a/tests/spdx/parser/rdf/test_extracted_licensing_info_parser.py +++ b/tests/spdx/parser/rdf/test_extracted_licensing_info_parser.py @@ -10,7 +10,7 @@ # limitations under the License. import os -from rdflib import Graph, RDF +from rdflib import RDF, Graph from spdx.parser.rdf.extracted_licensing_info_parser import parse_extracted_licensing_info from spdx.rdfschema.namespace import SPDX_NAMESPACE diff --git a/tests/spdx/parser/rdf/test_file_parser.py b/tests/spdx/parser/rdf/test_file_parser.py index 9b9f634d5..33d168b4b 100644 --- a/tests/spdx/parser/rdf/test_file_parser.py +++ b/tests/spdx/parser/rdf/test_file_parser.py @@ -12,9 +12,9 @@ from unittest import TestCase from license_expression import get_spdx_licensing -from rdflib import Graph, RDF -from spdx.model.checksum import Checksum, ChecksumAlgorithm +from rdflib import RDF, Graph +from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.model.file import FileType from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.rdf.file_parser import parse_file @@ -36,9 +36,10 @@ def test_parse_file(): assert file.copyright_text == "copyrightText" assert file.contributors == ["fileContributor"] assert file.license_concluded == get_spdx_licensing().parse("MIT AND GPL-2.0") - TestCase().assertCountEqual(file.license_info_in_file, - [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), - SpdxNoAssertion()]) + TestCase().assertCountEqual( + file.license_info_in_file, + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNoAssertion()], + ) assert file.license_comment == "licenseComment" assert file.notice == "fileNotice" assert file.attribution_texts == ["fileAttributionText"] diff --git a/tests/spdx/parser/rdf/test_graph_parsing_function.py b/tests/spdx/parser/rdf/test_graph_parsing_function.py index c2b76203b..5a1118c2a 100644 --- a/tests/spdx/parser/rdf/test_graph_parsing_function.py +++ b/tests/spdx/parser/rdf/test_graph_parsing_function.py @@ -9,18 +9,25 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from rdflib import URIRef, Graph, Namespace +from rdflib import Graph, Namespace, URIRef from spdx.parser.rdf.graph_parsing_functions import parse_spdx_id, remove_prefix -@pytest.mark.parametrize("resource,doc_namespace,ext_namespace_mapping,expected", - [(URIRef("docNamespace#SPDXRef-Test"), "docNamespace", ("", Namespace("")), "SPDXRef-Test"), - (URIRef("docNamespaceSPDXRef-Test"), "docNamespace", ("", Namespace("")), - "docNamespaceSPDXRef-Test"), - (URIRef("differentNamespace#SPDXRef-Test"), "docNamespace", - ("extDoc", Namespace("differentNamespace#")), "extDoc:SPDXRef-Test"), - (None, "", ("", Namespace("")), None)]) +@pytest.mark.parametrize( + "resource,doc_namespace,ext_namespace_mapping,expected", + [ + (URIRef("docNamespace#SPDXRef-Test"), "docNamespace", ("", Namespace("")), "SPDXRef-Test"), + (URIRef("docNamespaceSPDXRef-Test"), "docNamespace", ("", Namespace("")), "docNamespaceSPDXRef-Test"), + ( + URIRef("differentNamespace#SPDXRef-Test"), + "docNamespace", + ("extDoc", Namespace("differentNamespace#")), + "extDoc:SPDXRef-Test", + ), + (None, "", ("", Namespace("")), None), + ], +) def test_parse_spdx_id(resource, doc_namespace, ext_namespace_mapping, expected): graph = Graph() graph.bind(*ext_namespace_mapping) @@ -29,8 +36,9 @@ def test_parse_spdx_id(resource, doc_namespace, ext_namespace_mapping, expected) assert spdx_id == expected -@pytest.mark.parametrize("string,prefix,expected", [("prefixString", "prefix", "String"), - ("prefixString", "refix", "prefixString")]) +@pytest.mark.parametrize( + "string,prefix,expected", [("prefixString", "prefix", "String"), ("prefixString", "refix", "prefixString")] +) def test_remove_prefix(string, prefix, expected): shorten_string = remove_prefix(string, prefix) diff --git a/tests/spdx/parser/rdf/test_license_expression_parser.py b/tests/spdx/parser/rdf/test_license_expression_parser.py index 0913a961a..3a529e768 100644 --- a/tests/spdx/parser/rdf/test_license_expression_parser.py +++ b/tests/spdx/parser/rdf/test_license_expression_parser.py @@ -12,12 +12,13 @@ from unittest import TestCase from license_expression import get_spdx_licensing -from rdflib import Graph, RDF -from spdx.parser.rdf import rdf_parser +from rdflib import RDF, Graph +from spdx.parser.rdf import rdf_parser from spdx.parser.rdf.license_expression_parser import parse_license_expression from spdx.rdfschema.namespace import SPDX_NAMESPACE + def test_license_expression_parser(): graph = Graph().parse(os.path.join(os.path.dirname(__file__), "data/file_to_test_rdf_parser.rdf.xml")) package_node = graph.value(predicate=RDF.type, object=SPDX_NAMESPACE.Package) @@ -30,17 +31,25 @@ def test_license_expression_parser(): def test_license_expression_parser_with_coupled_licenses(): doc = rdf_parser.parse_from_file( - os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXRdfExample-v2.3.spdx.rdf.xml")) + os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXRdfExample-v2.3.spdx.rdf.xml") + ) packages_by_spdx_id = {package.spdx_id: package for package in doc.packages} files_by_spdx_id = {file.spdx_id: file for file in doc.files} assert packages_by_spdx_id["SPDXRef-Package"].license_declared == get_spdx_licensing().parse( - "LGPL-2.0-only AND LicenseRef-3") + "LGPL-2.0-only AND LicenseRef-3" + ) assert packages_by_spdx_id["SPDXRef-Package"].license_concluded == get_spdx_licensing().parse( - "LGPL-2.0-only OR LicenseRef-3") - TestCase().assertCountEqual(packages_by_spdx_id["SPDXRef-Package"].license_info_from_files, - [get_spdx_licensing().parse("GPL-2.0"), get_spdx_licensing().parse("LicenseRef-1"), - get_spdx_licensing().parse("LicenseRef-2")]) + "LGPL-2.0-only OR LicenseRef-3" + ) + TestCase().assertCountEqual( + packages_by_spdx_id["SPDXRef-Package"].license_info_from_files, + [ + get_spdx_licensing().parse("GPL-2.0"), + get_spdx_licensing().parse("LicenseRef-1"), + get_spdx_licensing().parse("LicenseRef-2"), + ], + ) assert files_by_spdx_id["SPDXRef-JenaLib"].license_concluded == get_spdx_licensing().parse("LicenseRef-1") diff --git a/tests/spdx/parser/rdf/test_package_parser.py b/tests/spdx/parser/rdf/test_package_parser.py index f219496a2..454a37a79 100644 --- a/tests/spdx/parser/rdf/test_package_parser.py +++ b/tests/spdx/parser/rdf/test_package_parser.py @@ -16,10 +16,10 @@ from rdflib import RDF, Graph, Literal from spdx.model.actor import Actor, ActorType -from spdx.model.checksum import ChecksumAlgorithm, Checksum -from spdx.model.package import PackagePurpose, PackageVerificationCode, ExternalPackageRefCategory +from spdx.model.checksum import Checksum, ChecksumAlgorithm +from spdx.model.package import ExternalPackageRefCategory, PackagePurpose, PackageVerificationCode from spdx.model.spdx_no_assertion import SpdxNoAssertion -from spdx.parser.rdf.package_parser import parse_package, parse_external_package_ref +from spdx.parser.rdf.package_parser import parse_external_package_ref, parse_package from spdx.rdfschema.namespace import SPDX_NAMESPACE @@ -37,18 +37,20 @@ def test_package_parser(): assert package.version == "12.2" assert package.file_name == "./packageFileName" assert package.homepage == "https://homepage.com" - assert package.files_analyzed == True + assert package.files_analyzed is True assert package.checksums == [Checksum(ChecksumAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c")] assert package.source_info == "sourceInfo" assert package.license_concluded == get_spdx_licensing().parse("MIT AND GPL-2.0") assert package.license_declared == get_spdx_licensing().parse("MIT AND GPL-2.0") - TestCase().assertCountEqual(package.license_info_from_files, - [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), - SpdxNoAssertion()]) + TestCase().assertCountEqual( + package.license_info_from_files, + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNoAssertion()], + ) assert package.license_comment == "packageLicenseComment" assert package.copyright_text == "packageCopyrightText" - assert package.verification_code == PackageVerificationCode(value="85ed0817af83a24ad8da68c2b5094de69833983c", - excluded_files=["./exclude.py"]) + assert package.verification_code == PackageVerificationCode( + value="85ed0817af83a24ad8da68c2b5094de69833983c", excluded_files=["./exclude.py"] + ) assert len(package.external_references) == 1 assert package.summary == "packageSummary" assert package.description == "packageDescription" @@ -59,11 +61,25 @@ def test_package_parser(): assert package.originator == Actor(ActorType.PERSON, "originatorName", "some@mail.com") -@pytest.mark.parametrize("download_location,category,locator,type,comment", - [("https://download.com", ExternalPackageRefCategory.PACKAGE_MANAGER, - "org.apache.tomcat:tomcat:9.0.0.M4", "maven-central", "externalPackageRefComment"), - ("http://differentdownload.com", ExternalPackageRefCategory.OTHER, - "acmecorp/acmenator/4.1.3-alpha", "LocationRef-acmeforge","This is the external ref for Acme")]) +@pytest.mark.parametrize( + "download_location,category,locator,type,comment", + [ + ( + "https://download.com", + ExternalPackageRefCategory.PACKAGE_MANAGER, + "org.apache.tomcat:tomcat:9.0.0.M4", + "maven-central", + "externalPackageRefComment", + ), + ( + "http://differentdownload.com", + ExternalPackageRefCategory.OTHER, + "acmecorp/acmenator/4.1.3-alpha", + "LocationRef-acmeforge", + "This is the external ref for Acme", + ), + ], +) def test_external_package_ref_parser(download_location, category, locator, type, comment): graph = Graph().parse(os.path.join(os.path.dirname(__file__), "data/file_to_test_rdf_parser.rdf.xml")) doc_namespace = "https://some.namespace" diff --git a/tests/spdx/parser/rdf/test_rdf_parser.py b/tests/spdx/parser/rdf/test_rdf_parser.py index 769e5c8e2..b80fe3581 100644 --- a/tests/spdx/parser/rdf/test_rdf_parser.py +++ b/tests/spdx/parser/rdf/test_rdf_parser.py @@ -17,14 +17,15 @@ def test_rdf_parser_file_not_found(): - with pytest.raises(FileNotFoundError, match="No such file or directory") as err: - wrong_file_path = os.path.join(os.path.dirname(__file__), 'hnjfkjsedhnflsiafg.json') + with pytest.raises(FileNotFoundError, match="No such file or directory"): + wrong_file_path = os.path.join(os.path.dirname(__file__), "hnjfkjsedhnflsiafg.json") rdf_parser.parse_from_file(wrong_file_path) def test_rdf_parser_with_2_3_example(): doc = rdf_parser.parse_from_file( - os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXRdfExample-v2.3.spdx.rdf.xml")) + os.path.join(os.path.dirname(__file__), "../../data/formats/SPDXRdfExample-v2.3.spdx.rdf.xml") + ) assert type(doc) == Document assert len(doc.snippets) == 1 diff --git a/tests/spdx/parser/rdf/test_relationship_parser.py b/tests/spdx/parser/rdf/test_relationship_parser.py index b4b794bcf..e96fee535 100644 --- a/tests/spdx/parser/rdf/test_relationship_parser.py +++ b/tests/spdx/parser/rdf/test_relationship_parser.py @@ -10,7 +10,7 @@ # limitations under the License. import os -from rdflib import Graph, RDF +from rdflib import RDF, Graph from spdx.model.relationship import RelationshipType from spdx.parser.rdf.relationship_parser import parse_relationship diff --git a/tests/spdx/parser/rdf/test_snippet_parser.py b/tests/spdx/parser/rdf/test_snippet_parser.py index b0af0bedf..b98d8e9c7 100644 --- a/tests/spdx/parser/rdf/test_snippet_parser.py +++ b/tests/spdx/parser/rdf/test_snippet_parser.py @@ -13,12 +13,12 @@ import pytest from license_expression import get_spdx_licensing -from rdflib import Graph, RDF, BNode, Literal +from rdflib import RDF, BNode, Graph, Literal from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.parser.error import SPDXParsingError -from spdx.parser.rdf.snippet_parser import parse_snippet, parse_ranges -from spdx.rdfschema.namespace import SPDX_NAMESPACE, POINTER_NAMESPACE +from spdx.parser.rdf.snippet_parser import parse_ranges, parse_snippet +from spdx.rdfschema.namespace import POINTER_NAMESPACE, SPDX_NAMESPACE def test_parse_snippet(): @@ -33,9 +33,10 @@ def test_parse_snippet(): assert snippet.byte_range == (1, 2) assert snippet.line_range == (3, 4) assert snippet.license_concluded == get_spdx_licensing().parse("MIT AND GPL-2.0") - TestCase().assertCountEqual(snippet.license_info_in_snippet, - [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), - SpdxNoAssertion()]) + TestCase().assertCountEqual( + snippet.license_info_in_snippet, + [get_spdx_licensing().parse("MIT"), get_spdx_licensing().parse("GPL-2.0"), SpdxNoAssertion()], + ) assert snippet.license_comment == "snippetLicenseComment" assert snippet.copyright_text == "licenseCopyrightText" assert snippet.comment == "snippetComment" @@ -43,16 +44,23 @@ def test_parse_snippet(): assert snippet.attribution_texts == ["snippetAttributionText"] -@pytest.mark.parametrize("predicate_value_class_member", - [([(POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, - POINTER_NAMESPACE.offset), - (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, - POINTER_NAMESPACE.offset)]), - ([(POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, - POINTER_NAMESPACE.lineNumber), - (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.LineCharPointer, - POINTER_NAMESPACE.lineNumber)]) - ]) +@pytest.mark.parametrize( + "predicate_value_class_member", + [ + ( + [ + (POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + ] + ), + ( + [ + (POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + ] + ), + ], +) def test_parse_ranges(predicate_value_class_member): graph = Graph() pointer_class = predicate_value_class_member[0][2] @@ -66,16 +74,23 @@ def test_parse_ranges(predicate_value_class_member): assert range_dict[pointer_class.fragment][1] == predicate_value_class_member[1][1] -@pytest.mark.parametrize("predicate_value_class_member", - [([(POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, - POINTER_NAMESPACE.lineNumber), - (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, - POINTER_NAMESPACE.lineNumber)]), - ([(POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, - POINTER_NAMESPACE.offset), - (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.LineCharPointer, - POINTER_NAMESPACE.offset)]) - ]) +@pytest.mark.parametrize( + "predicate_value_class_member", + [ + ( + [ + (POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.lineNumber), + (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.lineNumber), + ] + ), + ( + [ + (POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.offset), + (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.offset), + ] + ), + ], +) def test_parse_ranges_wrong_pair_of_pointer_classes(predicate_value_class_member): graph = Graph() pointer_class = predicate_value_class_member[0][2] @@ -91,22 +106,42 @@ def test_parse_ranges_wrong_pair_of_pointer_classes(predicate_value_class_member @pytest.mark.parametrize( "predicate_value_class_member,expected_message", - [([(POINTER_NAMESPACE.endPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), - (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset)], - "Couldn't find pointer of type startPointer."), - ([(POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset)], - "Couldn't find pointer of type endPointer."), - ([(POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), - (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), - (POINTER_NAMESPACE.endPointer, 3, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset)], - "Multiple values for endPointer."), - ([(POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), - (POINTER_NAMESPACE.startPointer, 200, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber)], - "Multiple values for startPointer"), - ([(POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), - (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset)], - f"Types of startPointer and endPointer don't match") - ]) + [ + ( + [ + (POINTER_NAMESPACE.endPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + ], + "Couldn't find pointer of type startPointer.", + ), + ( + [(POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset)], + "Couldn't find pointer of type endPointer.", + ), + ( + [ + (POINTER_NAMESPACE.startPointer, 1, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + (POINTER_NAMESPACE.endPointer, 2, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + (POINTER_NAMESPACE.endPointer, 3, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + ], + "Multiple values for endPointer.", + ), + ( + [ + (POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + (POINTER_NAMESPACE.startPointer, 200, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + ], + "Multiple values for startPointer", + ), + ( + [ + (POINTER_NAMESPACE.startPointer, 100, POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + (POINTER_NAMESPACE.endPointer, 200, POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + ], + "Types of startPointer and endPointer don't match", + ), + ], +) def test_parse_ranges_error(predicate_value_class_member, expected_message): graph = Graph() @@ -119,7 +154,7 @@ def test_parse_ranges_error(predicate_value_class_member, expected_message): def add_range_to_graph_helper(graph, predicate_value_class_member): start_end_pointer = BNode() graph.add((start_end_pointer, RDF.type, POINTER_NAMESPACE.StartEndPointer)) - for (predicate, value, pointer_class, pointer_member) in predicate_value_class_member: + for predicate, value, pointer_class, pointer_member in predicate_value_class_member: pointer_node = BNode() graph.add((pointer_node, RDF.type, pointer_class)) graph.add((start_end_pointer, predicate, pointer_node)) diff --git a/tests/spdx/parser/tagvalue/test_annotation_parser.py b/tests/spdx/parser/tagvalue/test_annotation_parser.py index 65e9fa1d1..1fbd2060c 100644 --- a/tests/spdx/parser/tagvalue/test_annotation_parser.py +++ b/tests/spdx/parser/tagvalue/test_annotation_parser.py @@ -20,13 +20,15 @@ def test_parse_annotation(): parser = Parser() - annotation_str = "\n".join([ - "Annotator: Person: Jane Doe()", - "AnnotationDate: 2010-01-29T18:30:22Z", - "AnnotationComment: Document level annotation", - "AnnotationType: OTHER", - "SPDXREF: SPDXRef-DOCUMENT" - ]) + annotation_str = "\n".join( + [ + "Annotator: Person: Jane Doe()", + "AnnotationDate: 2010-01-29T18:30:22Z", + "AnnotationComment: Document level annotation", + "AnnotationType: OTHER", + "SPDXREF: SPDXRef-DOCUMENT", + ] + ) document = parser.parse("\n".join([DOCUMENT_STR, annotation_str])) assert document is not None assert len(document.annotations) == 1 @@ -38,22 +40,37 @@ def test_parse_annotation(): assert annotation.spdx_id == "SPDXRef-DOCUMENT" -@pytest.mark.parametrize("annotation_str, expected_message", [ - ("Annotator: Person: Jane Doe()", r"__init__() missing 4 " - "required positional arguments: 'spdx_id', 'annotation_type', " - "'annotation_date', and 'annotation_comment'"), - ("Annotator: Person: Jane Doe()\nAnnotationType: SOURCE\nAnnotationDate: 201001-2912:23", - "Error while parsing Annotation: ['Invalid AnnotationType: SOURCE. Line: 2', " - "'Error while parsing AnnotationDate: Token did not match specified grammar " - "rule. Line: 3']"), - ("Annotator: Jane Doe()\nAnnotationDate: 201001-29T18:30:22Z\n" - "AnnotationComment: Document level annotation\nAnnotationType: OTHER\nSPDXREF: SPDXRef-DOCUMENT", - "Error while parsing Annotation: ['Error while parsing Annotator: Token did " - "not match specified grammar rule. Line: 1', 'Error while parsing " - "AnnotationDate: Token did not match specified grammar rule. Line: 2']"), - ("Annotator: Person: ()", "Error while parsing Annotation: [['No name for Person provided: Person: ().']]"), - ("AnnotationType: REVIEW", "Element Annotation is not the current element in scope, probably the " - "expected tag to start the element (Annotator) is missing. Line: 1")]) +@pytest.mark.parametrize( + "annotation_str, expected_message", + [ + ( + "Annotator: Person: Jane Doe()", + r"__init__() missing 4 " + "required positional arguments: 'spdx_id', 'annotation_type', " + "'annotation_date', and 'annotation_comment'", + ), + ( + "Annotator: Person: Jane Doe()\nAnnotationType: SOURCE\nAnnotationDate: 201001-2912:23", + "Error while parsing Annotation: ['Invalid AnnotationType: SOURCE. Line: 2', " + "'Error while parsing AnnotationDate: Token did not match specified grammar " + "rule. Line: 3']", + ), + ( + "Annotator: Jane Doe()\nAnnotationDate: 201001-29T18:30:22Z\n" + "AnnotationComment: Document level annotation\nAnnotationType: OTHER\n" + "SPDXREF: SPDXRef-DOCUMENT", + "Error while parsing Annotation: ['Error while parsing Annotator: Token did " + "not match specified grammar rule. Line: 1', 'Error while parsing " + "AnnotationDate: Token did not match specified grammar rule. Line: 2']", + ), + ("Annotator: Person: ()", "Error while parsing Annotation: [['No name for Person provided: Person: ().']]"), + ( + "AnnotationType: REVIEW", + "Element Annotation is not the current element in scope, probably the " + "expected tag to start the element (Annotator) is missing. Line: 1", + ), + ], +) def test_parse_invalid_annotation(annotation_str, expected_message): parser = Parser() with pytest.raises(SPDXParsingError) as err: diff --git a/tests/spdx/parser/tagvalue/test_creation_info_parser.py b/tests/spdx/parser/tagvalue/test_creation_info_parser.py index 98971e24c..631aa3883 100644 --- a/tests/spdx/parser/tagvalue/test_creation_info_parser.py +++ b/tests/spdx/parser/tagvalue/test_creation_info_parser.py @@ -20,20 +20,24 @@ from spdx.parser.error import SPDXParsingError from spdx.parser.tagvalue.parser import Parser -DOCUMENT_STR = "\n".join([ - "SPDXVersion: SPDX-2.3", - "DataLicense: CC0-1.0", - "DocumentName: Sample_Document-V2.3", - "SPDXID: SPDXRef-DOCUMENT", - "DocumentComment: Sample Comment", - "DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", - "ExternalDocumentRef: DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "Creator: Person: Bob (bob@example.com)", - "Creator: Organization: Acme.", - "Created: 2010-02-03T00:00:00Z", - "CreatorComment: Sample Comment \nwith multiple \nlines.", - "LicenseListVersion: 3.17" -]) +DOCUMENT_STR = "\n".join( + [ + "SPDXVersion: SPDX-2.3", + "DataLicense: CC0-1.0", + "DocumentName: Sample_Document-V2.3", + "SPDXID: SPDXRef-DOCUMENT", + "DocumentComment: Sample Comment", + "DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", + "ExternalDocumentRef: DocumentRef-spdx-tool-1.2 " + "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 " + "SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + "Creator: Person: Bob (bob@example.com)", + "Creator: Organization: Acme.", + "Created: 2010-02-03T00:00:00Z", + "CreatorComment: Sample Comment \nwith multiple \nlines.", + "LicenseListVersion: 3.17", + ] +) def test_parse_creation_info(): @@ -47,44 +51,81 @@ def test_parse_creation_info(): assert creation_info.name == "Sample_Document-V2.3" assert creation_info.spdx_id == "SPDXRef-DOCUMENT" assert creation_info.document_comment == "Sample Comment" - assert creation_info.document_namespace == "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301" - TestCase().assertCountEqual(creation_info.creators, - [Actor(ActorType.PERSON, "Bob", "bob@example.com"), - Actor(ActorType.ORGANIZATION, "Acme.")]) + assert ( + creation_info.document_namespace + == "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301" + ) + TestCase().assertCountEqual( + creation_info.creators, + [Actor(ActorType.PERSON, "Bob", "bob@example.com"), Actor(ActorType.ORGANIZATION, "Acme.")], + ) assert creation_info.creator_comment == "Sample Comment \nwith multiple \nlines." assert creation_info.created == datetime(2010, 2, 3) assert creation_info.license_list_version == Version(3, 17) - assert creation_info.external_document_refs == [ExternalDocumentRef("DocumentRef-spdx-tool-1.2", - "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", - Checksum(ChecksumAlgorithm.SHA1, - "d6a770ba38583ed4bb4525bd96e50461655d2759"))] + assert creation_info.external_document_refs == [ + ExternalDocumentRef( + "DocumentRef-spdx-tool-1.2", + "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", + Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2759"), + ) + ] -@pytest.mark.parametrize("document_str, expected_message", - ([("\n".join( - ["SPDXVersion: SPDX-2.3", "DataLicense: CC0-1.0", "DocumentName: Sample_Document-V2.3", - "SPDXID: SPDXRef-DOCUMENT", "DocumentComment: Sample Comment", - "DocumentNamespace: Sample Comment", - "ExternalDocumentRef: DocumentRef-spdx-tool-1.2:htp://spdx.org:SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "Creator: Person Bob (bob@example.com)", "Creator: Organization: Acme [email]", - "Created: 2010-02-03T00:00:0Z", "CreatorComment: Sample Comment", - "LicenseListVersion: 7"]), - ("Error while parsing CreationInfo: ['Error while parsing DocumentNamespace: " - 'Token did not match specified grammar rule. Line: 6\', "Error while parsing ' - "ExternalDocumentRef: Couldn't split the first part of the value into " - 'document_ref_id and document_uri. Line: 7", \'Error while parsing Creator: ' - "Token did not match specified grammar rule. Line: 8', 'Error while parsing " - "Created: Token did not match specified grammar rule. Line: 10', '7 is not a " - "valid version string']")), - ("\n".join( - ["SPDXVersion: SPDX-2.3", "DataLicense: CC0-1.0", "DocumentName: Sample_Document-V2.3", - "SPDXID: SPDXRef-DOCUMENT"]), - r"__init__() missing 3 required positional arguments: 'document_namespace', 'creators', and 'created'"), - ("LicenseListVersion: 3.5\nLicenseListVersion: 3.7", - "Error while parsing CreationInfo: ['Multiple values for LicenseListVersion found. Line: 2']"), - ("ExternalDocumentRef: Document_ref document_uri SHA1: afded", - 'Error while parsing CreationInfo: ["Error while parsing ExternalDocumentRef: Couldn\'t match Checksum. Line: 1"]' - )])) +@pytest.mark.parametrize( + "document_str, expected_message", + ( + [ + ( + "\n".join( + [ + "SPDXVersion: SPDX-2.3", + "DataLicense: CC0-1.0", + "DocumentName: Sample_Document-V2.3", + "SPDXID: SPDXRef-DOCUMENT", + "DocumentComment: Sample Comment", + "DocumentNamespace: Sample Comment", + "ExternalDocumentRef: DocumentRef-spdx-tool-1.2:htp://spdx.org:SHA1: " + "d6a770ba38583ed4bb4525bd96e50461655d2759", + "Creator: Person Bob (bob@example.com)", + "Creator: Organization: Acme [email]", + "Created: 2010-02-03T00:00:0Z", + "CreatorComment: Sample Comment", + "LicenseListVersion: 7", + ] + ), + ( + "Error while parsing CreationInfo: ['Error while parsing DocumentNamespace: " + "Token did not match specified grammar rule. Line: 6', \"Error while parsing " + "ExternalDocumentRef: Couldn't split the first part of the value into " + "document_ref_id and document_uri. Line: 7\", 'Error while parsing Creator: " + "Token did not match specified grammar rule. Line: 8', 'Error while parsing " + "Created: Token did not match specified grammar rule. Line: 10', '7 is not a " + "valid version string']" + ), + ), + ( + "\n".join( + [ + "SPDXVersion: SPDX-2.3", + "DataLicense: CC0-1.0", + "DocumentName: Sample_Document-V2.3", + "SPDXID: SPDXRef-DOCUMENT", + ] + ), + r"__init__() missing 3 required positional arguments: 'document_namespace', 'creators', and 'created'", + ), + ( + "LicenseListVersion: 3.5\nLicenseListVersion: 3.7", + "Error while parsing CreationInfo: ['Multiple values for LicenseListVersion found. Line: 2']", + ), + ( + "ExternalDocumentRef: Document_ref document_uri SHA1: afded", + "Error while parsing CreationInfo: [\"Error while parsing ExternalDocumentRef: Couldn't match " + 'Checksum. Line: 1"]', + ), + ] + ), +) def test_parse_invalid_creation_info(document_str, expected_message): parser = Parser() with pytest.raises(SPDXParsingError) as err: diff --git a/tests/spdx/parser/tagvalue/test_extracted_licensing_info_parser.py b/tests/spdx/parser/tagvalue/test_extracted_licensing_info_parser.py index f8e27ace1..f97bff015 100644 --- a/tests/spdx/parser/tagvalue/test_extracted_licensing_info_parser.py +++ b/tests/spdx/parser/tagvalue/test_extracted_licensing_info_parser.py @@ -19,48 +19,60 @@ def test_parse_extracted_licensing_info(): parser = Parser() - extracted_licensing_info_str = "\n".join([ - "LicenseID: LicenseRef-Beerware-4.2", - "ExtractedText: \"THE BEER-WARE LICENSE\" (Revision 42): phk@FreeBSD.ORG wrote this file. As long as you " - "retain this notice you can 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" - "LicenseName: Beer-Ware License (Version 42)", - "LicenseCrossReference: http://people.freebsd.org/~phk/", - "LicenseCrossReference: http://another.cross.reference/", - "LicenseComment: The beerware license has a couple of other standard variants." - ]) + extracted_licensing_info_str = "\n".join( + [ + "LicenseID: LicenseRef-Beerware-4.2", + 'ExtractedText: "THE BEER-WARE LICENSE" (Revision 42): phk@FreeBSD.ORG wrote this file. As long as' + " you retain this notice you can 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", + "LicenseName: Beer-Ware License (Version 42)", + "LicenseCrossReference: http://people.freebsd.org/~phk/", + "LicenseCrossReference: http://another.cross.reference/", + "LicenseComment: The beerware license has a couple of other standard variants.", + ] + ) document = parser.parse("\n".join([DOCUMENT_STR, extracted_licensing_info_str])) assert document is not None assert len(document.extracted_licensing_info) == 1 extracted_licensing_info = document.extracted_licensing_info[0] assert extracted_licensing_info.license_id == "LicenseRef-Beerware-4.2" - assert extracted_licensing_info.extracted_text == "\"THE BEER-WARE LICENSE\" (Revision 42): phk@FreeBSD.ORG wrote this file. " \ - "As long as you retain this notice you can 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" + assert ( + extracted_licensing_info.extracted_text + == '"THE BEER-WARE LICENSE" (Revision 42): phk@FreeBSD.ORG wrote this file. ' + "As long as you retain this notice you can 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" + ) assert extracted_licensing_info.license_name == "Beer-Ware License (Version 42)" - TestCase().assertCountEqual(extracted_licensing_info.cross_references, - ["http://people.freebsd.org/~phk/", "http://another.cross.reference/"]) + TestCase().assertCountEqual( + extracted_licensing_info.cross_references, + ["http://people.freebsd.org/~phk/", "http://another.cross.reference/"], + ) assert extracted_licensing_info.comment == "The beerware license has a couple of other standard variants." def test_parse_invalid_extracted_licensing_info(): parser = Parser() - extracted_licensing_info_str = "\n".join([ - "ExtractedText: \"THE BEER-WARE LICENSE\" (Revision 42): phk@FreeBSD.ORG wrote this file. " - "As long as you retain this notice you can 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", - "LicenseName: Beer-Ware License (Version 42)", - "LicenseCrossReference: http://people.freebsd.org/~phk/", - "LicenseComment: The beerware license has a couple of other standard variants."]) + extracted_licensing_info_str = "\n".join( + [ + 'ExtractedText: "THE BEER-WARE LICENSE" (Revision 42): phk@FreeBSD.ORG wrote this file. ' + "As long as you retain this notice you can 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", + "LicenseName: Beer-Ware License (Version 42)", + "LicenseCrossReference: http://people.freebsd.org/~phk/", + "LicenseComment: The beerware license has a couple of other standard variants.", + ] + ) with pytest.raises(SPDXParsingError) as err: parser.parse(extracted_licensing_info_str) - assert err.value.get_messages() == ["Element ExtractedLicensingInfo is not the current element in scope, probably " - "the expected tag to start the element (LicenseID) is missing. Line: 1", - "Element ExtractedLicensingInfo is not the current element in scope, probably " - "the expected tag to start the element (LicenseID) is missing. Line: 2", - "Element ExtractedLicensingInfo is not the current element in scope, probably " - "the expected tag to start the element (LicenseID) is missing. Line: 3", - "Element ExtractedLicensingInfo is not the current element in scope, probably " - "the expected tag to start the element (LicenseID) is missing. Line: 4"] + assert err.value.get_messages() == [ + "Element ExtractedLicensingInfo is not the current element in scope, probably " + "the expected tag to start the element (LicenseID) is missing. Line: 1", + "Element ExtractedLicensingInfo is not the current element in scope, probably " + "the expected tag to start the element (LicenseID) is missing. Line: 2", + "Element ExtractedLicensingInfo is not the current element in scope, probably " + "the expected tag to start the element (LicenseID) is missing. Line: 3", + "Element ExtractedLicensingInfo is not the current element in scope, probably " + "the expected tag to start the element (LicenseID) is missing. Line: 4", + ] diff --git a/tests/spdx/parser/tagvalue/test_file_parser.py b/tests/spdx/parser/tagvalue/test_file_parser.py index 29399020f..ac6148bcd 100644 --- a/tests/spdx/parser/tagvalue/test_file_parser.py +++ b/tests/spdx/parser/tagvalue/test_file_parser.py @@ -20,19 +20,22 @@ def test_parse_file(): parser = Parser() - file_str = "\n".join([ - "FileName: testfile.java", - "SPDXID: SPDXRef-File", - "FileType: SOURCE", - "FileType: TEXT", - "FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - "LicenseConcluded: Apache-2.0", - "LicenseInfoInFile: Apache-2.0", - "LicenseInfoInFile: NOASSERTION", - "FileCopyrightText: Copyright 2014 Acme Inc.", - "FileComment: Very long file", - "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." - ]) + file_str = "\n".join( + [ + "FileName: testfile.java", + "SPDXID: SPDXRef-File", + "FileType: SOURCE", + "FileType: TEXT", + "FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "LicenseConcluded: Apache-2.0", + "LicenseInfoInFile: Apache-2.0", + "LicenseInfoInFile: NOASSERTION", + "FileCopyrightText: Copyright 2014 Acme Inc.", + "FileComment: Very long file", + "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." + "", + ] + ) document = parser.parse("\n".join([DOCUMENT_STR, file_str])) assert document is not None assert len(document.files) == 1 @@ -42,30 +45,34 @@ def test_parse_file(): assert spdx_file.file_types == [FileType.SOURCE, FileType.TEXT] assert spdx_file.comment == "Very long file" assert spdx_file.attribution_texts == [ - "Acknowledgements that might be required to be communicated in some contexts."] - assert spdx_file.license_info_in_file == [get_spdx_licensing().parse("Apache-2.0"), - SpdxNoAssertion()] + "Acknowledgements that might be required to be communicated in some contexts." + ] + assert spdx_file.license_info_in_file == [get_spdx_licensing().parse("Apache-2.0"), SpdxNoAssertion()] assert spdx_file.license_concluded == get_spdx_licensing().parse("Apache-2.0") def test_parse_invalid_file(): parser = Parser() - file_str = "\n".join([ - "FileName: testfile.java", - "SPDXID: SPDXRef-File", - "FileType: SOUCE", - "FileType: TEXT", - "FileChecksum: SHA3: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - "LicenseConcluded: Apache-2.0", - "LicenseInfoInFile: Apache-2.0", - "FileCopyrightText: Copyright 2014 Acme Inc.", - "FileComment: Very long file", - "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." - ]) + file_str = "\n".join( + [ + "FileName: testfile.java", + "SPDXID: SPDXRef-File", + "FileType: SOUCE", + "FileType: TEXT", + "FileChecksum: SHA3: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "LicenseConcluded: Apache-2.0", + "LicenseInfoInFile: Apache-2.0", + "FileCopyrightText: Copyright 2014 Acme Inc.", + "FileComment: Very long file", + "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." + "", + ] + ) with pytest.raises(SPDXParsingError) as err: parser.parse(file_str) assert err.value.get_messages() == [ "Error while parsing File: ['Invalid FileType: SOUCE. Line 3', 'Error while " - "parsing FileChecksum: Token did not match specified grammar rule. Line: 5']"] + "parsing FileChecksum: Token did not match specified grammar rule. Line: 5']" + ] diff --git a/tests/spdx/parser/tagvalue/test_helper_methods.py b/tests/spdx/parser/tagvalue/test_helper_methods.py index 75e7f0742..828083836 100644 --- a/tests/spdx/parser/tagvalue/test_helper_methods.py +++ b/tests/spdx/parser/tagvalue/test_helper_methods.py @@ -14,58 +14,92 @@ from spdx.parser.tagvalue.helper_methods import parse_checksum -@pytest.mark.parametrize("checksum_str, algorithm, value", - [("SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2759"), - ("SHA224: 9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588", - ChecksumAlgorithm.SHA224, - "9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588"), - ("SHA256: fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299", - ChecksumAlgorithm.SHA256, - "fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299"), - ( - "SHA384: 73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933", - ChecksumAlgorithm.SHA384, - "73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933"), - ( - "SHA512: c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f15af43e7cb5547f1a464053", - ChecksumAlgorithm.SHA512, - "c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f15af43e7cb5547f1a464053"), - ("SHA3-256: 1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce", - ChecksumAlgorithm.SHA3_256, - "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), ( - "SHA3-384: dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166", - ChecksumAlgorithm.SHA3_384, - "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166"), - ( - "SHA3-512: 906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36", - ChecksumAlgorithm.SHA3_512, - "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36"), - ("BLAKE2b-256: a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7", - ChecksumAlgorithm.BLAKE2B_256, - "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), ( - "BLAKE2B-384: 902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2", - ChecksumAlgorithm.BLAKE2B_384, - "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2"), - ( - "BLAKE2B-512: 72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c", - ChecksumAlgorithm.BLAKE2B_512, - "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c"), - ( - "BLAKE3: a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed", - ChecksumAlgorithm.BLAKE3, - "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed"), - ("MD2: af1eec2a1b18886c3f3cc244349d91d8", ChecksumAlgorithm.MD2, - "af1eec2a1b18886c3f3cc244349d91d8"), - ("MD4: d4c41ce30a517d6ce9d79c8c17bb4b66", ChecksumAlgorithm.MD4, - "d4c41ce30a517d6ce9d79c8c17bb4b66"), - ("MD5: 0d7f61beb7018b3924c6b8f96549fa39", ChecksumAlgorithm.MD5, - "0d7f61beb7018b3924c6b8f96549fa39"), - ( - "MD6: af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39", - ChecksumAlgorithm.MD6, - "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39"), - ("ADLER32: 02ec0130", ChecksumAlgorithm.ADLER32, "02ec0130")]) +@pytest.mark.parametrize( + "checksum_str, algorithm, value", + [ + ( + "SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + ChecksumAlgorithm.SHA1, + "d6a770ba38583ed4bb4525bd96e50461655d2759", + ), + ( + "SHA224: 9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588", + ChecksumAlgorithm.SHA224, + "9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588", + ), + ( + "SHA256: fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299", + ChecksumAlgorithm.SHA256, + "fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299", + ), + ( + "SHA384: 73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933", + ChecksumAlgorithm.SHA384, + "73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933", + ), + ( + "SHA512: c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34a" + "eb7ac10f15af43e7cb5547f1a464053", + ChecksumAlgorithm.SHA512, + "c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f" + "15af43e7cb5547f1a464053", + ), + ( + "SHA3-256: 1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce", + ChecksumAlgorithm.SHA3_256, + "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce", + ), + ( + "SHA3-384: dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c16" + "6", + ChecksumAlgorithm.SHA3_384, + "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166", + ), + ( + "SHA3-512: 906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd" + "3a101e1d111310266a5d46e2bc1ffbb36", + ChecksumAlgorithm.SHA3_512, + "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d11" + "1310266a5d46e2bc1ffbb36", + ), + ( + "BLAKE2b-256: a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7", + ChecksumAlgorithm.BLAKE2B_256, + "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7", + ), + ( + "BLAKE2B-384: 902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4" + "d0b2", + ChecksumAlgorithm.BLAKE2B_384, + "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2", + ), + ( + "BLAKE2B-512: 72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945" + "470842d90b5e8c4af74dce531ca8ebd8824c", + ChecksumAlgorithm.BLAKE2B_512, + "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8" + "c4af74dce531ca8ebd8824c", + ), + ( + "BLAKE3: a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67" + "239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967" + "a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed", + ChecksumAlgorithm.BLAKE3, + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dc" + "ec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a1300685" + "7d3b9985174bf67239874dcec4cbbc9839496179feafed", + ), + ("MD2: af1eec2a1b18886c3f3cc244349d91d8", ChecksumAlgorithm.MD2, "af1eec2a1b18886c3f3cc244349d91d8"), + ("MD4: d4c41ce30a517d6ce9d79c8c17bb4b66", ChecksumAlgorithm.MD4, "d4c41ce30a517d6ce9d79c8c17bb4b66"), + ("MD5: 0d7f61beb7018b3924c6b8f96549fa39", ChecksumAlgorithm.MD5, "0d7f61beb7018b3924c6b8f96549fa39"), + ( + "MD6: af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39", + ChecksumAlgorithm.MD6, + "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39", + ), + ("ADLER32: 02ec0130", ChecksumAlgorithm.ADLER32, "02ec0130"), + ], +) def test_parse_checksum(checksum_str, algorithm, value): checksum = parse_checksum(checksum_str) diff --git a/tests/spdx/parser/tagvalue/test_package_parser.py b/tests/spdx/parser/tagvalue/test_package_parser.py index 39d6eeef3..f5c75d751 100644 --- a/tests/spdx/parser/tagvalue/test_package_parser.py +++ b/tests/spdx/parser/tagvalue/test_package_parser.py @@ -23,36 +23,38 @@ def test_parse_package(): parser = Parser() - package_str = "\n".join([ - "PackageName: Test", - "SPDXID: SPDXRef-Package", - "PackageVersion: 1:22.36.1-8+deb11u1", - "PackageDownloadLocation: http://example.com/test", - "FilesAnalyzed: True", - "PackageSummary: Test package", - "PackageSourceInfo: Version 1.0 of test", - "PackageFileName: test-1.0.zip", - "PackageSupplier: Organization:ACME", - "PackageOriginator: Organization:ACME", - "PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - "PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", - "PackageDescription: A package.", - "PackageComment: Comment on the package.", - "PackageCopyrightText: Copyright 2014 Acme Inc.", - "PackageLicenseDeclared: Apache-2.0", - "PackageLicenseConcluded: (LicenseRef-2.0 and Apache-2.0)", - "PackageLicenseInfoFromFiles: Apache-1.0", - "PackageLicenseInfoFromFiles: Apache-2.0", - "PackageLicenseInfoFromFiles: NONE", - "PackageLicenseComments: License Comments", - "ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", - "ExternalRefComment: Some comment about the package.", - "ExternalRef: OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3-alpha", - "PrimaryPackagePurpose: OPERATING-SYSTEM", - "BuiltDate: 2020-01-01T12:00:00Z", - "ReleaseDate: 2021-01-01T12:00:00Z", - "ValidUntilDate: 2022-01-01T12:00:00Z" - ]) + package_str = "\n".join( + [ + "PackageName: Test", + "SPDXID: SPDXRef-Package", + "PackageVersion: 1:22.36.1-8+deb11u1", + "PackageDownloadLocation: http://example.com/test", + "FilesAnalyzed: True", + "PackageSummary: Test package", + "PackageSourceInfo: Version 1.0 of test", + "PackageFileName: test-1.0.zip", + "PackageSupplier: Organization:ACME", + "PackageOriginator: Organization:ACME", + "PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", + "PackageDescription: A package.", + "PackageComment: Comment on the package.", + "PackageCopyrightText: Copyright 2014 Acme Inc.", + "PackageLicenseDeclared: Apache-2.0", + "PackageLicenseConcluded: (LicenseRef-2.0 and Apache-2.0)", + "PackageLicenseInfoFromFiles: Apache-1.0", + "PackageLicenseInfoFromFiles: Apache-2.0", + "PackageLicenseInfoFromFiles: NONE", + "PackageLicenseComments: License Comments", + "ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", + "ExternalRefComment: Some comment about the package.", + "ExternalRef: OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3-alpha", + "PrimaryPackagePurpose: OPERATING-SYSTEM", + "BuiltDate: 2020-01-01T12:00:00Z", + "ReleaseDate: 2021-01-01T12:00:00Z", + "ValidUntilDate: 2022-01-01T12:00:00Z", + ] + ) document = parser.parse("\n".join([DOCUMENT_STR, package_str])) assert document is not None package = document.packages[0] @@ -60,50 +62,76 @@ def test_parse_package(): assert package.spdx_id == "SPDXRef-Package" assert package.version == "1:22.36.1-8+deb11u1" assert len(package.license_info_from_files) == 3 - TestCase().assertCountEqual(package.license_info_from_files, [get_spdx_licensing().parse("Apache-1.0"), - get_spdx_licensing().parse("Apache-2.0"), - SpdxNone()]) + TestCase().assertCountEqual( + package.license_info_from_files, + [get_spdx_licensing().parse("Apache-1.0"), get_spdx_licensing().parse("Apache-2.0"), SpdxNone()], + ) assert package.license_concluded == get_spdx_licensing().parse("LicenseRef-2.0 AND Apache-2.0") assert package.files_analyzed is True assert package.comment == "Comment on the package." assert len(package.external_references) == 2 - TestCase().assertCountEqual(package.external_references, - [ExternalPackageRef(ExternalPackageRefCategory.SECURITY, "cpe23Type", - "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", - "Some comment about the package."), - ExternalPackageRef(ExternalPackageRefCategory.OTHER, "LocationRef-acmeforge", - "acmecorp/acmenator/4.1.3-alpha")]) + TestCase().assertCountEqual( + package.external_references, + [ + ExternalPackageRef( + ExternalPackageRefCategory.SECURITY, + "cpe23Type", + "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", + "Some comment about the package.", + ), + ExternalPackageRef( + ExternalPackageRefCategory.OTHER, "LocationRef-acmeforge", "acmecorp/acmenator/4.1.3-alpha" + ), + ], + ) assert package.primary_package_purpose == PackagePurpose.OPERATING_SYSTEM assert package.built_date == datetime(2020, 1, 1, 12) assert package.release_date == datetime(2021, 1, 1, 12) assert package.valid_until_date == datetime(2022, 1, 1, 12) -@pytest.mark.parametrize("package_str, expected_message", - [("PackageDownloadLocation: SPDXRef-Package", - "Element Package is not the current element in scope, probably the expected " - "tag to start the element (PackageName) is missing. Line: 1"), - ("PackageName: TestPackage", - r"__init__() missing 2 required positional arguments: 'spdx_id' and 'download_location'"), - ("PackageName: TestPackage\nPackageCopyrightText:This is a copyright\n" - "PackageCopyrightText:MultipleCopyright", - "Error while parsing Package: ['Multiple values for PackageCopyrightText " - "found. Line: 3']"), - ("PackageName: TestPackage\nExternalRef: reference locator", - ('Error while parsing Package: ["Couldn\'t split PackageExternalRef in category, ' - 'reference_type and locator. Line: 2"]')), - ("PackageName: TestPackage\nExternalRef: category reference locator", - "Error while parsing Package: ['Invalid ExternalPackageRefCategory: " - "category. Line: 2']"), - ("SPDXID:SPDXRef-DOCUMENT\nPackageName: TestPackage\nSPDXID:SPDXRef-Package\n" - "PackageDownloadLocation: download.com\nPackageVerificationCode: category reference locator", - "Error while parsing Package: ['Error while parsing PackageVerificationCode: " - "Value did not match expected format. Line: 5']"), - ("PackageName: TestPackage\nBuiltDate: 2012\nValidUntilDate:202-11-02T00:00", - "Error while parsing Package: ['Error while parsing BuiltDate: Token did not " - "match specified grammar rule. Line: 2', 'Error while parsing " - "ValidUntilDate: Token did not match specified grammar rule. Line: 3']") - ]) +@pytest.mark.parametrize( + "package_str, expected_message", + [ + ( + "PackageDownloadLocation: SPDXRef-Package", + "Element Package is not the current element in scope, probably the expected " + "tag to start the element (PackageName) is missing. Line: 1", + ), + ( + "PackageName: TestPackage", + r"__init__() missing 2 required positional arguments: 'spdx_id' and 'download_location'", + ), + ( + "PackageName: TestPackage\nPackageCopyrightText:This is a copyright\n" + "PackageCopyrightText:MultipleCopyright", + "Error while parsing Package: ['Multiple values for PackageCopyrightText " "found. Line: 3']", + ), + ( + "PackageName: TestPackage\nExternalRef: reference locator", + ( + "Error while parsing Package: [\"Couldn't split PackageExternalRef in category, " + 'reference_type and locator. Line: 2"]' + ), + ), + ( + "PackageName: TestPackage\nExternalRef: category reference locator", + "Error while parsing Package: ['Invalid ExternalPackageRefCategory: " "category. Line: 2']", + ), + ( + "SPDXID:SPDXRef-DOCUMENT\nPackageName: TestPackage\nSPDXID:SPDXRef-Package\n" + "PackageDownloadLocation: download.com\nPackageVerificationCode: category reference locator", + "Error while parsing Package: ['Error while parsing PackageVerificationCode: " + "Value did not match expected format. Line: 5']", + ), + ( + "PackageName: TestPackage\nBuiltDate: 2012\nValidUntilDate:202-11-02T00:00", + "Error while parsing Package: ['Error while parsing BuiltDate: Token did not " + "match specified grammar rule. Line: 2', 'Error while parsing " + "ValidUntilDate: Token did not match specified grammar rule. Line: 3']", + ), + ], +) def test_parse_invalid_package(package_str, expected_message): parser = Parser() diff --git a/tests/spdx/parser/tagvalue/test_relationship_parser.py b/tests/spdx/parser/tagvalue/test_relationship_parser.py index 90ef9da4e..fc74b05b7 100644 --- a/tests/spdx/parser/tagvalue/test_relationship_parser.py +++ b/tests/spdx/parser/tagvalue/test_relationship_parser.py @@ -10,7 +10,7 @@ # limitations under the License. import pytest -from spdx.model.relationship import RelationshipType, Relationship +from spdx.model.relationship import Relationship, RelationshipType from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.parser.error import SPDXParsingError @@ -18,20 +18,31 @@ from tests.spdx.parser.tagvalue.test_creation_info_parser import DOCUMENT_STR -@pytest.mark.parametrize("relationship_str, expected_relationship", - [("\n".join(["Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-File", - "RelationshipComment: This is a comment."]), - Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, - "SPDXRef-File", "This is a comment.")), - ("Relationship: SPDXRef-DOCUMENT PATCH_FOR NOASSERTION", - Relationship("SPDXRef-DOCUMENT", RelationshipType.PATCH_FOR, - SpdxNoAssertion())), - ("Relationship: SPDXRef-CarolCompression DEPENDS_ON NONE", - Relationship("SPDXRef-CarolCompression", RelationshipType.DEPENDS_ON, SpdxNone())), - ("Relationship: DocumentRef-ExternalDocument:SPDXRef-Test DEPENDS_ON DocumentRef:AnotherRef", - Relationship("DocumentRef-ExternalDocument:SPDXRef-Test", RelationshipType.DEPENDS_ON, - "DocumentRef:AnotherRef")) - ]) +@pytest.mark.parametrize( + "relationship_str, expected_relationship", + [ + ( + "\n".join( + ["Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-File", "RelationshipComment: This is a comment."] + ), + Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-File", "This is a comment."), + ), + ( + "Relationship: SPDXRef-DOCUMENT PATCH_FOR NOASSERTION", + Relationship("SPDXRef-DOCUMENT", RelationshipType.PATCH_FOR, SpdxNoAssertion()), + ), + ( + "Relationship: SPDXRef-CarolCompression DEPENDS_ON NONE", + Relationship("SPDXRef-CarolCompression", RelationshipType.DEPENDS_ON, SpdxNone()), + ), + ( + "Relationship: DocumentRef-ExternalDocument:SPDXRef-Test DEPENDS_ON DocumentRef:AnotherRef", + Relationship( + "DocumentRef-ExternalDocument:SPDXRef-Test", RelationshipType.DEPENDS_ON, "DocumentRef:AnotherRef" + ), + ), + ], +) def test_parse_relationship(relationship_str, expected_relationship): parser = Parser() document = parser.parse("\n".join([DOCUMENT_STR, relationship_str])) @@ -41,12 +52,22 @@ def test_parse_relationship(relationship_str, expected_relationship): assert relationship == expected_relationship -@pytest.mark.parametrize("relationship_str, expected_message", - [("Relationship: spdx_id DESCRIBES", - ['Error while parsing Relationship: ["Relationship couldn\'t be split in ' - 'spdx_element_id, relationship_type and related_spdx_element. Line: 1"]']), - ("Relationship: spdx_id IS spdx_id", - ["Error while parsing Relationship: ['Invalid RelationshipType IS. Line: 1']"])]) +@pytest.mark.parametrize( + "relationship_str, expected_message", + [ + ( + "Relationship: spdx_id DESCRIBES", + [ + "Error while parsing Relationship: [\"Relationship couldn't be split in " + 'spdx_element_id, relationship_type and related_spdx_element. Line: 1"]' + ], + ), + ( + "Relationship: spdx_id IS spdx_id", + ["Error while parsing Relationship: ['Invalid RelationshipType IS. Line: 1']"], + ), + ], +) def test_parse_invalid_relationship(relationship_str, expected_message): parser = Parser() with pytest.raises(SPDXParsingError) as err: diff --git a/tests/spdx/parser/tagvalue/test_snippet_parser.py b/tests/spdx/parser/tagvalue/test_snippet_parser.py index 94c54c39f..4e563a581 100644 --- a/tests/spdx/parser/tagvalue/test_snippet_parser.py +++ b/tests/spdx/parser/tagvalue/test_snippet_parser.py @@ -21,20 +21,22 @@ def test_parse_snippet(): parser = Parser() - snippet_str = "\n".join([ - "SnippetSPDXID: SPDXRef-Snippet", - "SnippetLicenseComments: Some lic comment.", - "SnippetCopyrightText: Copyright 2008-2010 John Smith ", - "SnippetComment: Some snippet comment.", - "SnippetName: from linux kernel", - "SnippetFromFileSPDXID: SPDXRef-DoapSource", - "SnippetLicenseConcluded: Apache-2.0", - "LicenseInfoInSnippet: NOASSERTION", - "SnippetByteRange: 310:420", - "SnippetLineRange: 5:23", - "SnippetAttributionText: This is a text\nthat spans multiple lines.", - "SnippetAttributionText: This text spans one line but has trailing and leading whitespaces. " - ]) + snippet_str = "\n".join( + [ + "SnippetSPDXID: SPDXRef-Snippet", + "SnippetLicenseComments: Some lic comment.", + "SnippetCopyrightText: Copyright 2008-2010 John Smith ", + "SnippetComment: Some snippet comment.", + "SnippetName: from linux kernel", + "SnippetFromFileSPDXID: SPDXRef-DoapSource", + "SnippetLicenseConcluded: Apache-2.0", + "LicenseInfoInSnippet: NOASSERTION", + "SnippetByteRange: 310:420", + "SnippetLineRange: 5:23", + "SnippetAttributionText: This is a text\nthat spans multiple lines.", + "SnippetAttributionText: This text spans one line but has trailing and leading whitespaces. ", + ] + ) document = parser.parse("\n".join([DOCUMENT_STR, snippet_str])) assert document is not None @@ -53,22 +55,37 @@ def test_parse_snippet(): assert snippet.line_range[0] == 5 assert snippet.line_range[1] == 23 TestCase().assertCountEqual( - snippet.attribution_texts, ["This is a text\nthat spans multiple lines.", - "This text spans one line but has trailing and leading whitespaces."]) + snippet.attribution_texts, + [ + "This is a text\nthat spans multiple lines.", + "This text spans one line but has trailing and leading whitespaces.", + ], + ) -@pytest.mark.parametrize("snippet_str, expected_message", [ - ("SnippetName: TestSnippet", "Element Snippet is not the current element in scope, probably the expected " - "tag to start the element (SnippetSPDXID) is missing. Line: 1"), - ("SnippetSPDXID: SPDXDRef-Snippet\nSnippetByteRange: 1,4", - 'Error while parsing Snippet: ["Value for SnippetByteRange doesn\'t match ' - 'valid range pattern. Line: 2"]'), - ("SnippetSPDXID: SPDXDRef-Snippet\nSnippetByteRange: 1:4\nSnippetByteRange:10:23", - "Error while parsing Snippet: ['Multiple values for SnippetByteRange found. " - "Line: 3']"), - ("SnippetSPDXID: SPDXRef-Snippet", r"__init__() missing 2 required " - r"positional arguments: 'file_spdx_id' and 'byte_range'") -]) +@pytest.mark.parametrize( + "snippet_str, expected_message", + [ + ( + "SnippetName: TestSnippet", + "Element Snippet is not the current element in scope, probably the expected " + "tag to start the element (SnippetSPDXID) is missing. Line: 1", + ), + ( + "SnippetSPDXID: SPDXDRef-Snippet\nSnippetByteRange: 1,4", + "Error while parsing Snippet: [\"Value for SnippetByteRange doesn't match " + 'valid range pattern. Line: 2"]', + ), + ( + "SnippetSPDXID: SPDXDRef-Snippet\nSnippetByteRange: 1:4\nSnippetByteRange:10:23", + "Error while parsing Snippet: ['Multiple values for SnippetByteRange found. " "Line: 3']", + ), + ( + "SnippetSPDXID: SPDXRef-Snippet", + r"__init__() missing 2 required " r"positional arguments: 'file_spdx_id' and 'byte_range'", + ), + ], +) def test_parse_invalid_snippet(snippet_str, expected_message): parser = Parser() diff --git a/tests/spdx/parser/tagvalue/test_tag_value_lexer.py b/tests/spdx/parser/tagvalue/test_tag_value_lexer.py index 5eab39bea..2a8bb670b 100644 --- a/tests/spdx/parser/tagvalue/test_tag_value_lexer.py +++ b/tests/spdx/parser/tagvalue/test_tag_value_lexer.py @@ -28,14 +28,16 @@ def token_assert_helper(token, token_type, value, line_number): def test_tokenization_of_document(lexer): - document_str = "\n".join([ - "SPDXVersion: SPDX-2.1", - "DataLicense: CC0-1.0", - "DocumentName: Sample_Document-V2.1", - "SPDXID: SPDXRef-DOCUMENT", - "DocumentComment: Sample Comment", - "DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301" - ]) + document_str = "\n".join( + [ + "SPDXVersion: SPDX-2.1", + "DataLicense: CC0-1.0", + "DocumentName: Sample_Document-V2.1", + "SPDXID: SPDXRef-DOCUMENT", + "DocumentComment: Sample Comment", + "DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", + ] + ) lexer.input(document_str) token_assert_helper(lexer.token(), "DOC_VERSION", "SPDXVersion", 1) token_assert_helper(lexer.token(), "LINE", "SPDX-2.1", 1) @@ -48,38 +50,55 @@ def test_tokenization_of_document(lexer): token_assert_helper(lexer.token(), "DOC_COMMENT", "DocumentComment", 5) token_assert_helper(lexer.token(), "TEXT", "Sample Comment", 5) token_assert_helper(lexer.token(), "DOC_NAMESPACE", "DocumentNamespace", 6) - token_assert_helper(lexer.token(), "LINE", - "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", 6) + token_assert_helper( + lexer.token(), "LINE", "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", 6 + ) def test_tokenization_of_external_document_references(lexer): - data = "\n".join([ - "ExternalDocumentRef:DocumentRef-spdx-tool-2.1 http://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "ExternalDocumentRef:DocumentRef-spdx-tool-2.1 ldap://[2001:db8::7]/c=GB?objectClass?one SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759"]) + data = "\n".join( + [ + "ExternalDocumentRef:DocumentRef-spdx-tool-2.1 http://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3" + "-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + "ExternalDocumentRef:DocumentRef-spdx-tool-2.1 ldap://[2001:db8::7]/c=GB?objectClass?one " + "SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + ] + ) lexer.input(data) token_assert_helper(lexer.token(), "EXT_DOC_REF", "ExternalDocumentRef", 1) - token_assert_helper(lexer.token(), "LINE", - "DocumentRef-spdx-tool-2.1 http://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - 1) + token_assert_helper( + lexer.token(), + "LINE", + "DocumentRef-spdx-tool-2.1 http://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301 " + "SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + 1, + ) token_assert_helper(lexer.token(), "EXT_DOC_REF", "ExternalDocumentRef", 2) - token_assert_helper(lexer.token(), "LINE", - "DocumentRef-spdx-tool-2.1 ldap://[2001:db8::7]/c=GB?objectClass?one SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - 2) + token_assert_helper( + lexer.token(), + "LINE", + "DocumentRef-spdx-tool-2.1 ldap://[2001:db8::7]/c=GB?objectClass?one " + "SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + 2, + ) def test_tokenization_of_file(lexer): - file_str = "\n".join([ - "FileName: testfile.java", - "SPDXID: SPDXRef-File", - "FileType: SOURCE", - "FileType: TEXT", - "FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - "LicenseConcluded: Apache-2.0", - "LicenseInfoInFile: Apache-2.0", - "FileCopyrightText: Copyright 2014 Acme Inc.", - "FileComment: Very long file", - "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." - ]) + file_str = "\n".join( + [ + "FileName: testfile.java", + "SPDXID: SPDXRef-File", + "FileType: SOURCE", + "FileType: TEXT", + "FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "LicenseConcluded: Apache-2.0", + "LicenseInfoInFile: Apache-2.0", + "FileCopyrightText: Copyright 2014 Acme Inc.", + "FileComment: Very long file", + "FileAttributionText: Acknowledgements that might be required to be communicated in some contexts." + "", + ] + ) lexer.input(file_str) token_assert_helper(lexer.token(), "FILE_NAME", "FileName", 1) @@ -101,18 +120,23 @@ def test_tokenization_of_file(lexer): token_assert_helper(lexer.token(), "FILE_COMMENT", "FileComment", 9) token_assert_helper(lexer.token(), "TEXT", "Very long file", 9) token_assert_helper(lexer.token(), "FILE_ATTRIBUTION_TEXT", "FileAttributionText", 10) - token_assert_helper(lexer.token(), "TEXT", - "Acknowledgements that might be required to be communicated in some contexts.", - 10) + token_assert_helper( + lexer.token(), + "TEXT", + "Acknowledgements that might be required to be communicated in some contexts.", + 10, + ) def test_tokenization_of_creation_info(lexer): - creation_str = "\n".join([ - "Creator: Person: Bob (bob@example.com)", - "Creator: Organization: Acme.", - "Created: 2010-02-03T00:00:00Z", - "CreatorComment: Sample Comment" - ]) + creation_str = "\n".join( + [ + "Creator: Person: Bob (bob@example.com)", + "Creator: Organization: Acme.", + "Created: 2010-02-03T00:00:00Z", + "CreatorComment: Sample Comment", + ] + ) lexer.input(creation_str) token_assert_helper(lexer.token(), "CREATOR", "Creator", 1) @@ -126,34 +150,36 @@ def test_tokenization_of_creation_info(lexer): def test_tokenization_of_package(lexer): - package_str = "\n".join([ - "PackageName: Test", - "SPDXID: SPDXRef-Package", - "PackageVersion: Version 0.9.2", - "PackageDownloadLocation: http://example.com/test", - "FilesAnalyzed: True", - "PackageSummary: Test package", - "PackageSourceInfo: Version 1.0 of test", - "PackageFileName: test-1.0.zip", - "PackageSupplier: Organization:ACME", - "PackageOriginator: Organization:ACME", - "PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - "PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", - "PackageDescription: A package.", - "PackageComment: Comment on the package.", - "PackageCopyrightText: Copyright 2014 Acme Inc.", - "PackageLicenseDeclared: Apache-2.0", - "PackageLicenseConcluded: (LicenseRef-2.0 and Apache-2.0)", - "PackageLicenseInfoFromFiles: Apache-1.0", - "PackageLicenseInfoFromFiles: Apache-2.0", - "PackageLicenseComments: License Comments", - "ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", - "ExternalRefComment: Some comment about the package.", - "PrimaryPackagePurpose: OPERATING-SYSTEM", - "BuiltDate: 2020-01-01T12:00:00Z", - "ReleaseDate: 2021-01-01T12:00:00Z", - "ValidUntilDate: 2022-01-01T12:00:00Z" - ]) + package_str = "\n".join( + [ + "PackageName: Test", + "SPDXID: SPDXRef-Package", + "PackageVersion: Version 0.9.2", + "PackageDownloadLocation: http://example.com/test", + "FilesAnalyzed: True", + "PackageSummary: Test package", + "PackageSourceInfo: Version 1.0 of test", + "PackageFileName: test-1.0.zip", + "PackageSupplier: Organization:ACME", + "PackageOriginator: Organization:ACME", + "PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", + "PackageDescription: A package.", + "PackageComment: Comment on the package.", + "PackageCopyrightText: Copyright 2014 Acme Inc.", + "PackageLicenseDeclared: Apache-2.0", + "PackageLicenseConcluded: (LicenseRef-2.0 and Apache-2.0)", + "PackageLicenseInfoFromFiles: Apache-1.0", + "PackageLicenseInfoFromFiles: Apache-2.0", + "PackageLicenseComments: License Comments", + "ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", + "ExternalRefComment: Some comment about the package.", + "PrimaryPackagePurpose: OPERATING-SYSTEM", + "BuiltDate: 2020-01-01T12:00:00Z", + "ReleaseDate: 2021-01-01T12:00:00Z", + "ValidUntilDate: 2022-01-01T12:00:00Z", + ] + ) lexer.input(package_str) token_assert_helper(lexer.token(), "PKG_NAME", "PackageName", 1) @@ -179,8 +205,9 @@ def test_tokenization_of_package(lexer): token_assert_helper(lexer.token(), "PKG_CHECKSUM", "PackageChecksum", 11) token_assert_helper(lexer.token(), "CHECKSUM", "SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", 11) token_assert_helper(lexer.token(), "PKG_VERIFICATION_CODE", "PackageVerificationCode", 12) - token_assert_helper(lexer.token(), "LINE", - "4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", 12) + token_assert_helper( + lexer.token(), "LINE", "4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)", 12 + ) token_assert_helper(lexer.token(), "PKG_DESCRIPTION", "PackageDescription", 13) token_assert_helper(lexer.token(), "TEXT", "A package.", 13) token_assert_helper(lexer.token(), "PKG_COMMENT", "PackageComment", 14) @@ -198,8 +225,9 @@ def test_tokenization_of_package(lexer): token_assert_helper(lexer.token(), "PKG_LICENSE_COMMENT", "PackageLicenseComments", 20) token_assert_helper(lexer.token(), "TEXT", "License Comments", 20) token_assert_helper(lexer.token(), "PKG_EXTERNAL_REF", "ExternalRef", 21) - token_assert_helper(lexer.token(), "LINE", - "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", 21) + token_assert_helper( + lexer.token(), "LINE", "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:", 21 + ) token_assert_helper(lexer.token(), "PKG_EXTERNAL_REF_COMMENT", "ExternalRefComment", 22) token_assert_helper(lexer.token(), "TEXT", "Some comment about the package.", 22) token_assert_helper(lexer.token(), "PRIMARY_PACKAGE_PURPOSE", "PrimaryPackagePurpose", 23) @@ -220,18 +248,20 @@ def test_tokenization_of_unknown_tag(lexer): def test_tokenization_of_snippet(lexer): - snippet_str = "\n".join([ - "SnippetSPDXID: SPDXRef-Snippet", - "SnippetLicenseComments: Some lic comment.", - "SnippetCopyrightText: Copyright 2008-2010 John Smith ", - "SnippetComment: Some snippet comment.", - "SnippetName: from linux kernel", - "SnippetFromFileSPDXID: SPDXRef-DoapSource", - "SnippetLicenseConcluded: Apache-2.0", - "LicenseInfoInSnippet: Apache-2.0", - "SnippetByteRange: 310:420", - "SnippetLineRange: 5:23", - ]) + snippet_str = "\n".join( + [ + "SnippetSPDXID: SPDXRef-Snippet", + "SnippetLicenseComments: Some lic comment.", + "SnippetCopyrightText: Copyright 2008-2010 John Smith ", + "SnippetComment: Some snippet comment.", + "SnippetName: from linux kernel", + "SnippetFromFileSPDXID: SPDXRef-DoapSource", + "SnippetLicenseConcluded: Apache-2.0", + "LicenseInfoInSnippet: Apache-2.0", + "SnippetByteRange: 310:420", + "SnippetLineRange: 5:23", + ] + ) lexer.input(snippet_str) token_assert_helper(lexer.token(), "SNIPPET_SPDX_ID", "SnippetSPDXID", 1) token_assert_helper(lexer.token(), "LINE", "SPDXRef-Snippet", 1) @@ -245,8 +275,7 @@ def test_tokenization_of_snippet(lexer): token_assert_helper(lexer.token(), "LINE", "from linux kernel", 5) token_assert_helper(lexer.token(), "SNIPPET_FILE_SPDXID", "SnippetFromFileSPDXID", 6) token_assert_helper(lexer.token(), "LINE", "SPDXRef-DoapSource", 6) - token_assert_helper(lexer.token(), "SNIPPET_LICENSE_CONCLUDED", - "SnippetLicenseConcluded", 7) + token_assert_helper(lexer.token(), "SNIPPET_LICENSE_CONCLUDED", "SnippetLicenseConcluded", 7) token_assert_helper(lexer.token(), "LINE", "Apache-2.0", 7) token_assert_helper(lexer.token(), "SNIPPET_LICENSE_INFO", "LicenseInfoInSnippet", 8) token_assert_helper(lexer.token(), "LINE", "Apache-2.0", 8) @@ -257,13 +286,15 @@ def test_tokenization_of_snippet(lexer): def test_tokenization_of_annotation(lexer): - annotation_str = "\n".join([ - "Annotator: Person: Jane Doe()", - "AnnotationDate: 2010-01-29T18:30:22Z", - "AnnotationComment: Document level annotation", - "AnnotationType: OTHER", - "SPDXREF: SPDXRef-DOCUMENT" - ]) + annotation_str = "\n".join( + [ + "Annotator: Person: Jane Doe()", + "AnnotationDate: 2010-01-29T18:30:22Z", + "AnnotationComment: Document level annotation", + "AnnotationType: OTHER", + "SPDXREF: SPDXRef-DOCUMENT", + ] + ) lexer.input(annotation_str) token_assert_helper(lexer.token(), "ANNOTATOR", "Annotator", 1) @@ -279,9 +310,13 @@ def test_tokenization_of_annotation(lexer): def test_tokenization_of_relationship(lexer): - relationship_str = "\n".join(["Relationship: SPDXRef-DOCUMENT DESCRIBES NONE", - "RelationshipComment: This is a comment.", - "Relationship: DocumentRef-extern:SPDXRef-Package DESCRIBES NONE"]) + relationship_str = "\n".join( + [ + "Relationship: SPDXRef-DOCUMENT DESCRIBES NONE", + "RelationshipComment: This is a comment.", + "Relationship: DocumentRef-extern:SPDXRef-Package DESCRIBES NONE", + ] + ) lexer.input(relationship_str) token_assert_helper(lexer.token(), "RELATIONSHIP", "Relationship", 1) diff --git a/tests/spdx/parser/tagvalue/test_tag_value_parser.py b/tests/spdx/parser/tagvalue/test_tag_value_parser.py index f194af2a7..1cd0183e0 100644 --- a/tests/spdx/parser/tagvalue/test_tag_value_parser.py +++ b/tests/spdx/parser/tagvalue/test_tag_value_parser.py @@ -14,7 +14,7 @@ import pytest from spdx.model.document import Document -from spdx.model.relationship import RelationshipType, Relationship +from spdx.model.relationship import Relationship, RelationshipType from spdx.parser.error import SPDXParsingError from spdx.parser.tagvalue.parser import Parser from tests.spdx.parser.tagvalue.test_creation_info_parser import DOCUMENT_STR @@ -47,36 +47,53 @@ def test_tag_value_parser(): def test_building_contains_relationship(): parser = Parser() document_str = "\n".join( - [DOCUMENT_STR, "FileName: File without package", "SPDXID: SPDXRef-File", - "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "PackageName: Package with two files", "SPDXID: SPDXRef-Package-with-two-files", - "PackageDownloadLocation: https://download.com", - "FileName: File in package", "SPDXID: SPDXRef-File-in-Package", - "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "FileName: Second file in package", "SPDXID: SPDXRef-Second-File-in-Package", - "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - "PackageName: Second package with file", "SPDXID: SPDXRef-Package-with-one-file", - "PackageDownloadLocation: https://download.com", - "FileName: File in package", "SPDXID: SPDXRef-File-in-different-Package", - "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", - ]) + [ + DOCUMENT_STR, + "FileName: File without package", + "SPDXID: SPDXRef-File", + "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + "PackageName: Package with two files", + "SPDXID: SPDXRef-Package-with-two-files", + "PackageDownloadLocation: https://download.com", + "FileName: File in package", + "SPDXID: SPDXRef-File-in-Package", + "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + "FileName: Second file in package", + "SPDXID: SPDXRef-Second-File-in-Package", + "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + "PackageName: Second package with file", + "SPDXID: SPDXRef-Package-with-one-file", + "PackageDownloadLocation: https://download.com", + "FileName: File in package", + "SPDXID: SPDXRef-File-in-different-Package", + "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + ] + ) document = parser.parse(document_str) assert document.relationships == [ Relationship("SPDXRef-Package-with-two-files", RelationshipType.CONTAINS, "SPDXRef-File-in-Package"), Relationship("SPDXRef-Package-with-two-files", RelationshipType.CONTAINS, "SPDXRef-Second-File-in-Package"), - Relationship("SPDXRef-Package-with-one-file", RelationshipType.CONTAINS, "SPDXRef-File-in-different-Package")] + Relationship("SPDXRef-Package-with-one-file", RelationshipType.CONTAINS, "SPDXRef-File-in-different-Package"), + ] def test_document_with_mixed_values(): parser = Parser() document_str = "\n".join( - ["SPDXID:SPDXRef-DOCUMENT", "FileName: File without package", "SPDXID: SPDXRef-File", - "PackageDownloadLocation: https://download.com", - "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759"]) + [ + "SPDXID:SPDXRef-DOCUMENT", + "FileName: File without package", + "SPDXID: SPDXRef-File", + "PackageDownloadLocation: https://download.com", + "FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759", + ] + ) with pytest.raises(SPDXParsingError) as err: parser.parse(document_str) - assert err.value.get_messages() == ["Element Package is not the current element in scope, probably the expected " - "tag to start the element (PackageName) is missing. Line: 4"] + assert err.value.get_messages() == [ + "Element Package is not the current element in scope, probably the expected " + "tag to start the element (PackageName) is missing. Line: 4" + ] diff --git a/tests/spdx/test_actor_parser.py b/tests/spdx/test_actor_parser.py index 2e956a14f..dfd43a172 100644 --- a/tests/spdx/test_actor_parser.py +++ b/tests/spdx/test_actor_parser.py @@ -8,20 +8,29 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import pytest from unittest import TestCase +import pytest + from spdx.model.actor import ActorType -from spdx.parser.error import SPDXParsingError from spdx.parser.actor_parser import ActorParser +from spdx.parser.error import SPDXParsingError -@pytest.mark.parametrize("actor_string,expected_type,expected_name,expected_mail", [ - ("Person: Jane Doe (jane.doe@example.com)", ActorType.PERSON, "Jane Doe", "jane.doe@example.com"), - ("Organization: Example organization (organization@example.com)", ActorType.ORGANIZATION, "Example organization", - "organization@example.com"), - ("Organization: Example organization ( )", ActorType.ORGANIZATION, "Example organization", None), - ("Tool: Example tool ", ActorType.TOOL, "Example tool", None)]) +@pytest.mark.parametrize( + "actor_string,expected_type,expected_name,expected_mail", + [ + ("Person: Jane Doe (jane.doe@example.com)", ActorType.PERSON, "Jane Doe", "jane.doe@example.com"), + ( + "Organization: Example organization (organization@example.com)", + ActorType.ORGANIZATION, + "Example organization", + "organization@example.com", + ), + ("Organization: Example organization ( )", ActorType.ORGANIZATION, "Example organization", None), + ("Tool: Example tool ", ActorType.TOOL, "Example tool", None), + ], +) def test_parse_actor(actor_string, expected_type, expected_name, expected_mail): actor_parser = ActorParser() @@ -32,12 +41,16 @@ def test_parse_actor(actor_string, expected_type, expected_name, expected_mail): assert actor.email == expected_mail -@pytest.mark.parametrize("actor_string,expected_message", [ - ("Perso: Jane Doe (jane.doe@example.com)", - ["Actor Perso: Jane Doe (jane.doe@example.com) doesn't match any of person, organization or tool."]), - ("Toole Example Tool ()", - ["Actor Toole Example Tool () doesn't match any of person, organization or tool."]) -]) +@pytest.mark.parametrize( + "actor_string,expected_message", + [ + ( + "Perso: Jane Doe (jane.doe@example.com)", + ["Actor Perso: Jane Doe (jane.doe@example.com) doesn't match any of person, organization or tool."], + ), + ("Toole Example Tool ()", ["Actor Toole Example Tool () doesn't match any of person, organization or tool."]), + ], +) def test_parse_invalid_actor(actor_string, expected_message): actor_parser = ActorParser() actor_string = actor_string diff --git a/tests/spdx/test_casing_tools.py b/tests/spdx/test_casing_tools.py index c5be2beb3..354cb7657 100644 --- a/tests/spdx/test_casing_tools.py +++ b/tests/spdx/test_casing_tools.py @@ -10,7 +10,7 @@ # limitations under the License. import pytest -from spdx.casing_tools import snake_case_to_camel_case, camel_case_to_snake_case +from spdx.casing_tools import camel_case_to_snake_case, snake_case_to_camel_case @pytest.mark.parametrize("snake_case_str,camel_case_str", [("snake_case", "snakeCase")]) @@ -20,9 +20,10 @@ def test_snake_case_to_camel_case(snake_case_str, camel_case_str): assert camel_case == camel_case_str -@pytest.mark.parametrize("camel_case_str,snake_case_str", - [("camelCase", "camel_case"), ("camelCaseMore", "camel_case_more"), - ("CamelCase", "camel_case")]) +@pytest.mark.parametrize( + "camel_case_str,snake_case_str", + [("camelCase", "camel_case"), ("camelCaseMore", "camel_case_more"), ("CamelCase", "camel_case")], +) def test_camel_case_to_snake_case(camel_case_str, snake_case_str): snake_case = camel_case_to_snake_case(camel_case_str) diff --git a/tests/spdx/test_datetime_conversions.py b/tests/spdx/test_datetime_conversions.py index 265054c0b..b396edf13 100644 --- a/tests/spdx/test_datetime_conversions.py +++ b/tests/spdx/test_datetime_conversions.py @@ -27,9 +27,13 @@ def test_datetime_from_str(): assert date == datetime(2010, 3, 4, 5, 45, 11) -@pytest.mark.parametrize("invalid_date_str, error_type, expected_message", - [(5, TypeError, "Could not convert str to datetime, invalid type: int"), - ("2010-02-03", ValueError, "time data '2010-02-03' does not match format '%Y-%m-%dT%H:%M:%SZ'")]) +@pytest.mark.parametrize( + "invalid_date_str, error_type, expected_message", + [ + (5, TypeError, "Could not convert str to datetime, invalid type: int"), + ("2010-02-03", ValueError, "time data '2010-02-03' does not match format '%Y-%m-%dT%H:%M:%SZ'"), + ], +) def test_datetime_from_str_error(invalid_date_str, error_type, expected_message): with pytest.raises(error_type, match=expected_message): datetime_from_str(invalid_date_str) diff --git a/tests/spdx/test_document_utils.py b/tests/spdx/test_document_utils.py index f2b0fb2ad..4c69f229d 100644 --- a/tests/spdx/test_document_utils.py +++ b/tests/spdx/test_document_utils.py @@ -5,8 +5,8 @@ import pytest -from spdx.document_utils import get_element_from_spdx_id, get_contained_spdx_element_ids -from tests.spdx.fixtures import document_fixture, snippet_fixture, package_fixture, file_fixture +from spdx.document_utils import get_contained_spdx_element_ids, get_element_from_spdx_id +from tests.spdx.fixtures import document_fixture, file_fixture, package_fixture, snippet_fixture @pytest.fixture diff --git a/tests/spdx/validation/test_actor_validator.py b/tests/spdx/validation/test_actor_validator.py index dbee17547..19a99b8c7 100644 --- a/tests/spdx/validation/test_actor_validator.py +++ b/tests/spdx/validation/test_actor_validator.py @@ -15,7 +15,7 @@ from spdx.model.actor import ActorType from spdx.validation.actor_validator import validate_actor -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import actor_fixture @@ -26,16 +26,22 @@ def test_valid_actor_person(): assert validation_messages == [] -@pytest.mark.parametrize("actor, expected_message", - [(actor_fixture(actor_type=ActorType.TOOL, email="mail@mail.com"), - "email must be None if actor_type is TOOL, but is: mail@mail.com"), - ]) +@pytest.mark.parametrize( + "actor, expected_message", + [ + ( + actor_fixture(actor_type=ActorType.TOOL, email="mail@mail.com"), + "email must be None if actor_type is TOOL, but is: mail@mail.com", + ), + ], +) def test_invalid_actor(actor, expected_message): parent_id = "SPDXRef-DOCUMENT" validation_messages: List[ValidationMessage] = validate_actor(actor, parent_id) - expected = ValidationMessage(expected_message, - ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, - full_element=actor)) + expected = ValidationMessage( + expected_message, + ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor), + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_annotation_validator.py b/tests/spdx/validation/test_annotation_validator.py index 608de5bb8..aba5995d5 100644 --- a/tests/spdx/validation/test_annotation_validator.py +++ b/tests/spdx/validation/test_annotation_validator.py @@ -16,8 +16,8 @@ from spdx.model.annotation import Annotation from spdx.model.document import Document from spdx.validation.annotation_validator import validate_annotation -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -from tests.spdx.fixtures import document_fixture, annotation_fixture, file_fixture +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage +from tests.spdx.fixtures import annotation_fixture, document_fixture, file_fixture def test_valid_annotation(): @@ -26,17 +26,23 @@ def test_valid_annotation(): assert validation_messages == [] -@pytest.mark.parametrize("annotation_id, file_id, expected_message", - [("SPDXRef-File", "SPDXRef-hiddenFile", - 'did not find the referenced spdx_id "SPDXRef-File" in the SPDX document') - ]) +@pytest.mark.parametrize( + "annotation_id, file_id, expected_message", + [ + ( + "SPDXRef-File", + "SPDXRef-hiddenFile", + 'did not find the referenced spdx_id "SPDXRef-File" in the SPDX document', + ) + ], +) def test_invalid_annotation(annotation_id, file_id, expected_message): annotation: Annotation = annotation_fixture(spdx_id=annotation_id) document: Document = document_fixture(files=[file_fixture(spdx_id=file_id)]) validation_messages: List[ValidationMessage] = validate_annotation(annotation, document) - expected = ValidationMessage(expected_message, - ValidationContext(element_type=SpdxElementType.ANNOTATION, - full_element=annotation)) + expected = ValidationMessage( + expected_message, ValidationContext(element_type=SpdxElementType.ANNOTATION, full_element=annotation) + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_checksum_validator.py b/tests/spdx/validation/test_checksum_validator.py index 995806a28..7f4ae51d5 100644 --- a/tests/spdx/validation/test_checksum_validator.py +++ b/tests/spdx/validation/test_checksum_validator.py @@ -15,114 +15,220 @@ from spdx.model.checksum import Checksum, ChecksumAlgorithm from spdx.validation.checksum_validator import validate_checksum -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import checksum_fixture -@pytest.mark.parametrize("checksum", - [checksum_fixture(), - Checksum(ChecksumAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), - Checksum(ChecksumAlgorithm.SHA224, - "9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588"), - Checksum(ChecksumAlgorithm.SHA256, - "fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299"), - Checksum(ChecksumAlgorithm.SHA384, - "73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933"), - Checksum(ChecksumAlgorithm.SHA512, - "c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f15af43e7cb5547f1a464053"), - Checksum(ChecksumAlgorithm.SHA3_256, - "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), - Checksum(ChecksumAlgorithm.SHA3_384, - "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166"), - Checksum(ChecksumAlgorithm.SHA3_512, - "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36"), - Checksum(ChecksumAlgorithm.BLAKE2B_256, - "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), - Checksum(ChecksumAlgorithm.BLAKE2B_384, - "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2"), - Checksum(ChecksumAlgorithm.BLAKE2B_512, - "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c"), - Checksum(ChecksumAlgorithm.BLAKE3, - "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed"), - Checksum(ChecksumAlgorithm.MD2, "af1eec2a1b18886c3f3cc244349d91d8"), - Checksum(ChecksumAlgorithm.MD4, "d4c41ce30a517d6ce9d79c8c17bb4b66"), - Checksum(ChecksumAlgorithm.MD5, "0d7f61beb7018b3924c6b8f96549fa39"), - Checksum(ChecksumAlgorithm.MD6, - "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39"), - Checksum(ChecksumAlgorithm.ADLER32, "02ec0130")]) +@pytest.mark.parametrize( + "checksum", + [ + checksum_fixture(), + Checksum(ChecksumAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), + Checksum(ChecksumAlgorithm.SHA224, "9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588"), + Checksum(ChecksumAlgorithm.SHA256, "fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299"), + Checksum( + ChecksumAlgorithm.SHA384, + "73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933", + ), + Checksum( + ChecksumAlgorithm.SHA512, + "c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f" + "15af43e7cb5547f1a464053", + ), + Checksum(ChecksumAlgorithm.SHA3_256, "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), + Checksum( + ChecksumAlgorithm.SHA3_384, + "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166", + ), + Checksum( + ChecksumAlgorithm.SHA3_512, + "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d11" + "1310266a5d46e2bc1ffbb36", + ), + Checksum(ChecksumAlgorithm.BLAKE2B_256, "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), + Checksum( + ChecksumAlgorithm.BLAKE2B_384, + "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2", + ), + Checksum( + ChecksumAlgorithm.BLAKE2B_512, + "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8" + "c4af74dce531ca8ebd8824c", + ), + Checksum( + ChecksumAlgorithm.BLAKE3, + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874d" + "cec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006" + "857d3b9985174bf67239874dcec4cbbc9839496179feafed", + ), + Checksum(ChecksumAlgorithm.MD2, "af1eec2a1b18886c3f3cc244349d91d8"), + Checksum(ChecksumAlgorithm.MD4, "d4c41ce30a517d6ce9d79c8c17bb4b66"), + Checksum(ChecksumAlgorithm.MD5, "0d7f61beb7018b3924c6b8f96549fa39"), + Checksum( + ChecksumAlgorithm.MD6, + "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39", + ), + Checksum(ChecksumAlgorithm.ADLER32, "02ec0130"), + ], +) def test_valid_checksum(checksum): validation_messages: List[ValidationMessage] = validate_checksum(checksum, "parent_id", "SPDX-2.3") assert validation_messages == [] -@pytest.mark.parametrize("checksum, expected_message", - [(Checksum(ChecksumAlgorithm.SHA1, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA1 must consist of 40 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA224, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA224 must consist of 56 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA256, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA256 must consist of 64 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA384, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA384 must consist of 96 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA512, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA512 must consist of 128 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA3_256, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA3_256 must consist of 64 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA3_384, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA3_384 must consist of 96 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA3_512, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.SHA3_512 must consist of 128 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.BLAKE2B_256, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.BLAKE2B_256 must consist of 64 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.BLAKE2B_384, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.BLAKE2B_384 must consist of 96 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.BLAKE2B_512, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.BLAKE2B_512 must consist of 128 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.BLAKE3, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.BLAKE3 must consist of at least 256 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.MD2, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), - "value of ChecksumAlgorithm.MD2 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"), - (Checksum(ChecksumAlgorithm.MD4, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), - "value of ChecksumAlgorithm.MD4 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"), - (Checksum(ChecksumAlgorithm.MD5, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), - "value of ChecksumAlgorithm.MD5 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"), - (Checksum(ChecksumAlgorithm.MD6, - "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed5"), - "value of ChecksumAlgorithm.MD6 must consist of between 0 and 512 lowercase hexadecimal digits, but is: a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed5 (length: 513 digits)"), - (Checksum(ChecksumAlgorithm.ADLER32, "af1eec2a1b18886c3f3cc244349d91d8"), - "value of ChecksumAlgorithm.ADLER32 must consist of 8 lowercase hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"), - (Checksum(ChecksumAlgorithm.SHA1, "CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4"), - "value of ChecksumAlgorithm.SHA1 must consist of 40 lowercase hexadecimal digits, but is: CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4 (length: 40 digits)"), - ]) +@pytest.mark.parametrize( + "checksum, expected_message", + [ + ( + Checksum(ChecksumAlgorithm.SHA1, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA1 must consist of 40 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA224, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA224 must consist of 56 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA256, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA256 must consist of 64 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA384, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA384 must consist of 96 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA512, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA512 must consist of 128 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA3_256, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA3_256 must consist of 64 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA3_384, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA3_384 must consist of 96 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA3_512, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.SHA3_512 must consist of 128 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.BLAKE2B_256, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.BLAKE2B_256 must consist of 64 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.BLAKE2B_384, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.BLAKE2B_384 must consist of 96 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.BLAKE2B_512, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.BLAKE2B_512 must consist of 128 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.BLAKE3, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.BLAKE3 must consist of at least 256 lowercase hexadecimal digits, but is: af1e" + "ec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.MD2, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), + "value of ChecksumAlgorithm.MD2 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364" + "f3ebbb42c484ff43d00791c (length: 40 digits)", + ), + ( + Checksum(ChecksumAlgorithm.MD4, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), + "value of ChecksumAlgorithm.MD4 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364" + "f3ebbb42c484ff43d00791c (length: 40 digits)", + ), + ( + Checksum(ChecksumAlgorithm.MD5, "71c4025dd9897b364f3ebbb42c484ff43d00791c"), + "value of ChecksumAlgorithm.MD5 must consist of 32 lowercase hexadecimal digits, but is: 71c4025dd9897b364" + "f3ebbb42c484ff43d00791c (length: 40 digits)", + ), + ( + Checksum( + ChecksumAlgorithm.MD6, + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf672398" + "74dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967" + "a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582" + "b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b" + "5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc983949617" + "9feafed5", + ), + "value of ChecksumAlgorithm.MD6 must consist of between 0 and 512 lowercase hexadecimal digits, but is: " + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dc" + "ec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a1300685" + "7d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6a" + "c3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341" + "bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed5 " + "(length: 513 digits)", + ), + ( + Checksum(ChecksumAlgorithm.ADLER32, "af1eec2a1b18886c3f3cc244349d91d8"), + "value of ChecksumAlgorithm.ADLER32 must consist of 8 lowercase hexadecimal digits, but is: " + "af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)", + ), + ( + Checksum(ChecksumAlgorithm.SHA1, "CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4"), + "value of ChecksumAlgorithm.SHA1 must consist of 40 lowercase hexadecimal digits, but is: " + "CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4 (length: 40 digits)", + ), + ], +) def test_invalid_checksum(checksum, expected_message): parent_id = "parent_id" validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id, "SPDX-2.3") - expected = ValidationMessage(expected_message, - ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, - full_element=checksum)) + expected = ValidationMessage( + expected_message, + ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM, full_element=checksum), + ) assert validation_messages == [expected] -@pytest.mark.parametrize("checksum", - [Checksum(ChecksumAlgorithm.SHA3_256, - "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), - Checksum(ChecksumAlgorithm.SHA3_384, - "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166"), - Checksum(ChecksumAlgorithm.SHA3_512, - "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36"), - Checksum(ChecksumAlgorithm.BLAKE2B_256, - "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), - Checksum(ChecksumAlgorithm.BLAKE2B_384, - "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2"), - Checksum(ChecksumAlgorithm.BLAKE2B_512, - "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c"), - Checksum(ChecksumAlgorithm.BLAKE3, - "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed"), - Checksum(ChecksumAlgorithm.ADLER32, "02ec0130") - ]) +@pytest.mark.parametrize( + "checksum", + [ + Checksum(ChecksumAlgorithm.SHA3_256, "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"), + Checksum( + ChecksumAlgorithm.SHA3_384, + "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166", + ), + Checksum( + ChecksumAlgorithm.SHA3_512, + "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d1" + "11310266a5d46e2bc1ffbb36", + ), + Checksum(ChecksumAlgorithm.BLAKE2B_256, "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"), + Checksum( + ChecksumAlgorithm.BLAKE2B_384, + "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2", + ), + Checksum( + ChecksumAlgorithm.BLAKE2B_512, + "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e" + "8c4af74dce531ca8ebd8824c", + ), + Checksum( + ChecksumAlgorithm.BLAKE3, + "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874" + "dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006" + "857d3b9985174bf67239874dcec4cbbc9839496179feafed", + ), + Checksum(ChecksumAlgorithm.ADLER32, "02ec0130"), + ], +) def test_v2_3only_checksums(checksum): parent_id = "parent_id" validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id, "SPDX-2.2") diff --git a/tests/spdx/validation/test_creation_info_validator.py b/tests/spdx/validation/test_creation_info_validator.py index 4e62e6fbc..b278e2f0c 100644 --- a/tests/spdx/validation/test_creation_info_validator.py +++ b/tests/spdx/validation/test_creation_info_validator.py @@ -14,7 +14,7 @@ import pytest from spdx.validation.creation_info_validator import validate_creation_info -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import creation_info_fixture @@ -25,15 +25,23 @@ def test_valid_creation_info(): assert validation_messages == [] -@pytest.mark.parametrize \ - ("creation_info_input, spdx_id, expected_message", - [(creation_info_fixture(spdx_id="SPDXRef-doc"), "SPDXRef-doc", - 'spdx_id must be "SPDXRef-DOCUMENT", but is: SPDXRef-doc'), - (creation_info_fixture(data_license="MIT"), "SPDXRef-DOCUMENT", - 'data_license must be "CC0-1.0", but is: MIT'), - (creation_info_fixture(document_namespace="some_namespace"), "SPDXRef-DOCUMENT", - "document_namespace must be a valid URI specified in RFC-3986 and must contain no fragment (#), but is: some_namespace"), - ]) +@pytest.mark.parametrize( + "creation_info_input, spdx_id, expected_message", + [ + ( + creation_info_fixture(spdx_id="SPDXRef-doc"), + "SPDXRef-doc", + 'spdx_id must be "SPDXRef-DOCUMENT", but is: SPDXRef-doc', + ), + (creation_info_fixture(data_license="MIT"), "SPDXRef-DOCUMENT", 'data_license must be "CC0-1.0", but is: MIT'), + ( + creation_info_fixture(document_namespace="some_namespace"), + "SPDXRef-DOCUMENT", + "document_namespace must be a valid URI specified in RFC-3986 and must contain no fragment (#), " + "but is: some_namespace", + ), + ], +) def test_invalid_creation_info(creation_info_input, expected_message, spdx_id): validation_messages: List[ValidationMessage] = validate_creation_info(creation_info_input, "SPDX-2.3") diff --git a/tests/spdx/validation/test_document_validator.py b/tests/spdx/validation/test_document_validator.py index f9a66d1b5..d26258b63 100644 --- a/tests/spdx/validation/test_document_validator.py +++ b/tests/spdx/validation/test_document_validator.py @@ -13,11 +13,11 @@ import pytest -from spdx.model.document import Document, CreationInfo +from spdx.model.document import CreationInfo, Document from spdx.model.relationship import Relationship, RelationshipType from spdx.validation.document_validator import validate_full_spdx_document -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -from tests.spdx.fixtures import document_fixture, creation_info_fixture, file_fixture, package_fixture, snippet_fixture +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage +from tests.spdx.fixtures import creation_info_fixture, document_fixture, file_fixture, package_fixture, snippet_fixture def test_valid_document(): @@ -27,22 +27,44 @@ def test_valid_document(): assert validation_messages == [] -@pytest.mark.parametrize("creation_info, version_input, expected_message", - [(creation_info_fixture(spdx_version="SPDX-2.3"), "SPDX-2.3", None), - (creation_info_fixture(spdx_version="SPDX-2.3"), None, None), - (creation_info_fixture(spdx_version="SPDX-2.3"), "SPDX-2.2", - "provided SPDX version SPDX-2.2 does not match the document's SPDX version SPDX-2.3"), - (creation_info_fixture(spdx_version="SPDX-2.3"), "SPDX2.3", - "provided SPDX version SPDX2.3 does not match the document's SPDX version SPDX-2.3"), - (creation_info_fixture(spdx_version="SPDX2.3"), "SPDX-2.3", - 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), - (creation_info_fixture(spdx_version="SPDX2.3"), None, - 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), - (creation_info_fixture(spdx_version="SPDX2.3"), "SPDX2.3", - 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3'), - (creation_info_fixture(spdx_version="SPDX-2.1"), "SPDX-2.1", - 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX-2.1'), - ]) +@pytest.mark.parametrize( + "creation_info, version_input, expected_message", + [ + (creation_info_fixture(spdx_version="SPDX-2.3"), "SPDX-2.3", None), + (creation_info_fixture(spdx_version="SPDX-2.3"), None, None), + ( + creation_info_fixture(spdx_version="SPDX-2.3"), + "SPDX-2.2", + "provided SPDX version SPDX-2.2 does not match the document's SPDX version SPDX-2.3", + ), + ( + creation_info_fixture(spdx_version="SPDX-2.3"), + "SPDX2.3", + "provided SPDX version SPDX2.3 does not match the document's SPDX version SPDX-2.3", + ), + ( + creation_info_fixture(spdx_version="SPDX2.3"), + "SPDX-2.3", + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3', + ), + ( + creation_info_fixture(spdx_version="SPDX2.3"), + None, + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3', + ), + ( + creation_info_fixture(spdx_version="SPDX2.3"), + "SPDX2.3", + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s spdx_version is: SPDX2.3', + ), + ( + creation_info_fixture(spdx_version="SPDX-2.1"), + "SPDX-2.1", + 'only SPDX versions "SPDX-2.2" and "SPDX-2.3" are supported, but the document\'s ' + "spdx_version is: SPDX-2.1", + ), + ], +) def test_spdx_version_handling(creation_info: CreationInfo, version_input: str, expected_message: Optional[str]): document: Document = document_fixture(creation_info=creation_info) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document, version_input) @@ -52,16 +74,25 @@ def test_spdx_version_handling(creation_info: CreationInfo, version_input: str, if expected_message: expected.append(ValidationMessage(expected_message, context)) - expected.append(ValidationMessage("There are issues concerning the SPDX version of the document. " - "As subsequent validation relies on the correct version, " - "the validation process has been cancelled.", context)) + expected.append( + ValidationMessage( + "There are issues concerning the SPDX version of the document. " + "As subsequent validation relies on the correct version, " + "the validation process has been cancelled.", + context, + ) + ) assert validation_messages == expected -@pytest.mark.parametrize("relationships", - [[Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-File")], - [Relationship("SPDXRef-File", RelationshipType.DESCRIBED_BY, "SPDXRef-DOCUMENT")]]) +@pytest.mark.parametrize( + "relationships", + [ + [Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, "SPDXRef-File")], + [Relationship("SPDXRef-File", RelationshipType.DESCRIBED_BY, "SPDXRef-DOCUMENT")], + ], +) def test_document_describes_at_least_one_element(relationships): document = document_fixture(relationships=relationships) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) @@ -71,26 +102,38 @@ def test_document_describes_at_least_one_element(relationships): def test_document_does_not_describe_an_element(): document = document_fixture( - relationships=[Relationship("SPDXRef-Package", RelationshipType.DESCRIBES, "SPDXRef-File")]) + relationships=[Relationship("SPDXRef-Package", RelationshipType.DESCRIBES, "SPDXRef-File")] + ) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) - assert validation_messages == [ValidationMessage( - 'there must be at least one relationship "SPDXRef-DOCUMENT DESCRIBES ..." or "... DESCRIBED_BY SPDXRef-DOCUMENT"', - ValidationContext(spdx_id="SPDXRef-DOCUMENT", element_type=SpdxElementType.DOCUMENT) - )] + assert validation_messages == [ + ValidationMessage( + 'there must be at least one relationship "SPDXRef-DOCUMENT DESCRIBES ..." or "... DESCRIBED_BY ' + 'SPDXRef-DOCUMENT"', + ValidationContext(spdx_id="SPDXRef-DOCUMENT", element_type=SpdxElementType.DOCUMENT), + ) + ] def test_duplicated_spdx_ids(): document = document_fixture( - files=[file_fixture(spdx_id="SPDXRef-File"), file_fixture(spdx_id="SPDXRef-2"), - file_fixture(spdx_id="SPDXRef-3")], + files=[ + file_fixture(spdx_id="SPDXRef-File"), + file_fixture(spdx_id="SPDXRef-2"), + file_fixture(spdx_id="SPDXRef-3"), + ], packages=[package_fixture(spdx_id="SPDXRef-2"), package_fixture(spdx_id="SPDXRef-DOCUMENT")], - snippets=[snippet_fixture(spdx_id="SPDXRef-2"), snippet_fixture(spdx_id="SPDXRef-3")]) + snippets=[snippet_fixture(spdx_id="SPDXRef-2"), snippet_fixture(spdx_id="SPDXRef-3")], + ) context = ValidationContext(spdx_id=document.creation_info.spdx_id, element_type=SpdxElementType.DOCUMENT) validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) - assert validation_messages == [ValidationMessage( - "every spdx_id must be unique within the document, but found the following duplicates: ['SPDXRef-2', 'SPDXRef-3', 'SPDXRef-DOCUMENT']", - context)] + assert validation_messages == [ + ValidationMessage( + "every spdx_id must be unique within the document, but found the following duplicates: ['SPDXRef-2', " + "'SPDXRef-3', 'SPDXRef-DOCUMENT']", + context, + ) + ] diff --git a/tests/spdx/validation/test_external_document_ref_validator.py b/tests/spdx/validation/test_external_document_ref_validator.py index a81bc7b9d..4ad65edf4 100644 --- a/tests/spdx/validation/test_external_document_ref_validator.py +++ b/tests/spdx/validation/test_external_document_ref_validator.py @@ -18,7 +18,8 @@ def test_valid_external_document_ref(): external_document_ref = external_document_ref_fixture() - validation_messages: List[ValidationMessage] = validate_external_document_ref(external_document_ref, "parent_id", - "SPDX-2.3") + validation_messages: List[ValidationMessage] = validate_external_document_ref( + external_document_ref, "parent_id", "SPDX-2.3" + ) assert validation_messages == [] diff --git a/tests/spdx/validation/test_external_package_ref_validator.py b/tests/spdx/validation/test_external_package_ref_validator.py index e9e50f7f5..b3dfa48d8 100644 --- a/tests/spdx/validation/test_external_package_ref_validator.py +++ b/tests/spdx/validation/test_external_package_ref_validator.py @@ -14,169 +14,297 @@ import pytest from spdx.model.package import ExternalPackageRef, ExternalPackageRefCategory -from spdx.validation.external_package_ref_validator import validate_external_package_ref, CPE22TYPE_REGEX, \ - CPE23TYPE_REGEX, MAVEN_CENTRAL_REGEX, NPM_REGEX, NUGET_REGEX, BOWER_REGEX, PURL_REGEX, SWH_REGEX, GITOID_REGEX -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType - - -@pytest.mark.parametrize("category, reference_type, locator", - [(ExternalPackageRefCategory.SECURITY, "cpe22Type", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts"), - (ExternalPackageRefCategory.SECURITY, "cpe23Type", - "cpe:2.3:o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*"), - (ExternalPackageRefCategory.SECURITY, "advisory", - "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"), - (ExternalPackageRefCategory.SECURITY, "fix", - "https://github.com/indutny/elliptic/commit/441b7428"), - (ExternalPackageRefCategory.SECURITY, "url", - "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/secp256k1_twist_attacks.md"), - (ExternalPackageRefCategory.SECURITY, "swid", "swid:2df9de35-0aff-4a86-ace6-f7dddd1ade4c"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "maven-central", - "org.apache.tomcat:tomcat:9.0.0.M4"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "npm", "http-server@0.3.0"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "nuget", "Microsoft.AspNet.MVC/5.0.0"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "bower", "modernizr#2.6.2"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:docker/debian@sha256:2f04d3d33b6027bb74ecc81397abe780649ec89f1a2af18d7022737d0482cefe"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:gem/jruby-launcher@1.1.2?platform=java"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:gem/ruby-advisory-db-check@0.12.4"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:golang/google.golang.org/genproto#googleapis/api/annotations"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?repository_url=repo.spring.io%2Frelease"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:npm/%40angular/animation@12.3.1"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:nuget/EnterpriseLibrary.Common@6.0.1304"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", - "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25"), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2"), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:1:dir:d198bc9d7a6bcf6db04f476d29314f157507d505"), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:1:rev:309cf2674ee7a0749978cf8265ab91a60aea0f7d"), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:1:rel:22ece559cc7cc2364edc5e5593d63ae8bd229f9f"), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:1:snp:c7c108084bc0bf3d81436bf980b46e98bd338453"), - (ExternalPackageRefCategory.PERSISTENT_ID, "gitoid", - "gitoid:blob:sha1:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"), - (ExternalPackageRefCategory.PERSISTENT_ID, "gitoid", - "gitoid:blob:sha256:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c"), - (ExternalPackageRefCategory.OTHER, "some idstring", "#//string-withOUT!Spaces\\?") - ]) +from spdx.validation.external_package_ref_validator import ( + BOWER_REGEX, + CPE22TYPE_REGEX, + CPE23TYPE_REGEX, + GITOID_REGEX, + MAVEN_CENTRAL_REGEX, + NPM_REGEX, + NUGET_REGEX, + PURL_REGEX, + SWH_REGEX, + validate_external_package_ref, +) +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage + + +@pytest.mark.parametrize( + "category, reference_type, locator", + [ + (ExternalPackageRefCategory.SECURITY, "cpe22Type", "cpe:/o:canonical:ubuntu_linux:10.04:-:lts"), + (ExternalPackageRefCategory.SECURITY, "cpe23Type", "cpe:2.3:o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*"), + (ExternalPackageRefCategory.SECURITY, "advisory", "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"), + (ExternalPackageRefCategory.SECURITY, "fix", "https://github.com/indutny/elliptic/commit/441b7428"), + ( + ExternalPackageRefCategory.SECURITY, + "url", + "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/" + "secp256k1_twist_attacks.md", + ), + (ExternalPackageRefCategory.SECURITY, "swid", "swid:2df9de35-0aff-4a86-ace6-f7dddd1ade4c"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "maven-central", "org.apache.tomcat:tomcat:9.0.0.M4"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "npm", "http-server@0.3.0"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "nuget", "Microsoft.AspNet.MVC/5.0.0"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "bower", "modernizr#2.6.2"), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:docker/debian@sha256:2f04d3d33b6027bb74ecc81397abe780649ec89f1a2af18d7022737d0482cefe", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c", + ), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie"), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io", + ), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:gem/jruby-launcher@1.1.2?platform=java"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:gem/ruby-advisory-db-check@0.12.4"), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:golang/google.golang.org/genproto#googleapis/api/annotations", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?repository_url=repo.spring.io%2Frelease", + ), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:npm/%40angular/animation@12.3.1"), + (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:nuget/EnterpriseLibrary.Common@6.0.1304"), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25", + ), + (ExternalPackageRefCategory.PERSISTENT_ID, "swh", "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2"), + (ExternalPackageRefCategory.PERSISTENT_ID, "swh", "swh:1:dir:d198bc9d7a6bcf6db04f476d29314f157507d505"), + (ExternalPackageRefCategory.PERSISTENT_ID, "swh", "swh:1:rev:309cf2674ee7a0749978cf8265ab91a60aea0f7d"), + (ExternalPackageRefCategory.PERSISTENT_ID, "swh", "swh:1:rel:22ece559cc7cc2364edc5e5593d63ae8bd229f9f"), + (ExternalPackageRefCategory.PERSISTENT_ID, "swh", "swh:1:snp:c7c108084bc0bf3d81436bf980b46e98bd338453"), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "gitoid", + "gitoid:blob:sha1:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", + ), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "gitoid", + "gitoid:blob:sha256:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c", + ), + (ExternalPackageRefCategory.OTHER, "some idstring", "#//string-withOUT!Spaces\\?"), + ], +) def test_valid_external_package_ref(category, reference_type, locator): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, "parent_id", - "SPDX-2.3") + validation_messages: List[ValidationMessage] = validate_external_package_ref( + external_package_ref, "parent_id", "SPDX-2.3" + ) assert validation_messages == [] -@pytest.mark.parametrize("category, reference_type, locator, expected_message", - [( - ExternalPackageRefCategory.SECURITY, "cpe22Typo", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category SECURITY must be one of ['cpe22Type', 'cpe23Type', 'advisory', 'fix', 'url', 'swid'], but is: cpe22Typo"), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "nugat", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category PACKAGE_MANAGER must be one of ['maven-central', 'npm', 'nuget', 'bower', 'purl'], but is: nugat"), - (ExternalPackageRefCategory.PERSISTENT_ID, "git-oid", - "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", - "externalPackageRef type in category PERSISTENT_ID must be one of ['swh', 'gitoid'], but is: git-oid") - ]) +@pytest.mark.parametrize( + "category, reference_type, locator, expected_message", + [ + ( + ExternalPackageRefCategory.SECURITY, + "cpe22Typo", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category SECURITY must be one of ['cpe22Type', 'cpe23Type', 'advisory', 'fix'" + ", 'url', 'swid'], but is: cpe22Typo", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "nugat", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category PACKAGE_MANAGER must be one of ['maven-central', 'npm', 'nuget'," + " 'bower', 'purl'], but is: nugat", + ), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "git-oid", + "cpe:/o:canonical:ubuntu_linux:10.04:-:lts", + "externalPackageRef type in category PERSISTENT_ID must be one of ['swh', 'gitoid'], but is: git-oid", + ), + ], +) def test_invalid_external_package_ref_types(category, reference_type, locator, expected_message): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") parent_id = "SPDXRef-Package" - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, - "SPDX-2.3") + validation_messages: List[ValidationMessage] = validate_external_package_ref( + external_package_ref, parent_id, "SPDX-2.3" + ) - expected = ValidationMessage(expected_message, - ValidationContext(parent_id=parent_id, - element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, - full_element=external_package_ref)) + expected = ValidationMessage( + expected_message, + ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, full_element=external_package_ref + ), + ) assert validation_messages == [expected] -@pytest.mark.parametrize("category, reference_type, locator, expected_message", - [(ExternalPackageRefCategory.SECURITY, "cpe22Type", "cpe:o:canonical:ubuntu_linux:10.04:-:lts", - f'externalPackageRef locator of type "cpe22Type" must conform with the regex {CPE22TYPE_REGEX}, but is: cpe:o:canonical:ubuntu_linux:10.04:-:lts'), - (ExternalPackageRefCategory.SECURITY, "cpe23Type", - "cpe:2.3:/o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*", - f'externalPackageRef locator of type "cpe23Type" must conform with the regex {CPE23TYPE_REGEX}, but is: cpe:2.3:/o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*'), - (ExternalPackageRefCategory.SECURITY, "advisory", "http://locatorurl", - f'externalPackageRef locator of type "advisory" must be a valid URL, but is: http://locatorurl'), - (ExternalPackageRefCategory.SECURITY, "fix", "http://fixurl", - f'externalPackageRef locator of type "fix" must be a valid URL, but is: http://fixurl'), - (ExternalPackageRefCategory.SECURITY, "url", "http://url", - f'externalPackageRef locator of type "url" must be a valid URL, but is: http://url'), - (ExternalPackageRefCategory.SECURITY, "swid", "2df9de35-0aff-4a86-ace6-f7dddd1ade4c", - f'externalPackageRef locator of type "swid" must be a valid URI with scheme swid, but is: 2df9de35-0aff-4a86-ace6-f7dddd1ade4c'), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "maven-central", - "org.apache.tomcat:tomcat:tomcat:9.0.0.M4", - f'externalPackageRef locator of type "maven-central" must conform with the regex {MAVEN_CENTRAL_REGEX}, but is: org.apache.tomcat:tomcat:tomcat:9.0.0.M4'), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "npm", "http-server:0.3.0", - f'externalPackageRef locator of type "npm" must conform with the regex {NPM_REGEX}, but is: http-server:0.3.0'), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "nuget", "Microsoft.AspNet.MVC@5.0.0", - f'externalPackageRef locator of type "nuget" must conform with the regex {NUGET_REGEX}, but is: Microsoft.AspNet.MVC@5.0.0'), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "bower", "modernizr:2.6.2", - f'externalPackageRef locator of type "bower" must conform with the regex {BOWER_REGEX}, but is: modernizr:2.6.2'), - (ExternalPackageRefCategory.PACKAGE_MANAGER, "purl", "pkg:npm@12.3.1", - f'externalPackageRef locator of type "purl" must conform with the regex {PURL_REGEX}, but is: pkg:npm@12.3.1'), - (ExternalPackageRefCategory.PERSISTENT_ID, "swh", - "swh:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2", - f'externalPackageRef locator of type "swh" must conform with the regex {SWH_REGEX}, but is: swh:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2'), - (ExternalPackageRefCategory.PERSISTENT_ID, "gitoid", - "gitoid:blob:sha1:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c", - f'externalPackageRef locator of type "gitoid" must conform with the regex {GITOID_REGEX}, but is: gitoid:blob:sha1:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c'), - (ExternalPackageRefCategory.PERSISTENT_ID, "gitoid", - "gitoid:blob:sha256:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", - f'externalPackageRef locator of type "gitoid" must conform with the regex {GITOID_REGEX}, but is: gitoid:blob:sha256:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64'), - (ExternalPackageRefCategory.OTHER, "id string", "locator string", - "externalPackageRef locator in category OTHER must contain no spaces, but is: locator string"), - ]) +@pytest.mark.parametrize( + "category, reference_type, locator, expected_message", + [ + ( + ExternalPackageRefCategory.SECURITY, + "cpe22Type", + "cpe:o:canonical:ubuntu_linux:10.04:-:lts", + f'externalPackageRef locator of type "cpe22Type" must conform with the regex {CPE22TYPE_REGEX}, but is: ' + f"cpe:o:canonical:ubuntu_linux:10.04:-:lts", + ), + ( + ExternalPackageRefCategory.SECURITY, + "cpe23Type", + "cpe:2.3:/o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*", + f'externalPackageRef locator of type "cpe23Type" must conform with the regex {CPE23TYPE_REGEX}, but is: ' + f"cpe:2.3:/o:canonical:ubuntu_linux:10.04:-:lts:*:*:*:*:*", + ), + ( + ExternalPackageRefCategory.SECURITY, + "advisory", + "http://locatorurl", + 'externalPackageRef locator of type "advisory" must be a valid URL, but is: http://locatorurl', + ), + ( + ExternalPackageRefCategory.SECURITY, + "fix", + "http://fixurl", + 'externalPackageRef locator of type "fix" must be a valid URL, but is: http://fixurl', + ), + ( + ExternalPackageRefCategory.SECURITY, + "url", + "http://url", + 'externalPackageRef locator of type "url" must be a valid URL, but is: http://url', + ), + ( + ExternalPackageRefCategory.SECURITY, + "swid", + "2df9de35-0aff-4a86-ace6-f7dddd1ade4c", + 'externalPackageRef locator of type "swid" must be a valid URI with scheme swid, but is: ' + "2df9de35-0aff-4a86-ace6-f7dddd1ade4c", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "maven-central", + "org.apache.tomcat:tomcat:tomcat:9.0.0.M4", + f'externalPackageRef locator of type "maven-central" must conform with the regex {MAVEN_CENTRAL_REGEX}, ' + f"but is: org.apache.tomcat:tomcat:tomcat:9.0.0.M4", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "npm", + "http-server:0.3.0", + f'externalPackageRef locator of type "npm" must conform with the regex {NPM_REGEX}, ' + f"but is: http-server:0.3.0", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "nuget", + "Microsoft.AspNet.MVC@5.0.0", + f'externalPackageRef locator of type "nuget" must conform with the regex {NUGET_REGEX}, ' + f"but is: Microsoft.AspNet.MVC@5.0.0", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "bower", + "modernizr:2.6.2", + f'externalPackageRef locator of type "bower" must conform with the regex {BOWER_REGEX}, ' + f"but is: modernizr:2.6.2", + ), + ( + ExternalPackageRefCategory.PACKAGE_MANAGER, + "purl", + "pkg:npm@12.3.1", + f'externalPackageRef locator of type "purl" must conform with the regex {PURL_REGEX}, ' + f"but is: pkg:npm@12.3.1", + ), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "swh", + "swh:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2", + f'externalPackageRef locator of type "swh" must conform with the regex {SWH_REGEX}, ' + f"but is: swh:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2", + ), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "gitoid", + "gitoid:blob:sha1:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c", + f'externalPackageRef locator of type "gitoid" must conform with the regex {GITOID_REGEX}, ' + f"but is: gitoid:blob:sha1:3557f7eb43c621c71483743d4b37059bb80933e7f71277c0c3b3846159d1f61c", + ), + ( + ExternalPackageRefCategory.PERSISTENT_ID, + "gitoid", + "gitoid:blob:sha256:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", + f'externalPackageRef locator of type "gitoid" must conform with the regex {GITOID_REGEX},' + f" but is: gitoid:blob:sha256:261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64", + ), + ( + ExternalPackageRefCategory.OTHER, + "id string", + "locator string", + "externalPackageRef locator in category OTHER must contain no spaces, but is: locator string", + ), + ], +) def test_invalid_external_package_ref_locators(category, reference_type, locator, expected_message): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") parent_id = "SPDXRef-Package" - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, - "SPDX-2.3") + validation_messages: List[ValidationMessage] = validate_external_package_ref( + external_package_ref, parent_id, "SPDX-2.3" + ) - expected = ValidationMessage(expected_message, - ValidationContext(parent_id=parent_id, - element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, - full_element=external_package_ref)) + expected = ValidationMessage( + expected_message, + ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, full_element=external_package_ref + ), + ) assert validation_messages == [expected] -@pytest.mark.parametrize("category, reference_type, locator", - [(ExternalPackageRefCategory.SECURITY, "advisory", - "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"), - (ExternalPackageRefCategory.SECURITY, "fix", - "https://github.com/indutny/elliptic/commit/441b7428"), - (ExternalPackageRefCategory.SECURITY, "url", - "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/secp256k1_twist_attacks.md"), - (ExternalPackageRefCategory.SECURITY, "swid", "swid:2df9de35-0aff-4a86-ace6-f7dddd1ade4c") - ]) +@pytest.mark.parametrize( + "category, reference_type, locator", + [ + (ExternalPackageRefCategory.SECURITY, "advisory", "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"), + (ExternalPackageRefCategory.SECURITY, "fix", "https://github.com/indutny/elliptic/commit/441b7428"), + ( + ExternalPackageRefCategory.SECURITY, + "url", + "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/" + "secp256k1_twist_attacks.md", + ), + (ExternalPackageRefCategory.SECURITY, "swid", "swid:2df9de35-0aff-4a86-ace6-f7dddd1ade4c"), + ], +) def test_v2_3only_external_package_ref_types(category, reference_type, locator): external_package_ref = ExternalPackageRef(category, reference_type, locator, "externalPackageRef comment") parent_id = "SPDXRef-Package" - validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id, - "SPDX-2.2") + validation_messages: List[ValidationMessage] = validate_external_package_ref( + external_package_ref, parent_id, "SPDX-2.2" + ) - expected = ValidationMessage(f'externalPackageRef type "{reference_type}" is not supported in SPDX-2.2', - ValidationContext(parent_id=parent_id, - element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, - full_element=external_package_ref)) + expected = ValidationMessage( + f'externalPackageRef type "{reference_type}" is not supported in SPDX-2.2', + ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_PACKAGE_REF, full_element=external_package_ref + ), + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_extracted_licensing_info_validator.py b/tests/spdx/validation/test_extracted_licensing_info_validator.py index a85068f59..ce82f0626 100644 --- a/tests/spdx/validation/test_extracted_licensing_info_validator.py +++ b/tests/spdx/validation/test_extracted_licensing_info_validator.py @@ -14,7 +14,7 @@ import pytest from spdx.validation.extracted_licensing_info_validator import validate_extracted_licensing_info -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import extracted_licensing_info_fixture @@ -26,17 +26,27 @@ def test_valid_extracted_licensing_info(): # TODO: tests for licenses not on the SPDX License list (i.e. they must provide id, name and cross-references) -@pytest.mark.parametrize("extracted_licensing_info, expected_message", - [(extracted_licensing_info_fixture(extracted_text=None), - 'extracted_text must be provided if there is a license_id assigned'), - (extracted_licensing_info_fixture(cross_references=["invalid_url"]), - 'cross_reference must be a valid URL, but is: invalid_url') - ]) +@pytest.mark.parametrize( + "extracted_licensing_info, expected_message", + [ + ( + extracted_licensing_info_fixture(extracted_text=None), + "extracted_text must be provided if there is a license_id assigned", + ), + ( + extracted_licensing_info_fixture(cross_references=["invalid_url"]), + "cross_reference must be a valid URL, but is: invalid_url", + ), + ], +) def test_invalid_extracted_licensing_info(extracted_licensing_info, expected_message): validation_messages: List[ValidationMessage] = validate_extracted_licensing_info(extracted_licensing_info) - expected = ValidationMessage(expected_message, - ValidationContext(element_type=SpdxElementType.EXTRACTED_LICENSING_INFO, - full_element=extracted_licensing_info)) + expected = ValidationMessage( + expected_message, + ValidationContext( + element_type=SpdxElementType.EXTRACTED_LICENSING_INFO, full_element=extracted_licensing_info + ), + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_file_validator.py b/tests/spdx/validation/test_file_validator.py index b1fb6b41d..e215d56c9 100644 --- a/tests/spdx/validation/test_file_validator.py +++ b/tests/spdx/validation/test_file_validator.py @@ -15,9 +15,9 @@ import pytest from spdx.model.checksum import Checksum, ChecksumAlgorithm -from spdx.validation.file_validator import validate_file_within_document, validate_file -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -from tests.spdx.fixtures import file_fixture, document_fixture +from spdx.validation.file_validator import validate_file, validate_file_within_document +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage +from tests.spdx.fixtures import document_fixture, file_fixture def test_valid_file(): @@ -27,23 +27,35 @@ def test_valid_file(): assert validation_messages == [] -@pytest.mark.parametrize("file_input, spdx_id, expected_message", - [(file_fixture(name="/invalid/file/name"), file_fixture().spdx_id, - f'file name must not be an absolute path starting with "/", but is: /invalid/file/name'), - ( - file_fixture(checksums=[Checksum(ChecksumAlgorithm.MD2, "d4c41ce30a517d6ce9d79c8c17bb4b66")]), - file_fixture().spdx_id, - f'checksums must contain a SHA1 algorithm checksum, but only contains: []') - ]) +@pytest.mark.parametrize( + "file_input, spdx_id, expected_message", + [ + ( + file_fixture(name="/invalid/file/name"), + file_fixture().spdx_id, + 'file name must not be an absolute path starting with "/", but is: /invalid/file/name', + ), + ( + file_fixture(checksums=[Checksum(ChecksumAlgorithm.MD2, "d4c41ce30a517d6ce9d79c8c17bb4b66")]), + file_fixture().spdx_id, + "checksums must contain a SHA1 algorithm checksum, but only contains: []", + ), + ], +) def test_invalid_file(file_input, spdx_id, expected_message): - validation_messages: List[ValidationMessage] = validate_file_within_document(file_input, "SPDX-2.3", - document_fixture()) - - expected = ValidationMessage(expected_message, - ValidationContext(spdx_id=spdx_id, - parent_id=document_fixture().creation_info.spdx_id, - element_type=SpdxElementType.FILE, - full_element=file_input)) + validation_messages: List[ValidationMessage] = validate_file_within_document( + file_input, "SPDX-2.3", document_fixture() + ) + + expected = ValidationMessage( + expected_message, + ValidationContext( + spdx_id=spdx_id, + parent_id=document_fixture().creation_info.spdx_id, + element_type=SpdxElementType.FILE, + full_element=file_input, + ), + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_license_expression_validator.py b/tests/spdx/validation/test_license_expression_validator.py index 2bcdef5f1..4a81ec525 100644 --- a/tests/spdx/validation/test_license_expression_validator.py +++ b/tests/spdx/validation/test_license_expression_validator.py @@ -13,27 +13,32 @@ from unittest import TestCase import pytest -from license_expression import get_spdx_licensing, LicenseExpression +from license_expression import LicenseExpression, get_spdx_licensing from spdx.model.document import Document from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.validation.license_expression_validator import validate_license_expression, validate_license_expressions -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import document_fixture, extracted_licensing_info_fixture - FIXTURE_LICENSE_ID = extracted_licensing_info_fixture().license_id -@pytest.mark.parametrize("expression_string", - ["MIT", FIXTURE_LICENSE_ID, - f"GPL-2.0-only with GPL-CC-1.0 and {FIXTURE_LICENSE_ID} with 389-exception or Beerware"]) +@pytest.mark.parametrize( + "expression_string", + [ + "MIT", + FIXTURE_LICENSE_ID, + f"GPL-2.0-only with GPL-CC-1.0 and {FIXTURE_LICENSE_ID} with 389-exception or Beerware", + ], +) def test_valid_license_expression(expression_string): document: Document = document_fixture() license_expression: LicenseExpression = get_spdx_licensing().parse(expression_string) - validation_messages: List[ValidationMessage] = validate_license_expression(license_expression, document, - parent_id="SPDXRef-File") + validation_messages: List[ValidationMessage] = validate_license_expression( + license_expression, document, parent_id="SPDXRef-File" + ) assert validation_messages == [] @@ -41,62 +46,96 @@ def test_valid_license_expression(expression_string): @pytest.mark.parametrize("expression", [SpdxNone(), SpdxNoAssertion()]) def test_none_and_no_assertion(expression): document: Document = document_fixture() - validation_messages: List[ValidationMessage] = validate_license_expression(expression, document, - parent_id="SPDXRef-File") + validation_messages: List[ValidationMessage] = validate_license_expression( + expression, document, parent_id="SPDXRef-File" + ) assert validation_messages == [] -@pytest.mark.parametrize("expression_list", - [[SpdxNone()], [SpdxNoAssertion()], - [get_spdx_licensing().parse("MIT and GPL-3.0-only"), - get_spdx_licensing().parse(FIXTURE_LICENSE_ID)], - [SpdxNone(), get_spdx_licensing().parse("MIT"), SpdxNoAssertion()] - ]) +@pytest.mark.parametrize( + "expression_list", + [ + [SpdxNone()], + [SpdxNoAssertion()], + [get_spdx_licensing().parse("MIT and GPL-3.0-only"), get_spdx_licensing().parse(FIXTURE_LICENSE_ID)], + [SpdxNone(), get_spdx_licensing().parse("MIT"), SpdxNoAssertion()], + ], +) def test_valid_license_expressions(expression_list): document: Document = document_fixture() - validation_messages: List[ValidationMessage] = validate_license_expressions(expression_list, document, - parent_id="SPDXRef-File") + validation_messages: List[ValidationMessage] = validate_license_expressions( + expression_list, document, parent_id="SPDXRef-File" + ) assert validation_messages == [] -@pytest.mark.parametrize("expression_string, unknown_symbols", - [(f"{FIXTURE_LICENSE_ID} or LicenseRef-22", ["LicenseRef-22"]), - ("nope with 389-exception and _.- or LicenseRef-10", ["nope", "_.-", "LicenseRef-10"]) - ]) +@pytest.mark.parametrize( + "expression_string, unknown_symbols", + [ + (f"{FIXTURE_LICENSE_ID} or LicenseRef-22", ["LicenseRef-22"]), + ("nope with 389-exception and _.- or LicenseRef-10", ["nope", "_.-", "LicenseRef-10"]), + ], +) def test_invalid_license_expression_with_unknown_symbols(expression_string, unknown_symbols): document: Document = document_fixture() license_expression: LicenseExpression = get_spdx_licensing().parse(expression_string) parent_id = "SPDXRef-File" - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, - full_element=license_expression) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, full_element=license_expression + ) validation_messages: List[ValidationMessage] = validate_license_expression(license_expression, document, parent_id) - expected_messages = [ValidationMessage( - f"Unrecognized license reference: {symbol}. license_expression must only use IDs from the license list or extracted licensing info, but is: {license_expression}", - context - ) for symbol in unknown_symbols] + expected_messages = [ + ValidationMessage( + f"Unrecognized license reference: {symbol}. license_expression must only use IDs from the license list or " + f"extracted licensing info, but is: {license_expression}", + context, + ) + for symbol in unknown_symbols + ] TestCase().assertCountEqual(validation_messages, expected_messages) -@pytest.mark.parametrize("expression_string, expected_message", - [("MIT with MIT", - 'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: "MIT" at position: 9. for license_expression: MIT WITH MIT'), - (f"GPL-2.0-or-later and {FIXTURE_LICENSE_ID} with {FIXTURE_LICENSE_ID}", - f'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: "{FIXTURE_LICENSE_ID}" at position: 39. for license_expression: GPL-2.0-or-later AND {FIXTURE_LICENSE_ID} WITH {FIXTURE_LICENSE_ID}'), - (f"GPL-2.0-or-later with MIT and {FIXTURE_LICENSE_ID} with GPL-2.0-or-later", - f'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: "MIT" at position: 22. for license_expression: GPL-2.0-or-later WITH MIT AND {FIXTURE_LICENSE_ID} WITH GPL-2.0-or-later'), - ("389-exception with 389-exception", - 'A license exception symbol can only be used as an exception in a "WITH exception" statement. for token: "389-exception". for license_expression: 389-exception WITH 389-exception'), - ("389-exception with MIT", - 'A license exception symbol can only be used as an exception in a "WITH exception" statement. for token: "389-exception". for license_expression: 389-exception WITH MIT'), - ]) +@pytest.mark.parametrize( + "expression_string, expected_message", + [ + ( + "MIT with MIT", + 'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: "MIT" at ' + "position: 9. for license_expression: MIT WITH MIT", + ), + ( + f"GPL-2.0-or-later and {FIXTURE_LICENSE_ID} with {FIXTURE_LICENSE_ID}", + f'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: ' + f'"{FIXTURE_LICENSE_ID}" at position: 39. for license_expression: GPL-2.0-or-later AND ' + f"{FIXTURE_LICENSE_ID} WITH {FIXTURE_LICENSE_ID}", + ), + ( + f"GPL-2.0-or-later with MIT and {FIXTURE_LICENSE_ID} with GPL-2.0-or-later", + f'A plain license symbol cannot be used as an exception in a "WITH symbol" statement. for token: "MIT" at ' + f"position: 22. for license_expression: GPL-2.0-or-later WITH MIT AND {FIXTURE_LICENSE_ID} " + f"WITH GPL-2.0-or-later", + ), + ( + "389-exception with 389-exception", + 'A license exception symbol can only be used as an exception in a "WITH exception" statement. for token: ' + '"389-exception". for license_expression: 389-exception WITH 389-exception', + ), + ( + "389-exception with MIT", + 'A license exception symbol can only be used as an exception in a "WITH exception" statement. for token: ' + '"389-exception". for license_expression: 389-exception WITH MIT', + ), + ], +) def test_invalid_license_expression_with_invalid_exceptions(expression_string, expected_message): document: Document = document_fixture() license_expression: LicenseExpression = get_spdx_licensing().parse(expression_string) parent_id = "SPDXRef-File" - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, - full_element=license_expression) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.LICENSE_EXPRESSION, full_element=license_expression + ) validation_messages: List[ValidationMessage] = validate_license_expression(license_expression, document, parent_id) expected_messages = [ValidationMessage(expected_message, context)] diff --git a/tests/spdx/validation/test_package_validator.py b/tests/spdx/validation/test_package_validator.py index fe054201a..24ecd6160 100644 --- a/tests/spdx/validation/test_package_validator.py +++ b/tests/spdx/validation/test_package_validator.py @@ -18,69 +18,100 @@ from spdx.model.relationship import Relationship, RelationshipType from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone -from spdx.validation.package_validator import validate_package_within_document, validate_package -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType -from tests.spdx.fixtures import package_fixture, package_verification_code_fixture, document_fixture, file_fixture +from spdx.validation.package_validator import validate_package, validate_package_within_document +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage +from tests.spdx.fixtures import document_fixture, file_fixture, package_fixture, package_verification_code_fixture def test_valid_package(): package = package_fixture() - validation_messages: List[ValidationMessage] = validate_package_within_document(package, "SPDX-2.3", - document_fixture()) + validation_messages: List[ValidationMessage] = validate_package_within_document( + package, "SPDX-2.3", document_fixture() + ) assert validation_messages == [] -@pytest.mark.parametrize("package_input, expected_message", - [(package_fixture(files_analyzed=False, verification_code=package_verification_code_fixture(), - license_info_from_files=[]), - f'verification_code must be None if files_analyzed is False, but is: {package_verification_code_fixture()}'), - (package_fixture(files_analyzed=False, license_info_from_files=[SpdxNone()], - verification_code=None), - 'license_info_from_files must be None if files_analyzed is False, but is: [NONE]'), - (package_fixture(files_analyzed=False, license_info_from_files=[SpdxNoAssertion()], - verification_code=None), - 'license_info_from_files must be None if files_analyzed is False, but is: [NOASSERTION]'), - (package_fixture(files_analyzed=False, - license_info_from_files=[Licensing().parse("some_license")], - verification_code=None), - "license_info_from_files must be None if files_analyzed is False, but is: [LicenseSymbol('some_license', " - "is_exception=False)]") - ]) +@pytest.mark.parametrize( + "package_input, expected_message", + [ + ( + package_fixture( + files_analyzed=False, verification_code=package_verification_code_fixture(), license_info_from_files=[] + ), + f"verification_code must be None if files_analyzed is False, but is: " + f"{package_verification_code_fixture()}", + ), + ( + package_fixture(files_analyzed=False, license_info_from_files=[SpdxNone()], verification_code=None), + "license_info_from_files must be None if files_analyzed is False, but is: [NONE]", + ), + ( + package_fixture(files_analyzed=False, license_info_from_files=[SpdxNoAssertion()], verification_code=None), + "license_info_from_files must be None if files_analyzed is False, but is: [NOASSERTION]", + ), + ( + package_fixture( + files_analyzed=False, + license_info_from_files=[Licensing().parse("some_license")], + verification_code=None, + ), + "license_info_from_files must be None if files_analyzed is False, but is: [LicenseSymbol('some_license', " + "is_exception=False)]", + ), + ], +) def test_invalid_package(package_input, expected_message): - validation_messages: List[ValidationMessage] = validate_package_within_document(package_input, "SPDX-2.3", - document_fixture(relationships=[])) - - expected = ValidationMessage(expected_message, - ValidationContext(spdx_id=package_input.spdx_id, parent_id="SPDXRef-DOCUMENT", - element_type=SpdxElementType.PACKAGE, - full_element=package_input)) + validation_messages: List[ValidationMessage] = validate_package_within_document( + package_input, "SPDX-2.3", document_fixture(relationships=[]) + ) + + expected = ValidationMessage( + expected_message, + ValidationContext( + spdx_id=package_input.spdx_id, + parent_id="SPDXRef-DOCUMENT", + element_type=SpdxElementType.PACKAGE, + full_element=package_input, + ), + ) assert validation_messages == [expected] -@pytest.mark.parametrize("relationships", - [[Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File1")], - [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, - "DocumentRef-external:SPDXRef-File")], - [Relationship("SPDXRef-File2", RelationshipType.CONTAINED_BY, "SPDXRef-Package")], - [Relationship("DocumentRef-external:SPDXRef-File", RelationshipType.CONTAINED_BY, - "SPDXRef-Package")], - [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File2"), - Relationship("SPDXRef-File1", RelationshipType.CONTAINED_BY, "SPDXRef-Package")]]) +@pytest.mark.parametrize( + "relationships", + [ + [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File1")], + [Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "DocumentRef-external:SPDXRef-File")], + [Relationship("SPDXRef-File2", RelationshipType.CONTAINED_BY, "SPDXRef-Package")], + [Relationship("DocumentRef-external:SPDXRef-File", RelationshipType.CONTAINED_BY, "SPDXRef-Package")], + [ + Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File2"), + Relationship("SPDXRef-File1", RelationshipType.CONTAINED_BY, "SPDXRef-Package"), + ], + ], +) def test_invalid_package_with_contains(relationships): - document = document_fixture(relationships=relationships, - files=[file_fixture(spdx_id="SPDXRef-File1"), file_fixture(spdx_id="SPDXRef-File2")]) + document = document_fixture( + relationships=relationships, + files=[file_fixture(spdx_id="SPDXRef-File1"), file_fixture(spdx_id="SPDXRef-File2")], + ) package = package_fixture(files_analyzed=False, verification_code=None, license_info_from_files=[]) - context = ValidationContext(spdx_id=package.spdx_id, parent_id=document.creation_info.spdx_id, - element_type=SpdxElementType.PACKAGE, - full_element=package) + context = ValidationContext( + spdx_id=package.spdx_id, + parent_id=document.creation_info.spdx_id, + element_type=SpdxElementType.PACKAGE, + full_element=package, + ) validation_messages: List[ValidationMessage] = validate_package_within_document(package, "SPDX-2.3", document) assert validation_messages == [ - ValidationMessage(f"package must contain no elements if files_analyzed is False, but found {relationships}", - context)] + ValidationMessage( + f"package must contain no elements if files_analyzed is False, but found {relationships}", context + ) + ] def test_v2_3only_fields(): @@ -95,8 +126,15 @@ def test_v2_3only_fields(): def test_v2_2mandatory_fields(): - package = package_fixture(license_concluded=None, license_declared=None, copyright_text=None, - primary_package_purpose=None, built_date=None, release_date=None, valid_until_date=None) + package = package_fixture( + license_concluded=None, + license_declared=None, + copyright_text=None, + primary_package_purpose=None, + built_date=None, + release_date=None, + valid_until_date=None, + ) assert validate_package(package, "SPDX-2.3") == [] diff --git a/tests/spdx/validation/test_package_verification_code_validator.py b/tests/spdx/validation/test_package_verification_code_validator.py index d94d56be3..d6ddb1548 100644 --- a/tests/spdx/validation/test_package_verification_code_validator.py +++ b/tests/spdx/validation/test_package_verification_code_validator.py @@ -13,7 +13,7 @@ from spdx.model.package import PackageVerificationCode from spdx.validation.package_verification_code_validator import validate_verification_code -from spdx.validation.validation_message import ValidationContext, SpdxElementType, ValidationMessage +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage def test_valid_package_verification_code(): @@ -23,19 +23,30 @@ def test_valid_package_verification_code(): assert validation_messages == [] -@pytest.mark.parametrize("code, expected_message", - [(PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791cab", []), - "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791cab (length: 42 digits)"), - (PackageVerificationCode("CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4", []), - "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4 (length: 40 digits)"), - (PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791c", - ["/invalid/excluded/file"]), - 'file name must not be an absolute path starting with "/", but is: /invalid/excluded/file') - ]) +@pytest.mark.parametrize( + "code, expected_message", + [ + ( + PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791cab", []), + "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: " + "71c4025dd9897b364f3ebbb42c484ff43d00791cab (length: 42 digits)", + ), + ( + PackageVerificationCode("CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4", []), + "value of verification_code must consist of 40 lowercase hexadecimal digits, but is: " + "CE9F343C4BA371746FD7EAD9B59031AE34D8AFC4 (length: 40 digits)", + ), + ( + PackageVerificationCode("71c4025dd9897b364f3ebbb42c484ff43d00791c", ["/invalid/excluded/file"]), + 'file name must not be an absolute path starting with "/", but is: /invalid/excluded/file', + ), + ], +) def test_invalid_package_verification_code(code, expected_message): parent_id = "SPDXRef-Package" - context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE, - full_element=code) + context = ValidationContext( + parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE, full_element=code + ) validation_messages = validate_verification_code(code, parent_id) assert validation_messages == [ValidationMessage(expected_message, context)] diff --git a/tests/spdx/validation/test_relationship_validator.py b/tests/spdx/validation/test_relationship_validator.py index 32e4c114b..83e8bc1a6 100644 --- a/tests/spdx/validation/test_relationship_validator.py +++ b/tests/spdx/validation/test_relationship_validator.py @@ -18,50 +18,70 @@ from spdx.model.spdx_no_assertion import SpdxNoAssertion from spdx.model.spdx_none import SpdxNone from spdx.validation.relationship_validator import validate_relationship -from spdx.validation.validation_message import ValidationMessage, SpdxElementType, ValidationContext +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import document_fixture, relationship_fixture -@pytest.mark.parametrize("related_spdx_element", - ["SPDXRef-Package", SpdxNoAssertion(), SpdxNone()]) +@pytest.mark.parametrize("related_spdx_element", ["SPDXRef-Package", SpdxNoAssertion(), SpdxNone()]) def test_valid_relationship(related_spdx_element): - relationship = Relationship("SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, related_spdx_element, comment="comment") + relationship = Relationship( + "SPDXRef-DOCUMENT", RelationshipType.DESCRIBES, related_spdx_element, comment="comment" + ) validation_messages: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.3", document_fixture()) assert validation_messages == [] -@pytest.mark.parametrize("spdx_element_id, related_spdx_element_id, expected_message", - [("SPDXRef-unknownFile", "SPDXRef-File", - 'did not find the referenced spdx_id "SPDXRef-unknownFile" in the SPDX document'), - ("SPDXRef-File", "SPDXRef-unknownFile", - 'did not find the referenced spdx_id "SPDXRef-unknownFile" in the SPDX document'), - ]) +@pytest.mark.parametrize( + "spdx_element_id, related_spdx_element_id, expected_message", + [ + ( + "SPDXRef-unknownFile", + "SPDXRef-File", + 'did not find the referenced spdx_id "SPDXRef-unknownFile" in the SPDX document', + ), + ( + "SPDXRef-File", + "SPDXRef-unknownFile", + 'did not find the referenced spdx_id "SPDXRef-unknownFile" in the SPDX document', + ), + ], +) def test_unknown_spdx_id(spdx_element_id, related_spdx_element_id, expected_message): - relationship: Relationship = relationship_fixture(spdx_element_id=spdx_element_id, - related_spdx_element_id=related_spdx_element_id) + relationship: Relationship = relationship_fixture( + spdx_element_id=spdx_element_id, related_spdx_element_id=related_spdx_element_id + ) validation_messages: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.3", document_fixture()) - expected = ValidationMessage(expected_message, - ValidationContext(element_type=SpdxElementType.RELATIONSHIP, - full_element=relationship)) + expected = ValidationMessage( + expected_message, ValidationContext(element_type=SpdxElementType.RELATIONSHIP, full_element=relationship) + ) assert validation_messages == [expected] -@pytest.mark.parametrize("relationship, expected_message", - [(Relationship("SPDXRef-DOCUMENT", RelationshipType.SPECIFICATION_FOR, "SPDXRef-Package"), - "RelationshipType.SPECIFICATION_FOR is not supported in SPDX-2.2"), - (Relationship("SPDXRef-DOCUMENT", RelationshipType.REQUIREMENT_DESCRIPTION_FOR, - "SPDXRef-Package"), - "RelationshipType.REQUIREMENT_DESCRIPTION_FOR is not supported in SPDX-2.2")]) +@pytest.mark.parametrize( + "relationship, expected_message", + [ + ( + Relationship("SPDXRef-DOCUMENT", RelationshipType.SPECIFICATION_FOR, "SPDXRef-Package"), + "RelationshipType.SPECIFICATION_FOR is not supported in SPDX-2.2", + ), + ( + Relationship("SPDXRef-DOCUMENT", RelationshipType.REQUIREMENT_DESCRIPTION_FOR, "SPDXRef-Package"), + "RelationshipType.REQUIREMENT_DESCRIPTION_FOR is not supported in SPDX-2.2", + ), + ], +) def test_v2_3_only_types(relationship, expected_message): document: Document = document_fixture() validation_message: List[ValidationMessage] = validate_relationship(relationship, "SPDX-2.2", document) - expected = [ValidationMessage(expected_message, - ValidationContext(element_type=SpdxElementType.RELATIONSHIP, - full_element=relationship))] + expected = [ + ValidationMessage( + expected_message, ValidationContext(element_type=SpdxElementType.RELATIONSHIP, full_element=relationship) + ) + ] assert validation_message == expected diff --git a/tests/spdx/validation/test_snippet_validator.py b/tests/spdx/validation/test_snippet_validator.py index 90bd4aca1..5c9881653 100644 --- a/tests/spdx/validation/test_snippet_validator.py +++ b/tests/spdx/validation/test_snippet_validator.py @@ -14,38 +14,55 @@ import pytest -from spdx.validation.snippet_validator import validate_snippet_within_document, validate_snippet -from spdx.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType +from spdx.validation.snippet_validator import validate_snippet, validate_snippet_within_document +from spdx.validation.validation_message import SpdxElementType, ValidationContext, ValidationMessage from tests.spdx.fixtures import document_fixture, snippet_fixture def test_valid_snippet(): snippet = snippet_fixture() - validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet, "SPDX-2.3", - document_fixture()) + validation_messages: List[ValidationMessage] = validate_snippet_within_document( + snippet, "SPDX-2.3", document_fixture() + ) assert validation_messages == [] -@pytest.mark.parametrize("snippet_input, expected_message", - [(snippet_fixture(byte_range=(-12, 45)), - "byte_range values must be greater than or equal to 1, but is: (-12, 45)"), - (snippet_fixture(byte_range=(45, 23)), - "the first value of byte_range must be less than or equal to the second, but is: (45, 23)"), - (snippet_fixture(line_range=(-12, 45)), - "line_range values must be greater than or equal to 1, but is: (-12, 45)"), - (snippet_fixture(line_range=(45, 23)), - "the first value of line_range must be less than or equal to the second, but is: (45, 23)") - ]) +@pytest.mark.parametrize( + "snippet_input, expected_message", + [ + ( + snippet_fixture(byte_range=(-12, 45)), + "byte_range values must be greater than or equal to 1, but is: (-12, 45)", + ), + ( + snippet_fixture(byte_range=(45, 23)), + "the first value of byte_range must be less than or equal to the second, but is: (45, 23)", + ), + ( + snippet_fixture(line_range=(-12, 45)), + "line_range values must be greater than or equal to 1, but is: (-12, 45)", + ), + ( + snippet_fixture(line_range=(45, 23)), + "the first value of line_range must be less than or equal to the second, but is: (45, 23)", + ), + ], +) def test_invalid_ranges(snippet_input, expected_message): - validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet_input, "SPDX-2.3", - document_fixture()) - - expected = ValidationMessage(expected_message, - ValidationContext(spdx_id=snippet_input.spdx_id, - parent_id=document_fixture().creation_info.spdx_id, - element_type=SpdxElementType.SNIPPET, - full_element=snippet_input)) + validation_messages: List[ValidationMessage] = validate_snippet_within_document( + snippet_input, "SPDX-2.3", document_fixture() + ) + + expected = ValidationMessage( + expected_message, + ValidationContext( + spdx_id=snippet_input.spdx_id, + parent_id=document_fixture().creation_info.spdx_id, + element_type=SpdxElementType.SNIPPET, + full_element=snippet_input, + ), + ) assert validation_messages == [expected] diff --git a/tests/spdx/validation/test_spdx_id_validators.py b/tests/spdx/validation/test_spdx_id_validators.py index bcf8745c1..e29697862 100644 --- a/tests/spdx/validation/test_spdx_id_validators.py +++ b/tests/spdx/validation/test_spdx_id_validators.py @@ -12,21 +12,34 @@ import pytest -from spdx.validation.spdx_id_validators import is_valid_internal_spdx_id, is_valid_external_doc_ref_id, \ - get_list_of_all_spdx_ids, is_spdx_id_present_in_document, is_external_doc_ref_present_in_document, validate_spdx_id -from tests.spdx.fixtures import document_fixture, file_fixture, package_fixture, snippet_fixture, creation_info_fixture, \ - external_document_ref_fixture - -DOCUMENT = document_fixture(files=[file_fixture(spdx_id="SPDXRef-File1"), - file_fixture(spdx_id="SPDXRef-File2")], - packages=[package_fixture(spdx_id="SPDXRef-Package1"), - package_fixture(spdx_id="SPDXRef-Package2")], - snippets=[snippet_fixture(spdx_id="SPDXRef-Snippet1"), - snippet_fixture(spdx_id="SPDXRef-Snippet2")], - creation_info=creation_info_fixture( - external_document_refs=[ - external_document_ref_fixture(document_ref_id="DocumentRef-external"), - external_document_ref_fixture(document_ref_id="DocumentRef-1.2-ext")])) +from spdx.validation.spdx_id_validators import ( + get_list_of_all_spdx_ids, + is_external_doc_ref_present_in_document, + is_spdx_id_present_in_document, + is_valid_external_doc_ref_id, + is_valid_internal_spdx_id, + validate_spdx_id, +) +from tests.spdx.fixtures import ( + creation_info_fixture, + document_fixture, + external_document_ref_fixture, + file_fixture, + package_fixture, + snippet_fixture, +) + +DOCUMENT = document_fixture( + files=[file_fixture(spdx_id="SPDXRef-File1"), file_fixture(spdx_id="SPDXRef-File2")], + packages=[package_fixture(spdx_id="SPDXRef-Package1"), package_fixture(spdx_id="SPDXRef-Package2")], + snippets=[snippet_fixture(spdx_id="SPDXRef-Snippet1"), snippet_fixture(spdx_id="SPDXRef-Snippet2")], + creation_info=creation_info_fixture( + external_document_refs=[ + external_document_ref_fixture(document_ref_id="DocumentRef-external"), + external_document_ref_fixture(document_ref_id="DocumentRef-1.2-ext"), + ] + ), +) @pytest.mark.parametrize("spdx_id", ["SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-1.3-3.7"]) @@ -34,8 +47,9 @@ def test_valid_internal_spdx_ids(spdx_id): assert is_valid_internal_spdx_id(spdx_id) -@pytest.mark.parametrize("spdx_id", - ["spdxId", "spdxRef-DOCUMENT", "SPDXRef.File", "SPDXRef#Snippet", "SPDXRef-1.3_3.7"]) +@pytest.mark.parametrize( + "spdx_id", ["spdxId", "spdxRef-DOCUMENT", "SPDXRef.File", "SPDXRef#Snippet", "SPDXRef-1.3_3.7"] +) def test_invalid_internal_spdx_ids(spdx_id): assert not is_valid_internal_spdx_id(spdx_id) @@ -45,8 +59,9 @@ def test_valid_external_doc_ref_ids(doc_ref_id): assert is_valid_external_doc_ref_id(doc_ref_id) -@pytest.mark.parametrize("doc_ref_id", - ["external-ref", "Documentref-external", "DocumentRef-...#", "DocumentRef-v0_4_2-alpha"]) +@pytest.mark.parametrize( + "doc_ref_id", ["external-ref", "Documentref-external", "DocumentRef-...#", "DocumentRef-v0_4_2-alpha"] +) def test_invalid_external_doc_ref_ids(doc_ref_id): assert not is_valid_external_doc_ref_id(doc_ref_id) @@ -65,43 +80,81 @@ def test_is_external_doc_ref_present_in_document(): def test_list_of_all_spdx_ids(): - TestCase().assertCountEqual(get_list_of_all_spdx_ids(DOCUMENT), - ["SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-File2", "SPDXRef-Package1", - "SPDXRef-Package2", "SPDXRef-Snippet1", "SPDXRef-Snippet2"]) - - -@pytest.mark.parametrize("spdx_id", - ["DocumentRef-external:SPDXRef-File", "SPDXRef-Package"]) + TestCase().assertCountEqual( + get_list_of_all_spdx_ids(DOCUMENT), + [ + "SPDXRef-DOCUMENT", + "SPDXRef-File1", + "SPDXRef-File2", + "SPDXRef-Package1", + "SPDXRef-Package2", + "SPDXRef-Snippet1", + "SPDXRef-Snippet2", + ], + ) + + +@pytest.mark.parametrize("spdx_id", ["DocumentRef-external:SPDXRef-File", "SPDXRef-Package"]) def test_valid_spdx_id(spdx_id): validation_messages = validate_spdx_id(spdx_id, DOCUMENT) assert validation_messages == [] -@pytest.mark.parametrize("spdx_id, expected_messages", - [("DocumentRef-external:extern:SPDXRef-File", - [f"spdx_id must not contain more than one colon in order to separate the external document reference id from the internal SPDX id, but is: DocumentRef-external:extern:SPDXRef-File"]), - ("DocumentRef external:SPDXRef-File", - ['the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: DocumentRef external', - 'did not find the external document reference "DocumentRef external" in the SPDX document']), - ("DocRef-ext:SPDXRef-File_2", - ['the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: DocRef-ext', - 'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: SPDXRef-File_2', - 'did not find the external document reference "DocRef-ext" in the SPDX document']), - ("DocumentRef-external:SPDXRef-File_2", - ['the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: SPDXRef-File_2']), - ("SPDXRef-42+", - ['spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: SPDXRef-42+']) - ]) +@pytest.mark.parametrize( + "spdx_id, expected_messages", + [ + ( + "DocumentRef-external:extern:SPDXRef-File", + [ + "spdx_id must not contain more than one colon in order to separate the external document reference id" + " from the internal SPDX id, but is: DocumentRef-external:extern:SPDXRef-File" + ], + ), + ( + "DocumentRef external:SPDXRef-File", + [ + 'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" ' + 'and must begin with "DocumentRef-", but is: DocumentRef external', + 'did not find the external document reference "DocumentRef external" in the SPDX document', + ], + ), + ( + "DocRef-ext:SPDXRef-File_2", + [ + 'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" ' + 'and must begin with "DocumentRef-", but is: DocRef-ext', + 'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin ' + 'with "SPDXRef-", but is: SPDXRef-File_2', + 'did not find the external document reference "DocRef-ext" in the SPDX document', + ], + ), + ( + "DocumentRef-external:SPDXRef-File_2", + [ + 'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin ' + 'with "SPDXRef-", but is: SPDXRef-File_2' + ], + ), + ( + "SPDXRef-42+", + [ + 'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: ' + "SPDXRef-42+" + ], + ), + ], +) def test_invalid_spdx_id(spdx_id, expected_messages): validation_messages = validate_spdx_id(spdx_id, DOCUMENT) TestCase().assertCountEqual(validation_messages, expected_messages) -@pytest.mark.parametrize("spdx_id", - ["DocumentRef-external:SPDXRef-File", "SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-Package1", - "SPDXRef-Snippet1"]) +@pytest.mark.parametrize( + "spdx_id", + ["DocumentRef-external:SPDXRef-File", "SPDXRef-DOCUMENT", "SPDXRef-File1", "SPDXRef-Package1", "SPDXRef-Snippet1"], +) def test_valid_spdx_id_with_check_document(spdx_id): validation_messages = validate_spdx_id(spdx_id, DOCUMENT, check_document=True) assert validation_messages == [] @@ -112,8 +165,7 @@ def test_invalid_spdx_id_with_check_document(): assert validation_messages == ['did not find the referenced spdx_id "SPDXRef-Filet" in the SPDX document'] -@pytest.mark.parametrize("spdx_id", - ["DocumentRef-external:SPDXRef-File", "SPDXRef-File1"]) +@pytest.mark.parametrize("spdx_id", ["DocumentRef-external:SPDXRef-File", "SPDXRef-File1"]) def test_valid_spdx_id_with_check_files(spdx_id): validation_messages = validate_spdx_id(spdx_id, DOCUMENT, check_files=True) assert validation_messages == [] @@ -122,5 +174,5 @@ def test_valid_spdx_id_with_check_files(spdx_id): def test_invalid_spdx_id_with_check_files(): validation_messages = validate_spdx_id("SPDXRef-Package1", DOCUMENT, check_files=True) assert validation_messages == [ - 'did not find the referenced spdx_id "SPDXRef-Package1" in the SPDX document\'s files'] - + 'did not find the referenced spdx_id "SPDXRef-Package1" in the SPDX document\'s files' + ] diff --git a/tests/spdx/validation/test_uri_validators.py b/tests/spdx/validation/test_uri_validators.py index a692ee8c7..59a8dd1e5 100644 --- a/tests/spdx/validation/test_uri_validators.py +++ b/tests/spdx/validation/test_uri_validators.py @@ -11,12 +11,18 @@ import pytest -from spdx.validation.uri_validators import validate_url, validate_download_location, validate_uri - - -@pytest.mark.parametrize("input_value", ["https://some.url", - "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...", - "http://some.url", "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz"]) +from spdx.validation.uri_validators import validate_download_location, validate_uri, validate_url + + +@pytest.mark.parametrize( + "input_value", + [ + "https://some.url", + "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...", + "http://some.url", + "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz", + ], +) def test_valid_url(input_value): assert validate_url(input_value) == [] @@ -27,85 +33,108 @@ def test_invalid_url(input_value): assert validate_url(input_value) == [f"must be a valid URL, but is: {input_value}"] -@pytest.mark.parametrize("input_value", ["http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz", - "git://git.myproject.org/MyProject", - "git+https://git.myproject.org/MyProject.git", - "git+http://git.myproject.org/MyProject", - "git+ssh://git.myproject.org/MyProject.git", - "git+git://git.myproject.org/MyProject", - "git+git@git.myproject.org:MyProject", - "git://git.myproject.org/MyProject#src/somefile.c", - "git+https://git.myproject.org/MyProject#src/Class.java", - "git://git.myproject.org/MyProject.git@master", - "git+https://git.myproject.org/MyProject.git@v1.0", - "git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709", - "git+https://git.myproject.org/MyProject.git@master#/src/MyClass.cpp", - "git+https://git.myproject.org/MyProject@da39a3ee5e6b4b0d3255bfef95601890afd80709#lib/variable.rb", - "hg+http://hg.myproject.org/MyProject", - "hg+https://hg.myproject.org/MyProject", - "hg+ssh://hg.myproject.org/MyProject", - "hg+https://hg.myproject.org/MyProject#src/somefile.c", - "hg+https://hg.myproject.org/MyProject#src/Class.java", - "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b", - "hg+https://hg.myproject.org/MyProject@2019", - "hg+https://hg.myproject.org/MyProject@v1.0", - "hg+https://hg.myproject.org/MyProject@special_feature", - "hg+https://hg.myproject.org/MyProject@master#/src/MyClass.cpp", - "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b#lib/variable.rb", - "svn://svn.myproject.org/svn/MyProject", - "svn+svn://svn.myproject.org/svn/MyProject", - "svn+http://svn.myproject.org/svn/MyProject/trunk", - "svn+https://svn.myproject.org/svn/MyProject/trunk", - "svn+https://svn.myproject.org/MyProject#src/somefile.c", - "svn+https://svn.myproject.org/MyProject#src/Class.java", - "svn+https://svn.myproject.org/MyProject/trunk#src/somefile.c", - "svn+https://svn.myproject.org/MyProject/trunk/src/somefile.c", - "svn+https://svn.myproject.org/svn/MyProject/trunk@2019", - "svn+https://svn.myproject.org/MyProject@123#/src/MyClass.cpp", - "svn+https://svn.myproject.org/MyProject/trunk@1234#lib/variable/variable.rb", - "bzr+https://bzr.myproject.org/MyProject/trunk", - "bzr+http://bzr.myproject.org/MyProject/trunk", - "bzr+sftp://myproject.org/MyProject/trunk", - "bzr+ssh://myproject.org/MyProject/trunk", - "bzr+ftp://myproject.org/MyProject/trunk", - "bzr+lp:MyProject", - "bzr+https://bzr.myproject.org/MyProject/trunk#src/somefile.c", - "bzr+https://bzr.myproject.org/MyProject/trunk#src/Class.java", - "bzr+https://bzr.myproject.org/MyProject/trunk@2019", - "bzr+http://bzr.myproject.org/MyProject/trunk@v1.0", - "bzr+https://bzr.myproject.org/MyProject/trunk@2019#src/somefile.c", - ]) +@pytest.mark.parametrize( + "input_value", + [ + "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz", + "git://git.myproject.org/MyProject", + "git+https://git.myproject.org/MyProject.git", + "git+http://git.myproject.org/MyProject", + "git+ssh://git.myproject.org/MyProject.git", + "git+git://git.myproject.org/MyProject", + "git+git@git.myproject.org:MyProject", + "git://git.myproject.org/MyProject#src/somefile.c", + "git+https://git.myproject.org/MyProject#src/Class.java", + "git://git.myproject.org/MyProject.git@master", + "git+https://git.myproject.org/MyProject.git@v1.0", + "git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709", + "git+https://git.myproject.org/MyProject.git@master#/src/MyClass.cpp", + "git+https://git.myproject.org/MyProject@da39a3ee5e6b4b0d3255bfef95601890afd80709#lib/variable.rb", + "hg+http://hg.myproject.org/MyProject", + "hg+https://hg.myproject.org/MyProject", + "hg+ssh://hg.myproject.org/MyProject", + "hg+https://hg.myproject.org/MyProject#src/somefile.c", + "hg+https://hg.myproject.org/MyProject#src/Class.java", + "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b", + "hg+https://hg.myproject.org/MyProject@2019", + "hg+https://hg.myproject.org/MyProject@v1.0", + "hg+https://hg.myproject.org/MyProject@special_feature", + "hg+https://hg.myproject.org/MyProject@master#/src/MyClass.cpp", + "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b#lib/variable.rb", + "svn://svn.myproject.org/svn/MyProject", + "svn+svn://svn.myproject.org/svn/MyProject", + "svn+http://svn.myproject.org/svn/MyProject/trunk", + "svn+https://svn.myproject.org/svn/MyProject/trunk", + "svn+https://svn.myproject.org/MyProject#src/somefile.c", + "svn+https://svn.myproject.org/MyProject#src/Class.java", + "svn+https://svn.myproject.org/MyProject/trunk#src/somefile.c", + "svn+https://svn.myproject.org/MyProject/trunk/src/somefile.c", + "svn+https://svn.myproject.org/svn/MyProject/trunk@2019", + "svn+https://svn.myproject.org/MyProject@123#/src/MyClass.cpp", + "svn+https://svn.myproject.org/MyProject/trunk@1234#lib/variable/variable.rb", + "bzr+https://bzr.myproject.org/MyProject/trunk", + "bzr+http://bzr.myproject.org/MyProject/trunk", + "bzr+sftp://myproject.org/MyProject/trunk", + "bzr+ssh://myproject.org/MyProject/trunk", + "bzr+ftp://myproject.org/MyProject/trunk", + "bzr+lp:MyProject", + "bzr+https://bzr.myproject.org/MyProject/trunk#src/somefile.c", + "bzr+https://bzr.myproject.org/MyProject/trunk#src/Class.java", + "bzr+https://bzr.myproject.org/MyProject/trunk@2019", + "bzr+http://bzr.myproject.org/MyProject/trunk@v1.0", + "bzr+https://bzr.myproject.org/MyProject/trunk@2019#src/somefile.c", + ], +) def test_valid_package_download_location(input_value): assert validate_download_location(input_value) == [] # TODO: more negative examples: https://github.com/spdx/tools-python/issues/377 -@pytest.mark.parametrize("input_value", [":::::", ]) +@pytest.mark.parametrize( + "input_value", + [ + ":::::", + ], +) def test_invalid_package_download_location(input_value): assert validate_download_location(input_value) == [ - f"must be a valid download location according to the specification, but is: {input_value}"] - - -@pytest.mark.parametrize("input_value", ["https://some.uri", "http:////some", - "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...", - "h://someweirdtest^?", "https://some.uri that goes on!?"]) + f"must be a valid download location according to the specification, but is: {input_value}" + ] + + +@pytest.mark.parametrize( + "input_value", + [ + "https://some.uri", + "http:////some", + "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...", + "h://someweirdtest^?", + "https://some.uri that goes on!?", + ], +) def test_valid_uri(input_value): message = validate_uri(input_value) assert message == [] -@pytest.mark.parametrize("input_value", ["/invalid/uri", "http//uri", "http://some#uri", "some/uri", "some weird test"]) +@pytest.mark.parametrize( + "input_value", ["/invalid/uri", "http//uri", "http://some#uri", "some/uri", "some weird test"] +) def test_invalid_uri(input_value): message = validate_uri(input_value) - assert message == [f"must be a valid URI specified in RFC-3986 and must contain no fragment (#), but is: {input_value}"] + assert message == [ + f"must be a valid URI specified in RFC-3986 and must contain no fragment (#), but is: {input_value}" + ] @pytest.mark.parametrize("input_value", ["://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82..."]) @pytest.mark.skip( - "validate_uri() seems to invalidate URIs without scheme, so it does not run into this case. But I'm not sure yet if this covers all scheme-less examples." - "https://github.com/spdx/tools-python/issues/377") + "validate_uri() seems to invalidate URIs without scheme, so it does not run into this case. But I'm not sure yet " + "if this covers all scheme-less examples." + "https://github.com/spdx/tools-python/issues/377" +) def test_uri_without_scheme(input_value): message = validate_uri(input_value) diff --git a/tests/spdx/writer/json/test_json_writer.py b/tests/spdx/writer/json/test_json_writer.py index 2bfeb5aa5..aff0c9501 100644 --- a/tests/spdx/writer/json/test_json_writer.py +++ b/tests/spdx/writer/json/test_json_writer.py @@ -31,7 +31,7 @@ def test_write_json(temporary_file_path: str): with open(temporary_file_path) as written_file: written_json = json.load(written_file) - with open(os.path.join(os.path.dirname(__file__), 'expected_results', 'expected.json')) as expected_file: + with open(os.path.join(os.path.dirname(__file__), "expected_results", "expected.json")) as expected_file: expected_json = json.load(expected_file) assert written_json == expected_json diff --git a/tests/spdx/writer/rdf/test_annotation_writer.py b/tests/spdx/writer/rdf/test_annotation_writer.py index 435599b85..1e616ac6a 100644 --- a/tests/spdx/writer/rdf/test_annotation_writer.py +++ b/tests/spdx/writer/rdf/test_annotation_writer.py @@ -8,11 +8,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, Literal, RDFS, URIRef, RDF +from rdflib import RDF, RDFS, Graph, Literal, URIRef from spdx.datetime_conversions import datetime_to_iso_string -from spdx.writer.rdf.annotation_writer import add_annotation_to_graph from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.annotation_writer import add_annotation_to_graph from tests.spdx.fixtures import annotation_fixture diff --git a/tests/spdx/writer/rdf/test_checksum_writer.py b/tests/spdx/writer/rdf/test_checksum_writer.py index 535418dff..76560e8e4 100644 --- a/tests/spdx/writer/rdf/test_checksum_writer.py +++ b/tests/spdx/writer/rdf/test_checksum_writer.py @@ -9,11 +9,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from rdflib import Graph, URIRef, Literal, RDF +from rdflib import RDF, Graph, Literal, URIRef from spdx.model.checksum import ChecksumAlgorithm -from spdx.writer.rdf.checksum_writer import add_checksum_to_graph, algorithm_to_rdf_string from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.checksum_writer import add_checksum_to_graph, algorithm_to_rdf_string from tests.spdx.fixtures import checksum_fixture @@ -29,27 +29,28 @@ def test_add_checksum_to_graph(): assert (None, SPDX_NAMESPACE.checksumValue, Literal(checksum.value)) in graph -@pytest.mark.parametrize("algorithm,expected", [(ChecksumAlgorithm.SHA1, SPDX_NAMESPACE.checksumAlgorithm_sha1), - (ChecksumAlgorithm.SHA224, SPDX_NAMESPACE.checksumAlgorithm_sha224), - (ChecksumAlgorithm.SHA256, SPDX_NAMESPACE.checksumAlgorithm_sha256), - (ChecksumAlgorithm.SHA384, SPDX_NAMESPACE.checksumAlgorithm_sha384), - (ChecksumAlgorithm.SHA512, SPDX_NAMESPACE.checksumAlgorithm_sha512), - (ChecksumAlgorithm.SHA3_256, SPDX_NAMESPACE.checksumAlgorithm_sha3_256), - (ChecksumAlgorithm.SHA3_384, SPDX_NAMESPACE.checksumAlgorithm_sha3_384), - (ChecksumAlgorithm.SHA3_512, SPDX_NAMESPACE.checksumAlgorithm_sha3_512), - (ChecksumAlgorithm.BLAKE2B_256, - SPDX_NAMESPACE.checksumAlgorithm_blake2b256), - (ChecksumAlgorithm.BLAKE2B_384, - SPDX_NAMESPACE.checksumAlgorithm_blake2b384), - (ChecksumAlgorithm.BLAKE2B_512, - SPDX_NAMESPACE.checksumAlgorithm_blake2b512), - (ChecksumAlgorithm.BLAKE3, SPDX_NAMESPACE.checksumAlgorithm_blake3), - (ChecksumAlgorithm.MD2, SPDX_NAMESPACE.checksumAlgorithm_md2), - (ChecksumAlgorithm.MD4, SPDX_NAMESPACE.checksumAlgorithm_md4), - (ChecksumAlgorithm.MD5, SPDX_NAMESPACE.checksumAlgorithm_md5), - (ChecksumAlgorithm.MD6, SPDX_NAMESPACE.checksumAlgorithm_md6), - (ChecksumAlgorithm.ADLER32, SPDX_NAMESPACE.checksumAlgorithm_adler32) - ]) +@pytest.mark.parametrize( + "algorithm,expected", + [ + (ChecksumAlgorithm.SHA1, SPDX_NAMESPACE.checksumAlgorithm_sha1), + (ChecksumAlgorithm.SHA224, SPDX_NAMESPACE.checksumAlgorithm_sha224), + (ChecksumAlgorithm.SHA256, SPDX_NAMESPACE.checksumAlgorithm_sha256), + (ChecksumAlgorithm.SHA384, SPDX_NAMESPACE.checksumAlgorithm_sha384), + (ChecksumAlgorithm.SHA512, SPDX_NAMESPACE.checksumAlgorithm_sha512), + (ChecksumAlgorithm.SHA3_256, SPDX_NAMESPACE.checksumAlgorithm_sha3_256), + (ChecksumAlgorithm.SHA3_384, SPDX_NAMESPACE.checksumAlgorithm_sha3_384), + (ChecksumAlgorithm.SHA3_512, SPDX_NAMESPACE.checksumAlgorithm_sha3_512), + (ChecksumAlgorithm.BLAKE2B_256, SPDX_NAMESPACE.checksumAlgorithm_blake2b256), + (ChecksumAlgorithm.BLAKE2B_384, SPDX_NAMESPACE.checksumAlgorithm_blake2b384), + (ChecksumAlgorithm.BLAKE2B_512, SPDX_NAMESPACE.checksumAlgorithm_blake2b512), + (ChecksumAlgorithm.BLAKE3, SPDX_NAMESPACE.checksumAlgorithm_blake3), + (ChecksumAlgorithm.MD2, SPDX_NAMESPACE.checksumAlgorithm_md2), + (ChecksumAlgorithm.MD4, SPDX_NAMESPACE.checksumAlgorithm_md4), + (ChecksumAlgorithm.MD5, SPDX_NAMESPACE.checksumAlgorithm_md5), + (ChecksumAlgorithm.MD6, SPDX_NAMESPACE.checksumAlgorithm_md6), + (ChecksumAlgorithm.ADLER32, SPDX_NAMESPACE.checksumAlgorithm_adler32), + ], +) def test_algorithm_to_rdf_string(algorithm, expected): rdf_element = algorithm_to_rdf_string(algorithm) diff --git a/tests/spdx/writer/rdf/test_creation_info_writer.py b/tests/spdx/writer/rdf/test_creation_info_writer.py index 6237208ff..0a3e5155a 100644 --- a/tests/spdx/writer/rdf/test_creation_info_writer.py +++ b/tests/spdx/writer/rdf/test_creation_info_writer.py @@ -8,11 +8,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, Literal, RDFS, URIRef, RDF +from rdflib import RDF, RDFS, Graph, Literal, URIRef from spdx.datetime_conversions import datetime_to_iso_string +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE from spdx.writer.rdf.creation_info_writer import add_creation_info_to_graph -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE from tests.spdx.fixtures import creation_info_fixture diff --git a/tests/spdx/writer/rdf/test_external_document_ref_writer.py b/tests/spdx/writer/rdf/test_external_document_ref_writer.py index a8c206df1..6e6acf8f7 100644 --- a/tests/spdx/writer/rdf/test_external_document_ref_writer.py +++ b/tests/spdx/writer/rdf/test_external_document_ref_writer.py @@ -8,9 +8,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, URIRef, RDF -from spdx.rdfschema.namespace import SPDX_NAMESPACE +from rdflib import RDF, Graph, URIRef +from spdx.rdfschema.namespace import SPDX_NAMESPACE from spdx.writer.rdf.external_document_ref_writer import add_external_document_ref_to_graph from tests.spdx.fixtures import external_document_ref_fixture @@ -21,11 +21,12 @@ def test_add_external_document_ref_to_graph(): add_external_document_ref_to_graph(external_document_ref, graph, URIRef("docNode"), "docNamespace") - assert (URIRef("docNode"), SPDX_NAMESPACE.externalDocumentRef, URIRef("docNamespace#DocumentRef-external")) in graph + assert ( + URIRef("docNode"), + SPDX_NAMESPACE.externalDocumentRef, + URIRef("docNamespace#DocumentRef-external"), + ) in graph assert (None, RDF.type, SPDX_NAMESPACE.ExternalDocumentRef) in graph assert (None, SPDX_NAMESPACE.checksum, None) in graph assert (None, RDF.type, SPDX_NAMESPACE.Checksum) in graph assert (None, SPDX_NAMESPACE.spdxDocument, URIRef(external_document_ref.document_uri)) in graph - - - diff --git a/tests/spdx/writer/rdf/test_extracted_licensing_info_writer.py b/tests/spdx/writer/rdf/test_extracted_licensing_info_writer.py index 55669dae5..3019d62ac 100644 --- a/tests/spdx/writer/rdf/test_extracted_licensing_info_writer.py +++ b/tests/spdx/writer/rdf/test_extracted_licensing_info_writer.py @@ -8,9 +8,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, Literal, RDFS, URIRef, RDF -from spdx.rdfschema.namespace import SPDX_NAMESPACE +from rdflib import RDF, RDFS, Graph, Literal, URIRef +from spdx.rdfschema.namespace import SPDX_NAMESPACE from spdx.writer.rdf.extracted_licensing_info_writer import add_extracted_licensing_info_to_graph from tests.spdx.fixtures import extracted_licensing_info_fixture diff --git a/tests/spdx/writer/rdf/test_file_writer.py b/tests/spdx/writer/rdf/test_file_writer.py index a8efc647a..d28a1c9b8 100644 --- a/tests/spdx/writer/rdf/test_file_writer.py +++ b/tests/spdx/writer/rdf/test_file_writer.py @@ -8,10 +8,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, Literal, RDFS, RDF, URIRef +from rdflib import RDF, RDFS, Graph, Literal, URIRef +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE from spdx.writer.rdf.file_writer import add_file_to_graph -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE from tests.spdx.fixtures import file_fixture diff --git a/tests/spdx/writer/rdf/test_license_expression_writer.py b/tests/spdx/writer/rdf/test_license_expression_writer.py index 8f7d9ff5c..73152ee69 100644 --- a/tests/spdx/writer/rdf/test_license_expression_writer.py +++ b/tests/spdx/writer/rdf/test_license_expression_writer.py @@ -10,9 +10,9 @@ # limitations under the License. import pytest from license_expression import get_spdx_licensing -from rdflib import Graph, URIRef, RDF, Literal -from spdx.rdfschema.namespace import SPDX_NAMESPACE +from rdflib import RDF, Graph, Literal, URIRef +from spdx.rdfschema.namespace import SPDX_NAMESPACE from spdx.writer.rdf.license_expression_writer import add_license_expression_to_graph @@ -20,8 +20,9 @@ def test_add_conjunctive_license_set_to_graph(): graph = Graph() license_expression = get_spdx_licensing().parse("MIT AND GPL-2.0") - add_license_expression_to_graph(license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, - "https://namespace") + add_license_expression_to_graph( + license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, "https://namespace" + ) assert (URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, None) in graph assert (None, RDF.type, SPDX_NAMESPACE.ConjunctiveLicenseSet) in graph @@ -33,8 +34,9 @@ def test_add_disjunctive_license_set_to_graph(): graph = Graph() license_expression = get_spdx_licensing().parse("MIT OR GPL-2.0") - add_license_expression_to_graph(license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, - "https://namespace") + add_license_expression_to_graph( + license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, "https://namespace" + ) assert (URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, None) in graph assert (None, RDF.type, SPDX_NAMESPACE.DisjunctiveLicenseSet) in graph @@ -42,18 +44,23 @@ def test_add_disjunctive_license_set_to_graph(): assert (None, SPDX_NAMESPACE.member, URIRef("http://spdx.org/licenses/GPL-2.0-only")) in graph -@pytest.mark.parametrize("license_with_exception," - "expected_triple", [("MIT WITH openvpn-openssl-exception", - (URIRef("http://spdx.org/licenses/openvpn-openssl-exception"), RDF.type, - SPDX_NAMESPACE.LicenseException)), - ("MIT WITH unknown-exception", - (None, SPDX_NAMESPACE.licenseExceptionId, Literal("unknown-exception")))]) +@pytest.mark.parametrize( + "license_with_exception," "expected_triple", + [ + ( + "MIT WITH openvpn-openssl-exception", + (URIRef("http://spdx.org/licenses/openvpn-openssl-exception"), RDF.type, SPDX_NAMESPACE.LicenseException), + ), + ("MIT WITH unknown-exception", (None, SPDX_NAMESPACE.licenseExceptionId, Literal("unknown-exception"))), + ], +) def test_license_exception_to_graph(license_with_exception, expected_triple): graph = Graph() license_expression = get_spdx_licensing().parse(license_with_exception) - add_license_expression_to_graph(license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, - "https://namespace") + add_license_expression_to_graph( + license_expression, graph, URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, "https://namespace" + ) assert (URIRef("parentNode"), SPDX_NAMESPACE.licenseConcluded, None) in graph assert (None, RDF.type, SPDX_NAMESPACE.WithExceptionOperator) in graph diff --git a/tests/spdx/writer/rdf/test_package_writer.py b/tests/spdx/writer/rdf/test_package_writer.py index 7f57a7b4b..bab01ff53 100644 --- a/tests/spdx/writer/rdf/test_package_writer.py +++ b/tests/spdx/writer/rdf/test_package_writer.py @@ -9,14 +9,17 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from rdflib import Graph, URIRef, RDF, Literal, XSD, RDFS, DOAP -from spdx.model.package import ExternalPackageRefCategory +from rdflib import DOAP, RDF, RDFS, XSD, Graph, Literal, URIRef from spdx.datetime_conversions import datetime_to_iso_string -from spdx.writer.rdf.package_writer import add_package_to_graph, add_external_package_ref_to_graph, \ - add_package_verification_code_to_graph -from spdx.rdfschema.namespace import SPDX_NAMESPACE, LICENSE_NAMESPACE -from tests.spdx.fixtures import package_fixture, external_package_ref_fixture, package_verification_code_fixture +from spdx.model.package import ExternalPackageRefCategory +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, SPDX_NAMESPACE +from spdx.writer.rdf.package_writer import ( + add_external_package_ref_to_graph, + add_package_to_graph, + add_package_verification_code_to_graph, +) +from tests.spdx.fixtures import external_package_ref_fixture, package_fixture, package_verification_code_fixture def test_add_package_to_graph(): @@ -62,20 +65,34 @@ def test_add_package_verification_code_to_graph(): add_package_verification_code_to_graph(verification_code, graph, URIRef("docNamespace")) assert (None, RDF.type, SPDX_NAMESPACE.PackageVerificationCode) in graph - assert (None, SPDX_NAMESPACE.packageVerificationCodeValue, - Literal("85ed0817af83a24ad8da68c2b5094de69833983c")) in graph + assert ( + None, + SPDX_NAMESPACE.packageVerificationCodeValue, + Literal("85ed0817af83a24ad8da68c2b5094de69833983c"), + ) in graph assert (None, SPDX_NAMESPACE.packageVerificationCodeExcludedFile, Literal("./exclude.py")) in graph -@pytest.mark.parametrize("external_reference,ref_type,category", - [(external_package_ref_fixture(), URIRef("http://spdx.org/rdf/references/maven-central"), - SPDX_NAMESPACE.referenceCategory_packageManager), - (external_package_ref_fixture(locator="acmecorp/acmenator/4.1.3-alpha", - category=ExternalPackageRefCategory.OTHER, - reference_type="LocationRef-acmeforge", - comment="This is the external ref for Acme"), - URIRef("https://some.namespace#LocationRef-acmeforge"), - SPDX_NAMESPACE.referenceCategory_other)]) +@pytest.mark.parametrize( + "external_reference,ref_type,category", + [ + ( + external_package_ref_fixture(), + URIRef("http://spdx.org/rdf/references/maven-central"), + SPDX_NAMESPACE.referenceCategory_packageManager, + ), + ( + external_package_ref_fixture( + locator="acmecorp/acmenator/4.1.3-alpha", + category=ExternalPackageRefCategory.OTHER, + reference_type="LocationRef-acmeforge", + comment="This is the external ref for Acme", + ), + URIRef("https://some.namespace#LocationRef-acmeforge"), + SPDX_NAMESPACE.referenceCategory_other, + ), + ], +) def test_external_package_ref_to_graph(external_reference, ref_type, category): graph = Graph() doc_namespace = "https://some.namespace" diff --git a/tests/spdx/writer/rdf/test_rdf_writer.py b/tests/spdx/writer/rdf/test_rdf_writer.py index 38e4f5871..3d99c2389 100644 --- a/tests/spdx/writer/rdf/test_rdf_writer.py +++ b/tests/spdx/writer/rdf/test_rdf_writer.py @@ -12,10 +12,9 @@ import pytest -from tests.spdx.fixtures import document_fixture - from spdx.model.document import Document from spdx.writer.rdf.rdf_writer import write_document_to_file +from tests.spdx.fixtures import document_fixture @pytest.fixture diff --git a/tests/spdx/writer/rdf/test_relationship_writer.py b/tests/spdx/writer/rdf/test_relationship_writer.py index fd028d618..dc559caf0 100644 --- a/tests/spdx/writer/rdf/test_relationship_writer.py +++ b/tests/spdx/writer/rdf/test_relationship_writer.py @@ -8,10 +8,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from rdflib import Graph, URIRef, RDFS, Literal +from rdflib import RDFS, Graph, Literal, URIRef -from spdx.writer.rdf.relationship_writer import add_relationship_to_graph from spdx.rdfschema.namespace import SPDX_NAMESPACE +from spdx.writer.rdf.relationship_writer import add_relationship_to_graph from tests.spdx.fixtures import relationship_fixture @@ -20,7 +20,7 @@ def test_add_relationship_to_graph(): graph = Graph() add_relationship_to_graph(relationship, graph, "docNamespace", {}) - assert(URIRef("docNamespace#SPDXRef-DOCUMENT"), SPDX_NAMESPACE.relationship, None) in graph + assert (URIRef("docNamespace#SPDXRef-DOCUMENT"), SPDX_NAMESPACE.relationship, None) in graph assert (None, SPDX_NAMESPACE.relationshipType, SPDX_NAMESPACE.relationshipType_describes) in graph assert (None, SPDX_NAMESPACE.relatedSpdxElement, URIRef("docNamespace#SPDXRef-File")) in graph assert (None, RDFS.comment, Literal(relationship.comment)) in graph diff --git a/tests/spdx/writer/rdf/test_snippet_writer.py b/tests/spdx/writer/rdf/test_snippet_writer.py index 1951563aa..53c493ded 100644 --- a/tests/spdx/writer/rdf/test_snippet_writer.py +++ b/tests/spdx/writer/rdf/test_snippet_writer.py @@ -9,10 +9,10 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from rdflib import Graph, URIRef, RDF, Literal, RDFS -from spdx.rdfschema.namespace import SPDX_NAMESPACE, POINTER_NAMESPACE, LICENSE_NAMESPACE +from rdflib import RDF, RDFS, Graph, Literal, URIRef -from spdx.writer.rdf.snippet_writer import add_snippet_to_graph, add_range_to_graph +from spdx.rdfschema.namespace import LICENSE_NAMESPACE, POINTER_NAMESPACE, SPDX_NAMESPACE +from spdx.writer.rdf.snippet_writer import add_range_to_graph, add_snippet_to_graph from tests.spdx.fixtures import snippet_fixture @@ -35,9 +35,13 @@ def test_add_snippet_to_graph(): assert (None, RDFS.comment, Literal(snippet.comment)) in graph -@pytest.mark.parametrize("range,pointer,predicate", - [((5, 190), POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), - ((1, 3), POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber)]) +@pytest.mark.parametrize( + "range,pointer,predicate", + [ + ((5, 190), POINTER_NAMESPACE.ByteOffsetPointer, POINTER_NAMESPACE.offset), + ((1, 3), POINTER_NAMESPACE.LineCharPointer, POINTER_NAMESPACE.lineNumber), + ], +) def test_add_ranges_to_graph(range, pointer, predicate): graph = Graph() add_range_to_graph(range, graph, URIRef("snippetNode"), URIRef("docNamespace#SPDXRef-File"), pointer) diff --git a/tests/spdx/writer/rdf/test_writer_utils.py b/tests/spdx/writer/rdf/test_writer_utils.py index 258fa3788..aa74c570f 100644 --- a/tests/spdx/writer/rdf/test_writer_utils.py +++ b/tests/spdx/writer/rdf/test_writer_utils.py @@ -13,12 +13,20 @@ from spdx.writer.rdf.writer_utils import add_namespace_to_spdx_id -@pytest.mark.parametrize("spdx_id,namespace,external_namespaces,expected", - [("SPDXRef-File", "docNamespace", {}, "docNamespace#SPDXRef-File"), - ("externalDoc:SPDXRef-File", "docNamespace", {"externalDoc": "externalNamespace"}, - "externalNamespace#SPDXRef-File"), - ("externalDoc#A-Ref", "", {}, "externalDoc#A-Ref"), - ("externalDoc:A-Ref", "", {}, "externalDoc:A-Ref")]) +@pytest.mark.parametrize( + "spdx_id,namespace,external_namespaces,expected", + [ + ("SPDXRef-File", "docNamespace", {}, "docNamespace#SPDXRef-File"), + ( + "externalDoc:SPDXRef-File", + "docNamespace", + {"externalDoc": "externalNamespace"}, + "externalNamespace#SPDXRef-File", + ), + ("externalDoc#A-Ref", "", {}, "externalDoc#A-Ref"), + ("externalDoc:A-Ref", "", {}, "externalDoc:A-Ref"), + ], +) def test_add_namespace_to_spdx_id(spdx_id, namespace, expected, external_namespaces): extended_spdx_id = add_namespace_to_spdx_id(spdx_id, namespace, external_namespaces) diff --git a/tests/spdx/writer/tagvalue/test_creation_info_writer.py b/tests/spdx/writer/tagvalue/test_creation_info_writer.py index b4be91b5c..161d4047e 100644 --- a/tests/spdx/writer/tagvalue/test_creation_info_writer.py +++ b/tests/spdx/writer/tagvalue/test_creation_info_writer.py @@ -2,37 +2,63 @@ # # SPDX-License-Identifier: Apache-2.0 import datetime -from unittest.mock import mock_open, patch, call, MagicMock +from unittest.mock import MagicMock, call, mock_open, patch import pytest from spdx.model.document import CreationInfo -from tests.spdx.fixtures import creation_info_fixture, actor_fixture - from spdx.writer.tagvalue.creation_info_writer import write_creation_info +from tests.spdx.fixtures import actor_fixture, creation_info_fixture -@pytest.mark.parametrize("creation_info, expected_calls", - [(creation_info_fixture(), [call("SPDXVersion: SPDX-2.3\n"), call("DataLicense: CC0-1.0\n"), - call("SPDXID: SPDXRef-DOCUMENT\n"), - call("DocumentName: documentName\n"), - call("DocumentNamespace: https://some.namespace\n"), - call("DocumentComment: documentComment\n"), - call("\n## External Document References\n"), call( - "ExternalDocumentRef: DocumentRef-external https://namespace.com SHA1: 71c4025dd9897b364f3ebbb42c484ff43d00791c\n"), - call("\n"), call("## Creation Information\n"), - call("LicenseListVersion: 3.19\n"), - call("Creator: Person: creatorName (some@mail.com)\n"), - call("Created: 2022-12-01T00:00:00Z\n"), - call("CreatorComment: creatorComment\n")]), - (CreationInfo(spdx_version="SPDX-2.3", spdx_id="SPDXRef-DOCUMENT", creators=[actor_fixture()], - name="Test document", document_namespace="https://namespace.com", - created=datetime.datetime(2022, 3, 10)), - [call("SPDXVersion: SPDX-2.3\n"), call("DataLicense: CC0-1.0\n"), - call("SPDXID: SPDXRef-DOCUMENT\n"), call("DocumentName: Test document\n"), - call("DocumentNamespace: https://namespace.com\n"), call("\n"), - call("## Creation Information\n"), call("Creator: Person: actorName (some@mail.com)\n"), - call("Created: 2022-03-10T00:00:00Z\n")])]) +@pytest.mark.parametrize( + "creation_info, expected_calls", + [ + ( + creation_info_fixture(), + [ + call("SPDXVersion: SPDX-2.3\n"), + call("DataLicense: CC0-1.0\n"), + call("SPDXID: SPDXRef-DOCUMENT\n"), + call("DocumentName: documentName\n"), + call("DocumentNamespace: https://some.namespace\n"), + call("DocumentComment: documentComment\n"), + call("\n## External Document References\n"), + call( + "ExternalDocumentRef: DocumentRef-external https://namespace.com " + "SHA1: 71c4025dd9897b364f3ebbb42c484ff43d00791c\n" + ), + call("\n"), + call("## Creation Information\n"), + call("LicenseListVersion: 3.19\n"), + call("Creator: Person: creatorName (some@mail.com)\n"), + call("Created: 2022-12-01T00:00:00Z\n"), + call("CreatorComment: creatorComment\n"), + ], + ), + ( + CreationInfo( + spdx_version="SPDX-2.3", + spdx_id="SPDXRef-DOCUMENT", + creators=[actor_fixture()], + name="Test document", + document_namespace="https://namespace.com", + created=datetime.datetime(2022, 3, 10), + ), + [ + call("SPDXVersion: SPDX-2.3\n"), + call("DataLicense: CC0-1.0\n"), + call("SPDXID: SPDXRef-DOCUMENT\n"), + call("DocumentName: Test document\n"), + call("DocumentNamespace: https://namespace.com\n"), + call("\n"), + call("## Creation Information\n"), + call("Creator: Person: actorName (some@mail.com)\n"), + call("Created: 2022-03-10T00:00:00Z\n"), + ], + ), + ], +) def test_creation_info_writer(creation_info, expected_calls): mock: MagicMock = mock_open() with patch(f"{__name__}.open", mock, create=True): diff --git a/tests/spdx/writer/tagvalue/test_package_writer.py b/tests/spdx/writer/tagvalue/test_package_writer.py index 60570d269..ec5366617 100644 --- a/tests/spdx/writer/tagvalue/test_package_writer.py +++ b/tests/spdx/writer/tagvalue/test_package_writer.py @@ -8,10 +8,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from unittest.mock import patch, mock_open, call, MagicMock +from unittest.mock import MagicMock, call, mock_open, patch -from tests.spdx.fixtures import package_fixture from spdx.writer.tagvalue.package_writer import write_package +from tests.spdx.fixtures import package_fixture def test_package_writer(): @@ -25,33 +25,36 @@ def test_package_writer(): mock.assert_called_once_with("foo", "w") handle = mock() handle.write.assert_has_calls( - [call("## Package Information\n"), - call("PackageName: packageName\n"), - call("SPDXID: SPDXRef-Package\n"), - call("PackageVersion: 12.2\n"), - call("PackageFileName: ./packageFileName\n"), - call("PackageSupplier: Person: supplierName (some@mail.com)\n"), - call("PackageOriginator: Person: originatorName (some@mail.com)\n"), - call("PackageDownloadLocation: https://download.com\n"), - call("FilesAnalyzed: True\n"), - call("PackageVerificationCode: 85ed0817af83a24ad8da68c2b5094de69833983c (excludes: ./exclude.py)\n"), - call("PackageChecksum: SHA1: 71c4025dd9897b364f3ebbb42c484ff43d00791c\n"), - call("PackageHomePage: https://homepage.com\n"), - call("PackageSourceInfo: sourceInfo\n"), - call("PackageLicenseConcluded: MIT AND GPL-2.0-only\n"), - call("PackageLicenseInfoFromFiles: MIT\n"), - call("PackageLicenseInfoFromFiles: GPL-2.0-only\n"), - call('PackageLicenseInfoFromFiles: NOASSERTION\n'), - call("PackageLicenseDeclared: MIT AND GPL-2.0-only\n"), - call("PackageLicenseComments: packageLicenseComment\n"), - call("PackageCopyrightText: packageCopyrightText\n"), - call("PackageSummary: packageSummary\n"), - call("PackageDescription: packageDescription\n"), - call("PackageComment: packageComment\n"), - call("ExternalRef: PACKAGE-MANAGER maven-central org.apache.tomcat:tomcat:9.0.0.M4\n"), - call("ExternalRefComment: externalPackageRefComment\n"), - call("PackageAttributionText: packageAttributionText\n"), - call("PrimaryPackagePurpose: SOURCE\n"), - call("ReleaseDate: 2022-12-01T00:00:00Z\n"), - call("BuiltDate: 2022-12-02T00:00:00Z\n"), - call("ValidUntilDate: 2022-12-03T00:00:00Z\n")]) + [ + call("## Package Information\n"), + call("PackageName: packageName\n"), + call("SPDXID: SPDXRef-Package\n"), + call("PackageVersion: 12.2\n"), + call("PackageFileName: ./packageFileName\n"), + call("PackageSupplier: Person: supplierName (some@mail.com)\n"), + call("PackageOriginator: Person: originatorName (some@mail.com)\n"), + call("PackageDownloadLocation: https://download.com\n"), + call("FilesAnalyzed: True\n"), + call("PackageVerificationCode: 85ed0817af83a24ad8da68c2b5094de69833983c (excludes: ./exclude.py)\n"), + call("PackageChecksum: SHA1: 71c4025dd9897b364f3ebbb42c484ff43d00791c\n"), + call("PackageHomePage: https://homepage.com\n"), + call("PackageSourceInfo: sourceInfo\n"), + call("PackageLicenseConcluded: MIT AND GPL-2.0-only\n"), + call("PackageLicenseInfoFromFiles: MIT\n"), + call("PackageLicenseInfoFromFiles: GPL-2.0-only\n"), + call("PackageLicenseInfoFromFiles: NOASSERTION\n"), + call("PackageLicenseDeclared: MIT AND GPL-2.0-only\n"), + call("PackageLicenseComments: packageLicenseComment\n"), + call("PackageCopyrightText: packageCopyrightText\n"), + call("PackageSummary: packageSummary\n"), + call("PackageDescription: packageDescription\n"), + call("PackageComment: packageComment\n"), + call("ExternalRef: PACKAGE-MANAGER maven-central org.apache.tomcat:tomcat:9.0.0.M4\n"), + call("ExternalRefComment: externalPackageRefComment\n"), + call("PackageAttributionText: packageAttributionText\n"), + call("PrimaryPackagePurpose: SOURCE\n"), + call("ReleaseDate: 2022-12-01T00:00:00Z\n"), + call("BuiltDate: 2022-12-02T00:00:00Z\n"), + call("ValidUntilDate: 2022-12-03T00:00:00Z\n"), + ] + ) diff --git a/tests/spdx/writer/tagvalue/test_tagvalue_writer.py b/tests/spdx/writer/tagvalue/test_tagvalue_writer.py index 1936326ab..bdb442303 100644 --- a/tests/spdx/writer/tagvalue/test_tagvalue_writer.py +++ b/tests/spdx/writer/tagvalue/test_tagvalue_writer.py @@ -14,8 +14,8 @@ import pytest from spdx.parser.tagvalue import tagvalue_parser -from tests.spdx.fixtures import document_fixture from spdx.writer.tagvalue.tagvalue_writer import write_document_to_file +from tests.spdx.fixtures import document_fixture @pytest.fixture diff --git a/tests/spdx/writer/tagvalue/test_tagvalue_writer_helper_functions.py b/tests/spdx/writer/tagvalue/test_tagvalue_writer_helper_functions.py index 300a3fd33..a1bb05f9d 100644 --- a/tests/spdx/writer/tagvalue/test_tagvalue_writer_helper_functions.py +++ b/tests/spdx/writer/tagvalue/test_tagvalue_writer_helper_functions.py @@ -10,7 +10,7 @@ # limitations under the License. from spdx.model.relationship import RelationshipType from spdx.writer.tagvalue.tagvalue_writer_helper_functions import scan_relationships -from tests.spdx.fixtures import package_fixture, file_fixture, relationship_fixture +from tests.spdx.fixtures import file_fixture, package_fixture, relationship_fixture def test_scan_relationships(): @@ -20,14 +20,21 @@ def test_scan_relationships(): file_spdx_id = "SPDXRef-File" files = [file_fixture(spdx_id=file_spdx_id)] relationships = [ - relationship_fixture(spdx_element_id=first_package_spdx_id, relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id=file_spdx_id, comment=None), - relationship_fixture(spdx_element_id=second_package_spdx_id, relationship_type=RelationshipType.CONTAINS, - related_spdx_element_id=file_spdx_id, comment=None) + relationship_fixture( + spdx_element_id=first_package_spdx_id, + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id=file_spdx_id, + comment=None, + ), + relationship_fixture( + spdx_element_id=second_package_spdx_id, + relationship_type=RelationshipType.CONTAINS, + related_spdx_element_id=file_spdx_id, + comment=None, + ), ] relationships_to_write, contained_files_by_package_id = scan_relationships(relationships, packages, files) assert relationships_to_write == [] - assert contained_files_by_package_id == {first_package_spdx_id: files, - second_package_spdx_id: files} + assert contained_files_by_package_id == {first_package_spdx_id: files, second_package_spdx_id: files}