Ejemplo n.º 1
0
def test_validate_or():
    """ Test for the or_ validator, also in combination with not_"""

    # empty list error
    with pytest.raises(ValueError):
        or_()

    # empty list error 2
    with pytest.raises(ValueError):
        or_([])

    # single element simplification
    # assert or_(is_even) == failure_raiser(is_even)  TODO enable when equality works

    # lists
    a=or_(is_even, is_multiple_of(3))
    b=not_(or_(is_even, is_multiple_of(3)))

    # -- check that the validation works
    assert a(9) is True  # a is not even but is a multiple of 3 > ok
    assert a(4) is True  # a is even but is not a multiple of 3 > ok
    assert b(7) is True  # b is not even AND not a multiple of 3 > ok

    with pytest.raises(AllValidatorsFailed):
        a(7)  # 7 is odd and not multiple of 3

    with pytest.raises(DidNotFail):
        b(3)  # 3 is odd but it is a multiple of 3
Ejemplo n.º 2
0
def test_readme_index_usage_function():
    """ Tests that the examples provided in the index page under Usage examples/Function are correct """

    from mini_lambda import s, Len
    from valid8 import validate_arg
    from valid8.validation_lib import instance_of

    @validate_arg('name',
                  instance_of(str),
                  Len(s) > 0,
                  help_msg='name should be a non-empty string')
    def build_house(name, surface=None):
        print('Building house... DONE !')
        return name, surface

    build_house('sweet home', 200)

    with pytest.raises(InputValidationError) as exc_info:
        build_house('', 200)  # name is invalid
    e = exc_info.value
    assert str(e) == "name should be a non-empty string. " \
                     "Error validating input [name=''] for function [build_house]. " \
                     "At least one validation function failed for value ''. " \
                     "Successes: [\"instance_of_%r\"] / Failures: {'len(s) > 0': 'Returned False.'}." \
                     "" % str

    from mini_lambda import s, x, l, Len
    from valid8 import validate_arg, validate_out
    from valid8.validation_lib import instance_of, is_multiple_of

    @validate_arg('name',
                  instance_of(str),
                  Len(s) > 0,
                  help_msg='name should be a non-empty string')
    @validate_arg(
        'surface', (x >= 0) & (x < 10000),
        is_multiple_of(100),
        help_msg='Surface should be a multiple of 100 between 0 and 10000.')
    @validate_out(instance_of(tuple), Len(l) == 2)
    def build_house(name, surface=None):
        print('Building house... DONE !')
        return name, surface

    build_house('sweet home')
    build_house('sweet home', None)  # No error !

    with pytest.raises(TypeError):
        is_multiple_of(100)(None)

    with pytest.raises(TypeError):
        (Len(s) > 0).evaluate(None)
Ejemplo n.º 3
0
def test_validate_xor():
    """ Test for the xor_ validator """

    # empty list error
    with pytest.raises(ValueError):
        xor_()

    # empty list error 2
    with pytest.raises(ValueError):
        xor_([])

    # single element simplification
    # assert xor_(is_even) == failure_raiser(is_even) TODO enable when equality works

    # lists
    a=xor_(is_even, is_multiple_of(3))

    # -- check that the validation works
    assert a(9) is True  # a is not even but is a multiple of 3 > ok
    assert a(4) is True  # a is even but is not a multiple of 3 > ok

    with pytest.raises(XorTooManySuccess):
        a(6)  # a is both even and a multiple of 3

    with pytest.raises(AllValidatorsFailed):
        a(7)  # a is neither even nor a multiple of 3
