diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 80c86fc..e3f5030 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog ========= +v30.4.5 - 2026-03-03 +-------------------- + +This is a minor bugfix release: + +- Fix validate() to properly report errors for invalid expressions with + trailing operators (e.g. "GPL-3.0-or-later AND"). + v30.4.4 - 2025-01-10 -------------------- diff --git a/tests/test_license_expression.py b/tests/test_license_expression.py index c3b0999..7af4175 100644 --- a/tests/test_license_expression.py +++ b/tests/test_license_expression.py @@ -2537,6 +2537,45 @@ def test_validation_invalid_license_exception_strict_false(self): assert result.errors == [] assert result.invalid_symbols == [] + def test_validate_trailing_and_operator(self): + result = self.licensing.validate("GPL-2.0-or-later AND") + assert result.original_expression == "GPL-2.0-or-later AND" + assert not result.normalized_expression + assert len(result.errors) == 1 + assert "AND" in result.errors[0] + + def test_validate_trailing_or_operator(self): + result = self.licensing.validate("GPL-2.0-or-later OR") + assert result.original_expression == "GPL-2.0-or-later OR" + assert not result.normalized_expression + assert len(result.errors) == 1 + assert "OR" in result.errors[0] + + def test_validate_trailing_with_operator(self): + result = self.licensing.validate("GPL-2.0-or-later WITH") + assert result.original_expression == "GPL-2.0-or-later WITH" + assert not result.normalized_expression + assert len(result.errors) == 1 + + def test_validate_multiple_trailing_operators(self): + result = self.licensing.validate("GPL-2.0-or-later AND MIT OR") + assert result.original_expression == "GPL-2.0-or-later AND MIT OR" + assert not result.normalized_expression + assert len(result.errors) == 1 + assert "OR" in result.errors[0] + + def test_validate_leading_operator(self): + result = self.licensing.validate("AND MIT") + assert result.original_expression == "AND MIT" + assert not result.normalized_expression + assert len(result.errors) == 1 + + def test_validate_only_operators(self): + result = self.licensing.validate("AND OR") + assert result.original_expression == "AND OR" + assert not result.normalized_expression + assert len(result.errors) == 1 + class UtilTest(TestCase): test_data_dir = join(dirname(__file__), "data")