diff --git a/cyclonedx/factory/license.py b/cyclonedx/factory/license.py index d6446569..c5e0ffd1 100644 --- a/cyclonedx/factory/license.py +++ b/cyclonedx/factory/license.py @@ -21,7 +21,7 @@ if TYPE_CHECKING: # pragma: no cover from ..model import AttachedText, XsUri - from ..model.license import License + from ..model.license import License, LicenseAcknowledgement class LicenseFactory: @@ -29,19 +29,30 @@ class LicenseFactory: def make_from_string(self, value: str, *, license_text: Optional['AttachedText'] = None, - license_url: Optional['XsUri'] = None) -> 'License': + license_url: Optional['XsUri'] = None, + license_acknowledgement: Optional['LicenseAcknowledgement'] = None + ) -> 'License': """Make a :class:`cyclonedx.model.license.License` from a string.""" try: - return self.make_with_id(value, text=license_text, url=license_url) + return self.make_with_id(value, + text=license_text, + url=license_url, + acknowledgement=license_acknowledgement) except InvalidSpdxLicenseException: pass try: - return self.make_with_expression(value) + return self.make_with_expression(value, + acknowledgement=license_acknowledgement) except InvalidLicenseExpressionException: pass - return self.make_with_name(value, text=license_text, url=license_url) + return self.make_with_name(value, + text=license_text, + url=license_url, + acknowledgement=license_acknowledgement) - def make_with_expression(self, expression: str) -> LicenseExpression: + def make_with_expression(self, expression: str, *, + acknowledgement: Optional['LicenseAcknowledgement'] = None + ) -> LicenseExpression: """Make a :class:`cyclonedx.model.license.LicenseExpression` with a compound expression. Utilizes :func:`cyclonedx.spdx.is_compound_expression`. @@ -49,12 +60,14 @@ def make_with_expression(self, expression: str) -> LicenseExpression: :raises InvalidLicenseExpressionException: if param `value` is not known/supported license expression """ if is_spdx_compound_expression(expression): - return LicenseExpression(expression) + return LicenseExpression(expression, acknowledgement=acknowledgement) raise InvalidLicenseExpressionException(expression) def make_with_id(self, spdx_id: str, *, text: Optional['AttachedText'] = None, - url: Optional['XsUri'] = None) -> DisjunctiveLicense: + url: Optional['XsUri'] = None, + acknowledgement: Optional['LicenseAcknowledgement'] = None + ) -> DisjunctiveLicense: """Make a :class:`cyclonedx.model.license.DisjunctiveLicense` from an SPDX-ID. :raises InvalidSpdxLicenseException: if param `spdx_id` was not known/supported SPDX-ID @@ -62,10 +75,12 @@ def make_with_id(self, spdx_id: str, *, spdx_license_id = spdx_fixup(spdx_id) if spdx_license_id is None: raise InvalidSpdxLicenseException(spdx_id) - return DisjunctiveLicense(id=spdx_license_id, text=text, url=url) + return DisjunctiveLicense(id=spdx_license_id, text=text, url=url, acknowledgement=acknowledgement) def make_with_name(self, name: str, *, text: Optional['AttachedText'] = None, - url: Optional['XsUri'] = None) -> DisjunctiveLicense: + url: Optional['XsUri'] = None, + acknowledgement: Optional['LicenseAcknowledgement'] = None + ) -> DisjunctiveLicense: """Make a :class:`cyclonedx.model.license.DisjunctiveLicense` with a name.""" - return DisjunctiveLicense(name=name, text=text, url=url) + return DisjunctiveLicense(name=name, text=text, url=url, acknowledgement=acknowledgement) diff --git a/cyclonedx/model/license.py b/cyclonedx/model/license.py index a926ad0c..d1977aae 100644 --- a/cyclonedx/model/license.py +++ b/cyclonedx/model/license.py @@ -250,6 +250,7 @@ class LicenseExpression: def __init__( self, value: str, + # *, # all optional args are intended to be keyword-args acknowledgement: Optional[LicenseAcknowledgement] = None ) -> None: self._value = value diff --git a/tests/test_factory_license.py b/tests/test_factory_license.py index 7d21a1d3..05e6bd3a 100644 --- a/tests/test_factory_license.py +++ b/tests/test_factory_license.py @@ -21,7 +21,7 @@ from cyclonedx.exception.factory import InvalidLicenseExpressionException, InvalidSpdxLicenseException from cyclonedx.factory.license import LicenseFactory from cyclonedx.model import AttachedText, XsUri -from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression +from cyclonedx.model.license import DisjunctiveLicense, LicenseAcknowledgement, LicenseExpression class TestFactoryLicense(unittest.TestCase): @@ -29,41 +29,52 @@ class TestFactoryLicense(unittest.TestCase): def test_make_from_string_with_id(self) -> None: text = unittest.mock.NonCallableMock(spec=AttachedText) url = unittest.mock.NonCallableMock(spec=XsUri) - expected = DisjunctiveLicense(id='bar', text=text, url=url) + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = DisjunctiveLicense(id='bar', text=text, url=url, acknowledgement=acknowledgement) with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value='bar'), \ unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True): - actual = LicenseFactory().make_from_string('foo', license_text=text, license_url=url) + actual = LicenseFactory().make_from_string('foo', + license_text=text, + license_url=url, + license_acknowledgement=acknowledgement) self.assertEqual(expected, actual) def test_make_from_string_with_name(self) -> None: text = unittest.mock.NonCallableMock(spec=AttachedText) url = unittest.mock.NonCallableMock(spec=XsUri) - expected = DisjunctiveLicense(name='foo', text=text, url=url) + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = DisjunctiveLicense(name='foo', text=text, url=url, acknowledgement=acknowledgement) with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value=None), \ unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=False): - actual = LicenseFactory().make_from_string('foo', license_text=text, license_url=url) + actual = LicenseFactory().make_from_string('foo', + license_text=text, + license_url=url, + license_acknowledgement=acknowledgement) self.assertEqual(expected, actual) def test_make_from_string_with_expression(self) -> None: - expected = LicenseExpression('foo') + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = LicenseExpression('foo', acknowledgement=acknowledgement) with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value=None), \ unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True): - actual = LicenseFactory().make_from_string('foo') + actual = LicenseFactory().make_from_string('foo', + license_acknowledgement=acknowledgement) self.assertEqual(expected, actual) def test_make_with_id(self) -> None: text = unittest.mock.NonCallableMock(spec=AttachedText) url = unittest.mock.NonCallableMock(spec=XsUri) - expected = DisjunctiveLicense(id='bar', text=text, url=url) + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = DisjunctiveLicense(id='bar', text=text, url=url, acknowledgement=acknowledgement) with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value='bar'): - actual = LicenseFactory().make_with_id(spdx_id='foo', text=text, url=url) + actual = LicenseFactory().make_with_id(spdx_id='foo', text=text, url=url, acknowledgement=acknowledgement) self.assertEqual(expected, actual) @@ -75,14 +86,16 @@ def test_make_with_id_raises(self) -> None: def test_make_with_name(self) -> None: text = unittest.mock.NonCallableMock(spec=AttachedText) url = unittest.mock.NonCallableMock(spec=XsUri) - expected = DisjunctiveLicense(name='foo', text=text, url=url) - actual = LicenseFactory().make_with_name(name='foo', text=text, url=url) + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = DisjunctiveLicense(name='foo', text=text, url=url, acknowledgement=acknowledgement) + actual = LicenseFactory().make_with_name(name='foo', text=text, url=url, acknowledgement=acknowledgement) self.assertEqual(expected, actual) def test_make_with_expression(self) -> None: - expected = LicenseExpression('foo') + acknowledgement = unittest.mock.NonCallableMock(spec=LicenseAcknowledgement) + expected = LicenseExpression('foo', acknowledgement=acknowledgement) with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True): - actual = LicenseFactory().make_with_expression(expression='foo') + actual = LicenseFactory().make_with_expression(expression='foo', acknowledgement=acknowledgement) self.assertEqual(expected, actual) def test_make_with_expression_raises(self) -> None: