diff --git a/src/validataclass_search_queries/validators/__init__.py b/src/validataclass_search_queries/validators/__init__.py index 845aab1..8914157 100644 --- a/src/validataclass_search_queries/validators/__init__.py +++ b/src/validataclass_search_queries/validators/__init__.py @@ -4,9 +4,7 @@ Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. """ -from .multi_select_validator import ( - MultiSelectValidator, - MultiSelectIntegerValidator, - MultiSelectAnyOfValidator, - MultiSelectEnumValidator, -) +from .multi_select_any_of_validator import MultiSelectAnyOfValidator +from .multi_select_enum_validator import MultiSelectEnumValidator +from .multi_select_integer_validator import MultiSelectIntegerValidator +from .multi_select_validator import MultiSelectValidator diff --git a/src/validataclass_search_queries/validators/multi_select_any_of_validator.py b/src/validataclass_search_queries/validators/multi_select_any_of_validator.py new file mode 100644 index 0000000..1ea57af --- /dev/null +++ b/src/validataclass_search_queries/validators/multi_select_any_of_validator.py @@ -0,0 +1,49 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +from collections.abc import Iterable +from typing import Any + +from validataclass.validators import AnyOfValidator + +from .multi_select_validator import MultiSelectValidator + +__all__ = [ + 'MultiSelectAnyOfValidator', +] + + +class MultiSelectAnyOfValidator(MultiSelectValidator): + """ + Validator for multi-select search parameters that only allows a specified set of values. + + Shortcut for a `MultiSelectValidator` with an `AnyOfValidator`. + """ + + def __init__( + self, + # AnyOfValidator settings + allowed_values: Iterable[Any], + # TODO: case_insensitive is deprecated in validataclass and must be removed in a future version. + case_sensitive: bool | None = None, + case_insensitive: bool | None = None, + *, + # List settings + delimiter: str = ',', + max_length: int | None = None, + ): + """ + Create a `MultiSelectValidator` using an `AnyOfValidator` to validate the items. + """ + super().__init__( + AnyOfValidator( + allowed_values, + case_sensitive=case_sensitive, + case_insensitive=case_insensitive, + ), + delimiter=delimiter, + max_length=max_length, + ) diff --git a/src/validataclass_search_queries/validators/multi_select_enum_validator.py b/src/validataclass_search_queries/validators/multi_select_enum_validator.py new file mode 100644 index 0000000..689de06 --- /dev/null +++ b/src/validataclass_search_queries/validators/multi_select_enum_validator.py @@ -0,0 +1,54 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +from collections.abc import Iterable +from enum import Enum +from typing import Any, TypeVar + +from validataclass.validators import EnumValidator + +from .multi_select_validator import MultiSelectValidator + +__all__ = [ + 'MultiSelectEnumValidator', +] + +T_Enum = TypeVar('T_Enum', bound=Enum) + + +class MultiSelectEnumValidator(MultiSelectValidator[T_Enum]): + """ + Validator for multi-select search parameters that allows values from an Enum class. + + Shortcut for a `MultiSelectValidator` with an `EnumValidator`. + """ + + def __init__( + self, + # EnumValidator settings + enum_cls: type[Enum], + *, + allowed_values: Iterable[Any] | None = None, + # TODO: case_insensitive is deprecated in validataclass and must be removed in a future version. + case_sensitive: bool | None = None, + case_insensitive: bool | None = None, + # List settings + delimiter: str = ',', + max_length: int | None = None, + ): + """ + Create a `MultiSelectValidator` using an `EnumValidator` to validate the items. + """ + super().__init__( + EnumValidator( + enum_cls, + allowed_values=allowed_values, + case_sensitive=case_sensitive, + case_insensitive=case_insensitive, + ), + delimiter=delimiter, + max_length=max_length, + ) diff --git a/src/validataclass_search_queries/validators/multi_select_integer_validator.py b/src/validataclass_search_queries/validators/multi_select_integer_validator.py new file mode 100644 index 0000000..568f47d --- /dev/null +++ b/src/validataclass_search_queries/validators/multi_select_integer_validator.py @@ -0,0 +1,45 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +from validataclass.validators import IntegerValidator + +from .multi_select_validator import MultiSelectValidator + +__all__ = [ + 'MultiSelectIntegerValidator', +] + + +class MultiSelectIntegerValidator(MultiSelectValidator[int]): + """ + Validator for multi-select search parameters that only allows integers. + + Shortcut for a `MultiSelectValidator` with an `IntegerValidator`. + """ + + def __init__( + self, + *, + # Integer validator settings + min_value: int | None = IntegerValidator.DEFAULT_MIN_VALUE, + max_value: int | None = IntegerValidator.DEFAULT_MAX_VALUE, + # List settings + delimiter: str = ',', + max_length: int | None = None, + ): + """ + Create a `MultiSelectValidator` using an `IntegerValidator` to validate the items. + """ + # Initialize base MultiSelectValidator and IntegerValidator + super().__init__( + IntegerValidator( + min_value=min_value, + max_value=max_value, + allow_strings=True, + ), + delimiter=delimiter, + max_length=max_length, + ) diff --git a/src/validataclass_search_queries/validators/multi_select_validator.py b/src/validataclass_search_queries/validators/multi_select_validator.py index a7f3842..7467e53 100644 --- a/src/validataclass_search_queries/validators/multi_select_validator.py +++ b/src/validataclass_search_queries/validators/multi_select_validator.py @@ -4,27 +4,16 @@ Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. """ -from collections.abc import Iterable -from enum import Enum -from typing import Any - -from validataclass.validators import ( - AnyOfValidator, - EnumValidator, - IntegerValidator, - ListValidator, - Validator, - T_ListItem, - T_Enum, -) +from typing import Any, TypeVar + +from validataclass.validators import ListValidator, Validator __all__ = [ 'MultiSelectValidator', - 'MultiSelectIntegerValidator', - 'MultiSelectAnyOfValidator', - 'MultiSelectEnumValidator', ] +T_ListItem = TypeVar('T_ListItem') + # TODO: Base on StringToListValidator from upstream validataclass when implemented. class MultiSelectValidator(ListValidator[T_ListItem]): @@ -34,7 +23,7 @@ class MultiSelectValidator(ListValidator[T_ListItem]): Accepts a string as input, splits it to a list of strings using a delimiter (defaults to ",") and validates the resulting list using a specified item validator (based on the `ListValidator`). - The validator assumes a minimum list length of 1. A maximum list length can be optionally specified using `max_length`. + The validator assumes a minimum list length of 1. A maximum length can be optionally specified using `max_length`. The item validator can be any validator that accepts strings as input. @@ -60,12 +49,12 @@ def __init__( max_length: int | None = None, ): """ - Create a MultiSelectValidator with a given item validator. + Create a `MultiSelectValidator` with a given item validator. Parameters: - item_validator: Validator, used to validate the items in the list (required) - delimiter: String, specifies the string that separates the list items in the input string (default: ',') - max_length: Integer, specifies maximum length of input list (default: None, no maximum length) + `item_validator`: `Validator`, used to validate the items in the list (required) + `delimiter`: `str`, specifies the string that separates the list items in the input string (default: ',') + `max_length`: `int`, specifies maximum length of input list (default: `None`, no maximum length) """ # Initialize base ListValidator super().__init__( @@ -87,96 +76,6 @@ def validate(self, input_data: Any, **kwargs) -> list[T_ListItem]: else: # Split string to list value_list = input_data.split(self.delimiter) + # Validate list items return super().validate(value_list, **kwargs) - - -class MultiSelectIntegerValidator(MultiSelectValidator[int]): - """ - Validator for multi-select search parameters that only allows integers. - - Shortcut for a `MultiSelectValidator` with an `IntegerValidator`. - """ - - def __init__( - self, - *, - # Integer validator settings - min_value: int | None = IntegerValidator.DEFAULT_MIN_VALUE, - max_value: int | None = IntegerValidator.DEFAULT_MAX_VALUE, - # List settings - delimiter: str = ',', - max_length: int | None = None, - ): - """ - Create a MultiSelectValidator using a IntegerValidator to validate the items. - """ - # Initialize base MultiSelectValidator and IntegerValidator - super().__init__( - IntegerValidator( - min_value=min_value, - max_value=max_value, - allow_strings=True, - ), - delimiter=delimiter, - max_length=max_length, - ) - - -class MultiSelectAnyOfValidator(MultiSelectValidator): - """ - Validator for multi-select search parameters that only allows a specified set of values. - - Shortcut for a `MultiSelectValidator` with an `AnyOfValidator`. - """ - - def __init__( - self, - # AnyOfValidator settings - allowed_values: Iterable[Any], - # TODO: case_insensitive is deprecated in validataclass and must be removed in a future version. - case_sensitive: bool | None = None, - case_insensitive: bool | None = None, - *, - # List settings - delimiter: str = ',', - max_length: int | None = None, - ): - """ - Create a MultiSelectValidator using a AnyOfValidator to validate the items. - """ - super().__init__( - AnyOfValidator(allowed_values, case_sensitive=case_sensitive, case_insensitive=case_insensitive), - delimiter=delimiter, - max_length=max_length, - ) - - -class MultiSelectEnumValidator(MultiSelectValidator[T_Enum]): - """ - Validator for multi-select search parameters that allows values from an Enum class. - - Shortcut for a `MultiSelectValidator` with an `EnumValidator`. - """ - - def __init__( - self, - # EnumValidator settings - enum_cls: type[Enum], - *, - allowed_values: Iterable[Any] | None = None, - # TODO: case_insensitive is deprecated in validataclass and must be removed in a future version. - case_sensitive: bool | None = None, - case_insensitive: bool | None = None, - # List settings - delimiter: str = ',', - max_length: int | None = None, - ): - """ - Create a MultiSelectValidator using a EnumValidator to validate the items. - """ - super().__init__( - EnumValidator(enum_cls, allowed_values=allowed_values, case_sensitive=case_sensitive, case_insensitive=case_insensitive), - delimiter=delimiter, - max_length=max_length, - ) diff --git a/tests/unit/validators/multi_select_any_of_validator_test.py b/tests/unit/validators/multi_select_any_of_validator_test.py new file mode 100644 index 0000000..a4ffd3c --- /dev/null +++ b/tests/unit/validators/multi_select_any_of_validator_test.py @@ -0,0 +1,79 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +import pytest +from validataclass.exceptions import ListItemsValidationError, ListLengthError + +from validataclass_search_queries.validators import MultiSelectAnyOfValidator + + +def test_multi_select_any_of_validator_valid_input(): + """ Test the MultiSelectAnyOfValidator with valid input (case-insensitive). """ + validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz']) + assert validator.validate('FOO,baz,Bar') == ['foo', 'baz', 'BAR'] + + +@pytest.mark.parametrize( + 'input_data', [ + ',', + '0', + 'banana', + 'foo|bar', + ] +) +def test_multi_select_any_of_validator_invalid_input(input_data): + """ Test the MultiSelectAnyOfValidator with invalid input. """ + validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz']) + with pytest.raises(ListItemsValidationError): + validator.validate(input_data) + + +def test_multi_select_any_of_validator_invalid_empty_string(): + """ + Test the MultiSelectAnyOfValidator with an empty string as input, which should result in a ListLengthError because + it's parsed as an empty list and the base ListValidator always has a min_length of 1. + """ + validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz']) + with pytest.raises(ListLengthError): + validator.validate('') + + +def test_multi_select_any_of_validator_case_sensitive_valid(): + """ Test the MultiSelectAnyOfValidator with case_sensitive=True. """ + validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz'], case_sensitive=True) + assert validator.validate('foo,baz,BAR') == ['foo', 'baz', 'BAR'] + + +@pytest.mark.parametrize('input_data', ['FOO', 'bar', 'foo,BAZ']) +def test_multi_select_any_of_validator_case_sensitive_invalid(input_data): + """ Test the MultiSelectAnyOfValidator with case_sensitive=True. """ + validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz'], case_sensitive=True) + with pytest.raises(ListItemsValidationError): + validator.validate(input_data) + + +def test_multi_select_any_of_validator_with_custom_delimiter(): + """ Test the MultiSelectAnyOfValidator with a custom delimiter. """ + validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz'], delimiter='|') + + # Valid input + assert validator.validate('foo|baz') == ['foo', 'baz'] + + # Invalid input + with pytest.raises(ListItemsValidationError): + validator.validate('foo,bar') + + +def test_multi_select_any_of_validator_with_max_length(): + """ Test the MultiSelectAnyOfValidator with a maximum length. """ + validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz'], max_length=2) + + # Valid input + assert validator.validate('foo,baz') == ['foo', 'baz'] + + # Invalid input + with pytest.raises(ListLengthError): + validator.validate('foo,bar,baz') diff --git a/tests/unit/validators/multi_select_enum_validator_test.py b/tests/unit/validators/multi_select_enum_validator_test.py new file mode 100644 index 0000000..5c72abd --- /dev/null +++ b/tests/unit/validators/multi_select_enum_validator_test.py @@ -0,0 +1,98 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +import pytest +from validataclass.exceptions import ListItemsValidationError, ListLengthError + +from tests.helpers import UnitTestEnum +from validataclass_search_queries.validators import MultiSelectEnumValidator + + +def test_multi_select_enum_validator_valid_input(): + """ Test the MultiSelectEnumValidator with valid input (case-insensitive). """ + validator = MultiSelectEnumValidator(UnitTestEnum) + assert validator.validate('Foo,baz,BAR') == [UnitTestEnum.FOO, UnitTestEnum.BAZ, UnitTestEnum.BAR] + + +@pytest.mark.parametrize( + 'input_data', [ + ',', + '0', + 'banana', + 'foo|bar', + ] +) +def test_multi_select_enum_validator_invalid_input(input_data): + """ Test the MultiSelectEnumValidator with invalid input. """ + validator = MultiSelectEnumValidator(UnitTestEnum) + with pytest.raises(ListItemsValidationError): + validator.validate(input_data) + + +def test_multi_select_enum_validator_invalid_empty_string(): + """ + Test the MultiSelectEnumValidator with an empty string as input, which should result in a ListLengthError because + it's parsed as an empty list and the base ListValidator always has a min_length of 1. + """ + validator = MultiSelectEnumValidator(UnitTestEnum) + with pytest.raises(ListLengthError): + validator.validate('') + + +def test_multi_select_enum_validator_with_allowed_values(): + """ Test the MultiSelectEnumValidator with the allowed_values parameter. """ + validator = MultiSelectEnumValidator(UnitTestEnum, allowed_values=[UnitTestEnum.FOO]) + + # Valid input + assert validator.validate('foo,foo') == [UnitTestEnum.FOO, UnitTestEnum.FOO] + + # Invalid input + with pytest.raises(ListItemsValidationError): + validator.validate('foo,bar') + + +def test_multi_select_enum_validator_case_sensitive_valid(): + """ Test the MultiSelectEnumValidator with case_sensitive=True. """ + validator = MultiSelectEnumValidator(UnitTestEnum, case_sensitive=True) + + # Valid input + assert validator.validate('foo,baz,bar') == [UnitTestEnum.FOO, UnitTestEnum.BAZ, UnitTestEnum.BAR] + + # Invalid input + with pytest.raises(ListItemsValidationError): + validator.validate('foo,banana') + + +@pytest.mark.parametrize('input_data', ['FOO', 'foo,BAZ']) +def test_multi_select_enum_validator_case_sensitive_invalid(input_data): + """ Test the MultiSelectEnumValidator with case_sensitive=True. """ + validator = MultiSelectEnumValidator(UnitTestEnum, case_sensitive=True) + with pytest.raises(ListItemsValidationError): + validator.validate(input_data) + + +def test_multi_select_enum_validator_with_custom_delimiter(): + """ Test the MultiSelectEnumValidator with a custom delimiter. """ + validator = MultiSelectEnumValidator(UnitTestEnum, delimiter='|') + + # Valid input + assert validator.validate('foo|baz') == [UnitTestEnum.FOO, UnitTestEnum.BAZ] + + # Invalid input + with pytest.raises(ListItemsValidationError): + validator.validate('foo,bar') + + +def test_multi_select_enum_validator_with_max_length(): + """ Test the MultiSelectEnumValidator with a maximum length. """ + validator = MultiSelectEnumValidator(UnitTestEnum, max_length=2) + + # Valid input + assert validator.validate('foo,baz') == [UnitTestEnum.FOO, UnitTestEnum.BAZ] + + # Invalid input + with pytest.raises(ListLengthError): + validator.validate('foo,bar,baz') diff --git a/tests/unit/validators/multi_select_integer_validator_test.py b/tests/unit/validators/multi_select_integer_validator_test.py new file mode 100644 index 0000000..7c9784e --- /dev/null +++ b/tests/unit/validators/multi_select_integer_validator_test.py @@ -0,0 +1,68 @@ +""" +validataclass-search-queries +Copyright (c) 2026, binary butterfly GmbH and contributors +Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. +""" + +import pytest +from validataclass.exceptions import ListItemsValidationError, ListLengthError + +from validataclass_search_queries.validators import MultiSelectIntegerValidator + + +@pytest.mark.parametrize( + 'input_data, expected_result', + [ + ('1', [1]), + ('10', [10]), + ('1,3,1,2', [1, 3, 1, 2]), + ] +) +def test_multi_select_integer_validator_valid_input(input_data, expected_result): + """ Test the MultiSelectIntegerValidator with valid input. """ + validator = MultiSelectIntegerValidator(min_value=1, max_value=10) + assert validator.validate(input_data) == expected_result + + +@pytest.mark.parametrize( + 'input_data', + [ + ',', + 'banana', + '0', + '11', + ] +) +def test_multi_select_integer_validator_invalid_input(input_data): + """ Test the MultiSelectIntegerValidator with invalid input. """ + validator = MultiSelectIntegerValidator(min_value=1, max_value=10) + with pytest.raises(ListItemsValidationError): + validator.validate(input_data) + + +def test_multi_select_integer_validator_invalid_empty_string(): + """ + Test the MultiSelectIntegerValidator with an empty string as input, which should result in a ListLengthError because + it's parsed as an empty list and the base ListValidator always has a min_length of 1. + """ + validator = MultiSelectIntegerValidator() + with pytest.raises(ListLengthError): + validator.validate('') + + +def test_multi_select_integer_validator_with_custom_delimiter(): + """ Test the MultiSelectIntegerValidator with a custom delimiter. """ + validator = MultiSelectIntegerValidator(delimiter='|') + assert validator.validate('1|2|3') == [1, 2, 3] + + +def test_multi_select_integer_validator_with_max_length(): + """ Test the MultiSelectIntegerValidator with a maximum length. """ + validator = MultiSelectIntegerValidator(max_length=3) + + # Valid input + assert validator.validate('123,456,789') == [123, 456, 789] + + # Invalid input + with pytest.raises(ListLengthError): + validator.validate('1,2,3,4') diff --git a/tests/unit/validators/multi_select_validator_test.py b/tests/unit/validators/multi_select_validator_test.py index 711b3e2..67cb4cb 100644 --- a/tests/unit/validators/multi_select_validator_test.py +++ b/tests/unit/validators/multi_select_validator_test.py @@ -6,18 +6,11 @@ import pytest from validataclass.exceptions import ListItemsValidationError, ListLengthError -from validataclass.validators import StringValidator, EnumValidator, IntegerValidator +from validataclass.validators import EnumValidator, StringValidator from tests.helpers import UnitTestEnum -from validataclass_search_queries.validators import ( - MultiSelectValidator, - MultiSelectIntegerValidator, - MultiSelectAnyOfValidator, - MultiSelectEnumValidator, -) - +from validataclass_search_queries.validators import MultiSelectValidator -# Tests for MultiSelectValidator @pytest.mark.parametrize( 'item_validator, input_data, expected_result', @@ -55,227 +48,36 @@ def test_multi_select_validator_invalid_input(item_validator, input_data): validator.validate(input_data) -def test_multi_select_validator_with_custom_delimiter(): - """ Test the MultiSelectValidator with a custom delimiter. """ - validator = MultiSelectValidator(StringValidator(min_length=1), delimiter='|') - assert validator.validate('foo,bar|baz') == ['foo,bar', 'baz'] - - -def test_multi_select_validator_with_max_length(): - """ Test the MultiSelectValidator with a maximum length. """ - validator = MultiSelectValidator(StringValidator(), max_length=3) - - # Valid input - assert validator.validate('a,b,c') == ['a', 'b', 'c'] - - # Invalid input - with pytest.raises(ListLengthError): - validator.validate('a,b,c,d') - - @pytest.mark.parametrize( - 'validator', [ - MultiSelectValidator(StringValidator()), - MultiSelectValidator(IntegerValidator()), - MultiSelectValidator(EnumValidator(UnitTestEnum)), - MultiSelectIntegerValidator(), - MultiSelectAnyOfValidator(['foo', 'bar', 'baz']), - MultiSelectEnumValidator(UnitTestEnum), + 'item_validator', + [ + StringValidator(), + StringValidator(min_length=1), ] ) -def test_multi_select_validator_invalid_empty_string_list_length_error(validator): +def test_multi_select_validator_invalid_empty_string_list_length_error(item_validator): """ - Test the MultiSelectValidator and its subclasses with an empty string as input - (which is parsed as an empty list and always invalid because the base ListValidator has a min_length of 1). + Test the MultiSelectAnyOfValidator with an empty string as input, which should result in a ListLengthError because + it's parsed as an empty list and the base ListValidator always has a min_length of 1. """ - # Empty string input fails at the list length validation, regardless of item validator. + validator = MultiSelectValidator(item_validator) with pytest.raises(ListLengthError): validator.validate('') -# Tests for MultiSelectIntegerValidator - -@pytest.mark.parametrize( - 'input_data, expected_result', - [ - ('1', [1]), - ('10', [10]), - ('1,3,1,2', [1, 3, 1, 2]), - ] -) -def test_multi_select_integer_validator_valid_input(input_data, expected_result): - """ Test the MultiSelectIntegerValidator with valid input. """ - validator = MultiSelectIntegerValidator(min_value=1, max_value=10) - assert validator.validate(input_data) == expected_result - - -@pytest.mark.parametrize( - 'input_data', - [ - ',', - 'banana', - '0', - '11', - ] -) -def test_multi_select_integer_validator_invalid_input(input_data): - """ Test the MultiSelectIntegerValidator with invalid input. """ - validator = MultiSelectIntegerValidator(min_value=1, max_value=10) - with pytest.raises(ListItemsValidationError): - validator.validate(input_data) - - -def test_multi_select_integer_validator_with_custom_delimiter(): - """ Test the MultiSelectIntegerValidator with a custom delimiter. """ - validator = MultiSelectIntegerValidator(delimiter='|') - assert validator.validate('1|2|3') == [1, 2, 3] - - -def test_multi_select_integer_validator_with_max_length(): - """ Test the MultiSelectIntegerValidator with a maximum length. """ - validator = MultiSelectIntegerValidator(max_length=3) - - # Valid input - assert validator.validate('123,456,789') == [123, 456, 789] - - # Invalid input - with pytest.raises(ListLengthError): - validator.validate('1,2,3,4') - - -# Tests for MultiSelectAnyOfValidator - -def test_multi_select_any_of_validator_valid_input(): - """ Test the MultiSelectAnyOfValidator with valid input (case-insensitive). """ - validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz']) - assert validator.validate('FOO,baz,Bar') == ['foo', 'baz', 'BAR'] - - -@pytest.mark.parametrize( - 'input_data', [ - ',', - '0', - 'banana', - 'foo|bar', - ] -) -def test_multi_select_any_of_validator_invalid_input(input_data): - """ Test the MultiSelectAnyOfValidator with invalid input. """ - validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz']) - with pytest.raises(ListItemsValidationError): - validator.validate(input_data) - - -def test_multi_select_any_of_validator_case_sensitive_valid(): - """ Test the MultiSelectAnyOfValidator with case_sensitive=True. """ - validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz'], case_sensitive=True) - assert validator.validate('foo,baz,BAR') == ['foo', 'baz', 'BAR'] - - -@pytest.mark.parametrize('input_data', ['FOO', 'bar', 'foo,BAZ']) -def test_multi_select_any_of_validator_case_sensitive_invalid(input_data): - """ Test the MultiSelectAnyOfValidator with case_sensitive=True. """ - validator = MultiSelectAnyOfValidator(['foo', 'BAR', 'baz'], case_sensitive=True) - with pytest.raises(ListItemsValidationError): - validator.validate(input_data) - - -def test_multi_select_any_of_validator_with_custom_delimiter(): - """ Test the MultiSelectAnyOfValidator with a custom delimiter. """ - validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz'], delimiter='|') - - # Valid input - assert validator.validate('foo|baz') == ['foo', 'baz'] - - # Invalid input - with pytest.raises(ListItemsValidationError): - validator.validate('foo,bar') - - -def test_multi_select_any_of_validator_with_max_length(): - """ Test the MultiSelectAnyOfValidator with a maximum length. """ - validator = MultiSelectAnyOfValidator(['foo', 'bar', 'baz'], max_length=2) - - # Valid input - assert validator.validate('foo,baz') == ['foo', 'baz'] - - # Invalid input - with pytest.raises(ListLengthError): - validator.validate('foo,bar,baz') - - -# Tests for MultiSelectEnumValidator - -def test_multi_select_enum_validator_valid_input(): - """ Test the MultiSelectEnumValidator with valid input (case-insensitive). """ - validator = MultiSelectEnumValidator(UnitTestEnum) - assert validator.validate('Foo,baz,BAR') == [UnitTestEnum.FOO, UnitTestEnum.BAZ, UnitTestEnum.BAR] - - -@pytest.mark.parametrize( - 'input_data', [ - ',', - '0', - 'banana', - 'foo|bar', - ] -) -def test_multi_select_enum_validator_invalid_input(input_data): - """ Test the MultiSelectEnumValidator with invalid input. """ - validator = MultiSelectEnumValidator(UnitTestEnum) - with pytest.raises(ListItemsValidationError): - validator.validate(input_data) - - -def test_multi_select_enum_validator_with_allowed_values(): - """ Test the MultiSelectEnumValidator with the allowed_values parameter. """ - validator = MultiSelectEnumValidator(UnitTestEnum, allowed_values=[UnitTestEnum.FOO]) - - # Valid input - assert validator.validate('foo,foo') == [UnitTestEnum.FOO, UnitTestEnum.FOO] - - # Invalid input - with pytest.raises(ListItemsValidationError): - validator.validate('foo,bar') - - -def test_multi_select_enum_validator_case_sensitive_valid(): - """ Test the MultiSelectEnumValidator with case_sensitive=True. """ - validator = MultiSelectEnumValidator(UnitTestEnum, case_sensitive=True) - assert validator.validate('foo,baz,bar') == [UnitTestEnum.FOO, UnitTestEnum.BAZ, UnitTestEnum.BAR] - - # Invalid input - with pytest.raises(ListItemsValidationError): - validator.validate('foo,banana') - - -@pytest.mark.parametrize('input_data', ['FOO', 'foo,BAZ']) -def test_multi_select_enum_validator_case_sensitive_invalid(input_data): - """ Test the MultiSelectEnumValidator with case_sensitive=True. """ - validator = MultiSelectEnumValidator(UnitTestEnum, case_sensitive=True) - with pytest.raises(ListItemsValidationError): - validator.validate(input_data) - - -def test_multi_select_enum_validator_with_custom_delimiter(): - """ Test the MultiSelectEnumValidator with a custom delimiter. """ - validator = MultiSelectEnumValidator(UnitTestEnum, delimiter='|') - - # Valid input - assert validator.validate('foo|baz') == [UnitTestEnum.FOO, UnitTestEnum.BAZ] - - # Invalid input - with pytest.raises(ListItemsValidationError): - validator.validate('foo,bar') +def test_multi_select_validator_with_custom_delimiter(): + """ Test the MultiSelectValidator with a custom delimiter. """ + validator = MultiSelectValidator(StringValidator(min_length=1), delimiter='|') + assert validator.validate('foo,bar|baz') == ['foo,bar', 'baz'] -def test_multi_select_enum_validator_with_max_length(): - """ Test the MultiSelectEnumValidator with a maximum length. """ - validator = MultiSelectEnumValidator(UnitTestEnum, max_length=2) +def test_multi_select_validator_with_max_length(): + """ Test the MultiSelectValidator with a maximum length. """ + validator = MultiSelectValidator(StringValidator(), max_length=3) # Valid input - assert validator.validate('foo,baz') == [UnitTestEnum.FOO, UnitTestEnum.BAZ] + assert validator.validate('a,b,c') == ['a', 'b', 'c'] # Invalid input with pytest.raises(ListLengthError): - validator.validate('foo,bar,baz') + validator.validate('a,b,c,d')