diff --git a/src/univers/version_range.py b/src/univers/version_range.py index c50bc87c..9d3d3e4a 100644 --- a/src/univers/version_range.py +++ b/src/univers/version_range.py @@ -67,6 +67,10 @@ class VersionRange: constraints = attr.ib(type=tuple, default=attr.Factory(tuple)) def __attrs_post_init__(self, *args, **kwargs): + if not self.constraints: + raise ValueError( + f"{self.__class__.__name__} requires at least one VersionConstraint." + ) constraints = tuple(sorted(self.constraints)) # Notes: setattr is used because this is an immutable frozen instance. # See https://www.attrs.org/en/stable/init.html?#post-init diff --git a/tests/__init__.py b/tests/__init__.py index c5f86f4a..33c0f81d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -5,6 +5,7 @@ # Visit https://aboutcode.org and https://github.com/aboutcode-org/univers for support and download. from typing import NamedTuple +from typing import Optional from typing import Union @@ -14,13 +15,26 @@ class SchemaDrivenVersTest(NamedTuple): input: dict expected_output: Union[list, bool] description: str = "" + # name of the exception class expected to be raised while computing the + # result, for test cases whose input is invalid + expected_error: Optional[str] = None @classmethod def from_data(cls, data: dict): return cls(**data) def assert_result(self): - assert self.result == self.expected_output + if self.expected_error: + try: + self.result + except Exception as e: + assert type(e).__name__ == self.expected_error + else: + raise AssertionError( + f"{self.expected_error} not raised for input: {self.input!r}" + ) + else: + assert self.result == self.expected_output @property def result(self): diff --git a/tests/data/schema/range/conan_range_from_native.json b/tests/data/schema/range/conan_range_from_native.json index fb8a3ddd..fcc94bce 100644 --- a/tests/data/schema/range/conan_range_from_native.json +++ b/tests/data/schema/range/conan_range_from_native.json @@ -1137,7 +1137,8 @@ "native_range": "", "scheme": "conan" }, - "expected_output": "vers:conan/" + "expected_output": null, + "expected_error": "ValueError" }, { "description": "Construct VERS range from native conan range.", @@ -1437,7 +1438,8 @@ "native_range": "", "scheme": "conan" }, - "expected_output": "vers:conan/" + "expected_output": null, + "expected_error": "ValueError" }, { "description": "Construct VERS range from native conan range.", diff --git a/tests/data/schema/range/gitlab/conan_gitlab_range_from_native.json b/tests/data/schema/range/gitlab/conan_gitlab_range_from_native.json index 763407a2..8a15ecba 100644 --- a/tests/data/schema/range/gitlab/conan_gitlab_range_from_native.json +++ b/tests/data/schema/range/gitlab/conan_gitlab_range_from_native.json @@ -1137,7 +1137,8 @@ "native_range": "", "scheme": "conan" }, - "expected_output": "vers:conan/" + "expected_output": null, + "expected_error": "ValueError" }, { "description": "Construct VERS range from GitLab native conan range.", @@ -1437,7 +1438,8 @@ "native_range": "", "scheme": "conan" }, - "expected_output": "vers:conan/" + "expected_output": null, + "expected_error": "ValueError" }, { "description": "Construct VERS range from GitLab native conan range.", diff --git a/tests/test_version_range.py b/tests/test_version_range.py index b2cb3c4a..0d78ee11 100644 --- a/tests/test_version_range.py +++ b/tests/test_version_range.py @@ -458,3 +458,13 @@ def test_version_range_lexicographic(): assert LexicographicVersion(-123) in VersionRange.from_string("vers:lexicographic/<~") assert LexicographicVersion(None) in VersionRange.from_string("vers:lexicographic/*") assert LexicographicVersion("ABC") in VersionRange.from_string("vers:lexicographic/>abc|<=None") + + +def test_version_range_with_empty_constraints_is_invalid(): + # https://github.com/aboutcode-org/univers/issues/203 + with pytest.raises(ValueError): + VersionRange(constraints=[]) + with pytest.raises(ValueError): + RANGE_CLASS_BY_SCHEMES["apache"](constraints=[]) + with pytest.raises(ValueError): + VersionRange.from_string("vers:apache/")