Ejemplo n.º 4
0
def test_not_not_all():
    """ Test for the not_ and not_all validators """

    def gtcustom(x):
        assert x < 10

    a = not_(is_even)
    b = not_all(is_even, is_multiple_of(3))
    c = not_(gtcustom, catch_all=True)
    d = not_(gtcustom)

    assert a(11) is True
    assert b(11) is True
    assert c(11) is True  # 11 leads to an AssertionError (not a ValidationFailure), but the not_ handles the exception correctly

    with pytest.raises(DidNotFail) as exc_info:
        a(84)  # 84 is invalid (not even)
    e = exc_info.value
    assert str(e) == 'is_even validated value 84 with success, therefore the not() is a failure. ' \
                     'Function [is_even] returned [True] for value 84.'

    with pytest.raises(DidNotFail):
        b(6)   # 6 is invalid (is even and it is a multiple of 3)

    with pytest.raises(DidNotFail):
        c(9)   # 9 is invalid (is less than 10)

    with pytest.raises(DidNotFail):
        d(9)   # 9 is invalid (is less than 10)

    with pytest.raises(AssertionError):
        d(11)  # 11 is a *valid* value, but the not_ operator does not catch the exception so we get the error
Ejemplo n.º 5
0
def test_readme_index_combining_autoclass():
    """ Tests that the examples provided in the index page under Combining/autoclass are correct """

    from autoclass import autoclass
    from mini_lambda import s, x, Len
    from valid8 import validate_field, ClassFieldValidationError
    from valid8.validation_lib import instance_of, is_multiple_of

    class InvalidNameError(ClassFieldValidationError):
        help_msg = 'name should be a non-empty string'

    class InvalidSurfaceError(ClassFieldValidationError):
        help_msg = 'Surface should be a multiple of 100 between 0 and 10000.'

    @validate_field('name',
                    instance_of(str),
                    Len(s) > 0,
                    error_type=InvalidNameError)
    @validate_field('surface', (x >= 0) & (x < 10000),
                    is_multiple_of(100),
                    error_type=InvalidSurfaceError)
    @autoclass
    class House(object):
        def __init__(self, name, surface=None):
            pass

    h = House('sweet home', 200)

    h.surface = None  # Valid (surface is nonable by signature)

    with pytest.raises(InvalidNameError):
        h.name = ''  # InvalidNameError

    with pytest.raises(InvalidSurfaceError):
        h.surface = 10000  # InvalidSurfaceError
 class House:
     @validate_arg('name', Len(s) > 0,
                   error_type=InvalidName)
     @validate_arg('surface', (x >= 0) & (x < 10000), is_multiple_of(100),
                   error_type=InvalidSurface)
     def __init__(self, name: str, surface: Integral = None):
         pass
Ejemplo n.º 7
0
    class House(object):

        @validate_arg('name', instance_of(str), Len(s) > 0,
                      error_type=InvalidNameError)
        @validate_arg('surface', (x >= 0) & (x < 10000), is_multiple_of(100),
                      error_type=InvalidSurfaceError)
        def __init__(self, name, surface=None):
            pass
Ejemplo n.º 8
0
def test_readme_combining_enforce():
    # Imports - for type validation
    from numbers import Integral
    from typing import Tuple, Optional
    from enforce import runtime_validation, config
    config(dict(mode='covariant')
           )  # means that subclasses of required types are valid too
    from enforce.exceptions import RuntimeTypeError

    # Imports - for value validation
    from mini_lambda import s, x, Len
    from valid8 import validate_arg
    from valid8.validation_lib import is_multiple_of

    # Define our 2 applicative error types
    class InvalidNameError(InputValidationError):
        help_msg = 'name should be a non-empty string'

    class InvalidSurfaceError(InputValidationError):
        help_msg = 'Surface should be a multiple of 100 between 0 and 10000.'

    # Apply type + value validation
    @runtime_validation
    @validate_arg('name', Len(s) > 0, error_type=InvalidNameError)
    @validate_arg('surface', (x >= 0) & (x < 10000),
                  is_multiple_of(100),
                  error_type=InvalidSurfaceError)
    def build_house(
            name: str,
            surface: Optional[Integral] = None
    ) -> Tuple[str, Optional[Integral]]:
        print('Building house... DONE !')
        return name, surface

    build_house('sweet home', 200)
    build_house('sweet home')

    with pytest.raises(InvalidNameError):
        build_house('', 100)  # InvalidNameError

    with pytest.raises(InvalidSurfaceError):
        build_house('sweet home', 10000)  # InvalidSurfaceError

    with pytest.raises(RuntimeTypeError):
        build_house('test', 100.1)  # RuntimeTypeError
def test_validate_field_custom_type():
    """"""
    from valid8 import validate_field, ClassFieldValidationError
    from valid8.validation_lib import instance_of, is_multiple_of
    from mini_lambda import x, s, Len

    class InvalidNameError(ClassFieldValidationError):
        help_msg = 'name should be a non-empty string'

    class InvalidSurfaceError(ClassFieldValidationError):
        help_msg = 'Surface should be a multiple of 100 between 0 and 10000.'

    @validate_field('name', instance_of(str), Len(s) > 0,
                    error_type=InvalidNameError)
    @validate_field('surface', (x >= 0) & (x < 10000), is_multiple_of(100),
                    error_type=InvalidSurfaceError)
    class House(object):
        """Properties work only with new-style classes"""
        def __init__(self, name, surface=None):
            self.name = name
            self.surface = surface

        @property
        def surface(self):
            return self.__surface

        @surface.setter
        def surface(self, surface=None):
            self.__surface = surface

    h = House('sweet home')
    h.name = ''  # DOES NOT RAISE InvalidNameError

    with pytest.raises(InvalidNameError):
        h = House('')

    h.surface = 100
    with pytest.raises(InvalidSurfaceError):
        h.surface = 10000
Ejemplo n.º 10
0
def test_readme_index_usage_class_fields():
    """ Tests that the examples provided in the index page under Usage examples/class fields are correct"""

    from valid8 import validate_field, ClassFieldValidationError
    from valid8.validation_lib import instance_of, is_multiple_of
    from mini_lambda import x, s, Len

    @validate_field('name',
                    instance_of(str),
                    Len(s) > 0,
                    help_msg='name should be a non-empty string')
    @validate_field(
        'surface', (x >= 0) & (x < 10000),
        is_multiple_of(100),
        help_msg='Surface should be a multiple of 100 between 0 and 10000.')
    class House(object):
        def __init__(self, name, surface=None):
            self.name = name
            self.surface = surface

        @property
        def surface(self):
            return self.__surface

        @surface.setter
        def surface(self, surface=None):
            self.__surface = surface

    h = House('sweet home')
    h.name = ''  # DOES NOT RAISE InvalidNameError

    with pytest.raises(ClassFieldValidationError):
        h = House('')

    h.surface = 100
    with pytest.raises(ClassFieldValidationError):
        h.surface = 10000
Ejemplo n.º 11
0
def test_readme_index_usage_basic():
    """ Tests that the examples provided in the index page under Usage examples/Basic are correct """

    from valid8 import assert_valid
    from valid8.validation_lib import instance_of, is_multiple_of

    surf = -1

    # (1) simplest: one named variable to validate, one validation function
    assert_valid('surface', surf, instance_of(int))
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface', surf, is_multiple_of(100))
    e = exc_info.value
    assert str(e) == 'Error validating [surface=-1]. ' \
                     'IsNotMultipleOf: Value should be a multiple of 100. Wrong value: -1.'

    # (2) native mini_lambda support to define validation functions
    from mini_lambda import x
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface', surf, x > 0)
    e = exc_info.value
    assert str(
        e
    ) == 'Error validating [surface=-1]. InvalidValue: Function [x > 0] returned [False] for value -1.'
