Skip to content

tests: revisit spdx.is_expression() #782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 60 additions & 24 deletions tests/test_spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,62 @@
from json import load as json_load
from unittest import TestCase

from ddt import data, ddt, idata, unpack
from ddt import ddt, idata, unpack

from cyclonedx import spdx
from cyclonedx.schema._res import SPDX_JSON

# rework access
with open(SPDX_JSON) as spdx_schema:
KNOWN_SPDX_IDS = json_load(spdx_schema)['enum']
KNOWN_SPDX_IDS = set(json_load(spdx_schema)['enum'])

# for valid test data see the spec: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
VALID_EXPRESSIONS = {
# region Simple license expressions
'CDDL-1.0',
# region not supported yet #110 - https://github.com/aboutcode-org/license-expression/issues/110
# 'CDDL-1.0+',
# endregion region not supported yet #110
# region not supported yet #109 - https://github.com/aboutcode-org/license-expression/issues/109
# 'LicenseRef-23',
# 'LicenseRef-MIT-Style-1',
# 'DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2',
# endregion region not supported yet #109
# endregion Simple license expressions
# region Composite license expressions
'LGPL-2.1-only OR MIT',
'MIT or LGPL-2.1-only',
'(MIT OR LGPL-2.1-only)',
'LGPL-2.1-only OR MIT OR BSD-3-Clause',
'LGPL-2.1-only AND MIT',
'MIT AND LGPL-2.1-only',
'MIT and LGPL-2.1-only',
'(MIT AND LGPL-2.1-only)',
'LGPL-2.1-only AND MIT AND BSD-2-Clause',
'GPL-2.0-or-later WITH Bison-exception-2.2',
'LGPL-2.1-only OR BSD-3-Clause AND MIT',
'MIT AND (LGPL-2.1-or-later OR BSD-3-Clause)',
# endregion Composite license expressions
# region examples from CDX spec
'Apache-2.0 AND (MIT OR GPL-2.0-only)',
'GPL-3.0-only WITH Classpath-exception-2.0',
# endregion examples from CDX spec
}

INVALID_EXPRESSIONS = {
'MIT AND Apache-2.0 OR something-unknown'
'something invalid',
'(c) John Doe',
'Apache License, Version 2.0',
}

VALID_COMPOUND_EXPRESSIONS = {
# for valid test data see the spec: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/
'(MIT AND Apache-2.0)',
'BSD-2-Clause OR Apache-2.0',
UNKNOWN_SPDX_IDS = {
'',
'something unsupported', 'something unfixable',
'Apache 2.0',
'LicenseRef-custom-identifier',
*(VALID_EXPRESSIONS - KNOWN_SPDX_IDS),
*INVALID_EXPRESSIONS,
}


Expand All @@ -43,12 +86,11 @@ def test_positive(self, supported_value: str) -> None:
actual = spdx.is_supported_id(supported_value)
self.assertTrue(actual)

@data(
'something unsupported',
# somehow case-twisted values
'MiT',
'mit',
)
@idata(chain(UNKNOWN_SPDX_IDS, (
# region somehow case-twisted values
'MiT', 'mit',
# endregion somehow case-twisted values
)))
def test_negative(self, unsupported_value: str) -> None:
actual = spdx.is_supported_id(unsupported_value)
self.assertFalse(actual)
Expand All @@ -60,37 +102,31 @@ class TestSpdxFixup(TestCase):
@idata(chain(
# original value
((v, v) for v in KNOWN_SPDX_IDS),
# somehow case-twisted values
# region somehow case-twisted values
((v.lower(), v) for v in KNOWN_SPDX_IDS),
((v.upper(), v) for v in KNOWN_SPDX_IDS)
# endregion somehow case-twisted values
))
@unpack
def test_positive(self, fixable: str, expected_fixed: str) -> None:
actual = spdx.fixup_id(fixable)
self.assertEqual(expected_fixed, actual)

@data(
'something unfixable',
)
@idata(UNKNOWN_SPDX_IDS)
def test_negative(self, unfixable: str) -> None:
actual = spdx.fixup_id(unfixable)
self.assertIsNone(actual)


@ddt
class TestSpdxIsCompoundExpression(TestCase):
class TestSpdxIsExpression(TestCase):

@idata(VALID_COMPOUND_EXPRESSIONS)
@idata(VALID_EXPRESSIONS)
def test_positive(self, valid_expression: str) -> None:
actual = spdx.is_expression(valid_expression)
self.assertTrue(actual)

@data(
'MIT AND Apache-2.0 OR something-unknown'
'something invalid',
'(c) John Doe',
'Apache License, Version 2.0'
)
@idata(INVALID_EXPRESSIONS)
def test_negative(self, invalid_expression: str) -> None:
actual = spdx.is_expression(invalid_expression)
self.assertFalse(actual)