diff --git a/tests/_data/own/json/1.2/bom_with_mixed_licenses.json b/tests/_data/own/json/1.2/bom_with_mixed_licenses.json new file mode 100644 index 00000000..da4d3c54 --- /dev/null +++ b/tests/_data/own/json/1.2/bom_with_mixed_licenses.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "metadata": { + "component": { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}} + ], + "name": "app", + "type": "application" + }, + "licenses": [ + {"license": {"name": "foo license"}}, + {"license": {"id": "MIT"}}, + {"expression": "MIT OR Apache-2.0"} + ] + }, + "components": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"} + ], + "name": "comp", + "type": "library" + } + ], + "services": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}} + ], + "name": "serv" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1337 +} diff --git a/tests/_data/own/json/1.3/bom_with_mixed_licenses.json b/tests/_data/own/json/1.3/bom_with_mixed_licenses.json new file mode 100644 index 00000000..da4d3c54 --- /dev/null +++ b/tests/_data/own/json/1.3/bom_with_mixed_licenses.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "metadata": { + "component": { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}} + ], + "name": "app", + "type": "application" + }, + "licenses": [ + {"license": {"name": "foo license"}}, + {"license": {"id": "MIT"}}, + {"expression": "MIT OR Apache-2.0"} + ] + }, + "components": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"} + ], + "name": "comp", + "type": "library" + } + ], + "services": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}} + ], + "name": "serv" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1337 +} diff --git a/tests/_data/own/json/1.4/bom_with_mixed_licenses.json b/tests/_data/own/json/1.4/bom_with_mixed_licenses.json new file mode 100644 index 00000000..da4d3c54 --- /dev/null +++ b/tests/_data/own/json/1.4/bom_with_mixed_licenses.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "metadata": { + "component": { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}} + ], + "name": "app", + "type": "application" + }, + "licenses": [ + {"license": {"name": "foo license"}}, + {"license": {"id": "MIT"}}, + {"expression": "MIT OR Apache-2.0"} + ] + }, + "components": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"id": "MIT"}}, + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"} + ], + "name": "comp", + "type": "library" + } + ], + "services": [ + { + "description": "before CDX 1.5 it was allowed to mix `expression` and `license`", + "licenses": [ + {"license": {"name": "foo license"}}, + {"expression": "MIT OR Apache-2.0"}, + {"license": {"id": "MIT"}} + ], + "name": "serv" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1337 +} diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py index fe9ff177..c3b670d0 100644 --- a/tests/test_deserialize_json.py +++ b/tests/test_deserialize_json.py @@ -17,15 +17,17 @@ from json import loads as json_loads +from os.path import join from typing import Any, Callable from unittest import TestCase from unittest.mock import patch -from ddt import ddt, named_data +from ddt import data, ddt, named_data from cyclonedx.model.bom import Bom +from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression, LicenseRepository from cyclonedx.schema import OutputFormat, SchemaVersion -from tests import DeepCompareMixin, SnapshotMixin, mksname, uuid_generator +from tests import OWN_DATA_DIRECTORY, DeepCompareMixin, SnapshotMixin, mksname, uuid_generator from tests._data.models import all_get_bom_funct_valid, all_get_bom_funct_with_incomplete_deps @@ -35,7 +37,7 @@ class TestDeserializeJson(TestCase, SnapshotMixin, DeepCompareMixin): @named_data(*all_get_bom_funct_valid) @patch('cyclonedx.model.ThisTool._version', 'TESTING') @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4)) - def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None: + def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None: # only latest schema will have all data populated in serialized form snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.JSON) expected = get_bom() @@ -43,3 +45,30 @@ def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None: bom = Bom.from_json(json) self.assertBomDeepEqual(expected, bom, fuzzy_deps=get_bom in all_get_bom_funct_with_incomplete_deps) + + @data(SchemaVersion.V1_4, SchemaVersion.V1_3, SchemaVersion.V1_2) + def test_mixed_licenses_before15(self, sv: SchemaVersion) -> None: + # before CDX 1.5 it was allowed to mix `expression` and `license` + def test(ls: LicenseRepository) -> None: + self.assertEqual(3, len(ls)) + expression: LicenseExpression = next(( + li for li in ls if isinstance(li, LicenseExpression) + ), None) + with_id: DisjunctiveLicense = next(( + li for li in ls if isinstance(li, DisjunctiveLicense) and li.id is not None + ), None) + with_name: DisjunctiveLicense = next(( + li for li in ls if isinstance(li, DisjunctiveLicense) and li.name is not None + ), None) + self.assertEqual('MIT OR Apache-2.0', expression.value) + self.assertEqual('MIT', with_id.id) + self.assertEqual('foo license', with_name.name) + + json_file = join(OWN_DATA_DIRECTORY, 'json', sv.to_version(), 'bom_with_mixed_licenses.json') + with open(json_file) as f: + json = json_loads(f.read()) + bom: Bom = Bom.from_json(json) + test(bom.metadata.licenses) + test(bom.metadata.component.licenses) + test(list(bom.components)[0].licenses) + test(list(bom.services)[0].licenses) diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py index 3b2652d8..d4c5688a 100644 --- a/tests/test_deserialize_xml.py +++ b/tests/test_deserialize_xml.py @@ -34,7 +34,7 @@ class TestDeserializeXml(TestCase, SnapshotMixin, DeepCompareMixin): @named_data(*all_get_bom_funct_valid) @patch('cyclonedx.model.ThisTool._version', 'TESTING') @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4)) - def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None: + def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None: # only latest schema will have all data populated in serialized form snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.XML) expected = get_bom()