Ejemplo n.º 12
0
def test_readme_index_combining_attrs():
    """ Tests that the examples provided in the index page under Combining/autoclass are correct """

    import attr
    from mini_lambda import s, x, Len
    from valid8 import validate_field, ClassFieldValidationError
    from valid8.validation_lib import instance_of, is_multiple_of

    class InvalidNameError(ClassFieldValidationError):
        help_msg = 'name should be a non-empty string'

    class InvalidSurfaceError(ClassFieldValidationError):
        help_msg = 'Surface should be a multiple of 100 between 0 and 10000.'

    @validate_field('name',
                    instance_of(str),
                    Len(s) > 0,
                    error_type=InvalidNameError)
    @validate_field('surface', (x >= 0) & (x < 10000),
                    is_multiple_of(100),
                    error_type=InvalidSurfaceError)
    @attr.s
    class House(object):
        name = attr.ib()
        surface = attr.ib(default=None)

    h = House(
        'sweet home')  # Valid (surface is nonable by generated signature)

    h.name = ''  # DOES NOT RAISE InvalidNameError (no setter!)

    with pytest.raises(InvalidNameError):
        House('', 10000)  # InvalidNameError

    with pytest.raises(InvalidSurfaceError):
        House('sweet home', 10000)  # InvalidSurfaceError
Ejemplo n.º 13
0
def test_readme_index_usage_composition():
    """ Tests that the examples provided in the index page under Usage examples/Composition are correct """

    from valid8 import assert_valid
    from valid8.validation_lib import is_multiple_of
    from mini_lambda import x

    surf = -1

    # (7) composition of several base validation functions
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface', surf, (x >= 0) & (x < 10000),
                     is_multiple_of(100))
    e = exc_info.value
    assert str(e) == "Error validating [surface=-1]. " \
                     "At least one validation function failed for value -1. " \
                     "Successes: [] / Failures: {'(x >= 0) & (x < 10000)': 'Returned False.', " \
                     "'is_multiple_of_100': 'IsNotMultipleOf: Value should be a multiple of 100.'}."

    # (8) ... with a global custom error type. Oh by the way this supports templating
    class InvalidSurface(ValidationError):
        help_msg = 'Surface should be between {min_s} and {max_s} and be a multiple of {mul_s}, found {var_value}'

    min_surface, mul_surface, max_surface = 0, 100, 10000
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface',
                     surf, (x >= min_surface) & (x < max_surface),
                     is_multiple_of(mul_surface),
                     error_type=InvalidSurface,
                     min_s=min_surface,
                     mul_s=mul_surface,
                     max_s=max_surface)
    e = exc_info.value
    assert str(e) == "Surface should be between 0 and 10000 and be a multiple of 100, found -1. " \
                     "Error validating [surface=-1]. " \
                     "At least one validation function failed for value -1. " \
                     "Successes: [] / Failures: {" \
                     "'(x >= 0) & (x < 10000)': 'Returned False.', " \
                     "'is_multiple_of_100': 'IsNotMultipleOf: Value should be a multiple of 100.'}."

    # (9) ... and possible user-friendly intermediate failure messages
    with pytest.raises(ValidationError) as exc_info:
        assert_valid(
            'surface', surf,
            ((x >= 0) & (x < 10000), 'Surface should be between 0 and 10000'),
            (is_multiple_of(100), 'Surface should be a multiple of 100'))
    e = exc_info.value
    assert str(e) == "Error validating [surface=-1]. " \
                     "At least one validation function failed for value -1. " \
                     "Successes: [] / Failures: {" \
                     "'(x >= 0) & (x < 10000)': 'InvalidValue: Surface should be between 0 and 10000. " \
                     "Returned False.', " \
                     "'is_multiple_of_100': 'InvalidValue: Surface should be a multiple of 100. " \
                     "IsNotMultipleOf: Value should be a multiple of 100.'}."

    # *********** other even more complex tests ***********

    # + unique applicative error type
    with pytest.raises(ValidationError) as exc_info:
        assert_valid(
            'surface',
            surf,
            failure_raiser(
                (x >= min_surface) & (x < max_surface),
                help_msg='Surface should be between {min_val} and {max_val}',
                min_val=min_surface,
                max_val=max_surface),
            (is_multiple_of(100),
             'Surface should be a multiple of 100, found {wrong_value}'),
            error_type=InvalidSurface,
            min_s=min_surface,
            mul_s=mul_surface,
            max_s=max_surface)
    e = exc_info.value
    assert str(e) == "Surface should be between 0 and 10000 and be a multiple of 100, found -1. " \
                     "Error validating [surface=-1]. " \
                     "At least one validation function failed for value -1. " \
                     "Successes: [] / Failures: {" \
                     "'(x >= 0) & (x < 10000)': 'InvalidValue: Surface should be between 0 and 10000. " \
                     "Returned False.', " \
                     "'is_multiple_of_100': 'InvalidValue: Surface should be a multiple of 100, found -1. " \
                     "IsNotMultipleOf: Value should be a multiple of 100.'}."
Ejemplo n.º 14
0
def test_readme_index_usage_customization():
    """ Tests that the examples provided in the index page under Usage examples/Customization are correct """

    from valid8 import assert_valid, ValidationError
    from valid8.validation_lib import is_multiple_of
    from mini_lambda import x

    from valid8 import NonePolicy

    surf = -1

    # (3) explicit validation policy for None
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface', None, x > 0, none_policy=NonePolicy.FAIL)
    e = exc_info.value
    assert str(
        e
    ) == 'Error validating [surface=None]. ValueIsNone: The value must be non-None. Wrong value: None.'

    # *** (4) TEST: custom ValidationFailure (not ValidationError) message. Does it have any interest ? ***
    with pytest.raises(ValidationError) as exc_info:
        assert_valid(
            'surface', surf,
            (is_multiple_of(100), 'Surface should be a multiple of 100'))
    e = exc_info.value
    assert str(e) == 'Error validating [surface=-1]. ' \
                     'InvalidValue: Surface should be a multiple of 100. ' \
                     'Function [is_multiple_of_100] raised ' \
                     'IsNotMultipleOf: Value should be a multiple of 100. Wrong value: -1.'

    # (4) custom error message (exception is still a ValidationError)
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface',
                     surf,
                     x > 0,
                     help_msg='Surface should be positive')
    e = exc_info.value
    assert str(e) == "Surface should be positive. " \
                     "Error validating [surface=-1]. InvalidValue: Function [x > 0] returned [False] for value -1."

    # (5) custom error types (recommended to provide unique applicative errors)
    class InvalidSurface(ValidationError):
        help_msg = 'Surface should be a positive number'

    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface',
                     surf,
                     is_multiple_of(100),
                     error_type=InvalidSurface)
    e = exc_info.value
    assert isinstance(e, InvalidSurface)
    assert str(e) == 'Surface should be a positive number. ' \
                     'Error validating [surface=-1]. ' \
                     'IsNotMultipleOf: Value should be a multiple of 100. Wrong value: -1.'

    # (6) custom error types with templating
    class InvalidSurface(ValidationError):
        help_msg = 'Surface should be > {minimum}, found {var_value}'

    min_value = 0
    with pytest.raises(ValidationError) as exc_info:
        assert_valid('surface',
                     surf,
                     x > min_value,
                     error_type=InvalidSurface,
                     minimum=min_value)
    e = exc_info.value
    assert str(e) == "Surface should be > 0, found -1. " \
                     "Error validating [surface=-1]. InvalidValue: Function [x > 0] returned [False] for value -1."
Ejemplo n.º 15
0
 class House:
     @validate_arg('name', Len(s) > 0)
     @validate_arg('surface', (x >= 0) & (x < 10000), is_multiple_of(100))
     def __init__(self, name: str, surface: int = 100):
         pass
Ejemplo n.º 16
0
def test_is_multiple_of():
    assert is_multiple_of(3)(-9)
    with pytest.raises(IsNotMultipleOf):
        is_multiple_of(3)(-10)