Example #1
0
def test_validation_fails():
    currency2f = lambda x: float(x[:-1])
    qparams = {
        "price": "43.5$",
        "n_items": "0",
        "meta": "info",
        "num": "-10",
        "num2": "20",
        "token": "012345678",
    }
    for r in builder.iterbuild(qparams):
        params = (
            validate(r, price=currency2f, n_items=int, num=int,
                     num2=int).positive(  # `n_items` must be greater than zero
                         "n_items")
            # `num` must be equal to 10
            .eq("num", 10)
            # `num2` must be less than 10
            .lt("num2", 10)
            # Len of `token` must be equal to 10
            .check("token", lambda x: len(x) == 10)
            # The same check as above, but using `transform`
            .eq("token", 10, transform=len))
        with pytest.raises(InvalidQueryParamException) as e, params:
            pass
        assert e.value.status_code == HTTP_400_BAD_REQUEST
Example #2
0
def test_missing_param_throws_error():
    dct = {"param1": "whatever", "param2": "6.66"}
    for request in builder.iterbuild(dct):
        params = validate(request, param1=None, param2=float, param3=int)
        with pytest.raises(InvalidQueryParamException) as e, params:
            pass
        assert e.value.status_code == HTTP_400_BAD_REQUEST
Example #3
0
def test_validator_factory():
    currency2f = lambda x: float(x[:-1])
    qparams = {
        "price": "43.5$",
        "n_items": "1",
        "meta": "info",
        "num": "10",
        "num2": "5",
        "token": "0123456789",
    }
    for r in builder.iterbuild(qparams):
        params = (
            validate(r, price=currency2f, n_items=int, num=int,
                     num2=int).positive(  # `n_items` must be greater than zero
                         "n_items")
            # `num` must be equal to 10
            .eq("num", 10)
            # `num2` must be less than 10
            .lt("num2", 10)
            # Len of `token` must be equal to 10
            .check("token", lambda x: len(x) == 10)
            # The same check as above, but using `transform`
            .eq("token", 10, transform=len))
        with params as p:
            assert {43.5, 1, "info", 10, 5,
                    "0123456789"} == set(p.__dct__.values())
Example #4
0
def test_params_processed():
    dct = {"num": "42", "double": "2.79", "string": "some string"}
    for request in builder.iterbuild(dct):
        with validate(request, num=int, double=float) as p:
            assert p.num == 42
            assert p.double == 2.79
            assert p.string == "some string"
Example #5
0
def test_params_omitted():
    dct = {"num": "42", "string": "some string"}
    for request in builder.iterbuild(dct):
        # Disable auto-detection of parameters (box_all)
        params = validate(request, num=int, box_all=False)
        with pytest.raises(APIException) as e, params as p:
            assert p.num == 42
            assert p.string == "some string"
        assert e.value.status_code == HTTP_500_INTERNAL_SERVER_ERROR
Example #6
0
def test_unsupported_errors_handled():
    supported_exceptions = (TypeError, ValueError, KeyError)
    random_exceptions = (IOError, BrokenPipeError, ConnectionError,
                         BufferError)
    params = {"param": "value"}
    for r in builder.iterbuild(params):
        for exc in supported_exceptions + random_exceptions:
            with pytest.raises(APIException) as e, validate(r):
                raise exc
            assert e.value.status_code == HTTP_500_INTERNAL_SERVER_ERROR
Example #7
0
def test_exception_handled_in_outside_context():
    """
    See `QueryParamValidator._validate()` and `test_supported_errors_handled()` for more info.
    """

    # Random exception.
    def f(_):
        raise IOError

    params = {"param": "value"}
    for r in builder.iterbuild(params):
        with pytest.raises(APIException) as e, validate(r, param=f):
            pass
        assert e.value.status_code == HTTP_500_INTERNAL_SERVER_ERROR
Example #8
0
def test_custom_validation_errors():
    def num_predicate(value: int) -> bool:
        if not 0 < value < 10:
            raise QvalValidationError(
                f"`num` must belong to the interval (0; 10), got '{value}'.")
        return True

    params = validate({"num": "5"}, {"num": num_predicate}, num=int)
    with params as p:
        assert p.num == 5

    try:
        with params.apply_to_request({"num": "20"}):
            pass
    except InvalidQueryParamException as e:
        assert "`num` must belong to the interval (0; 10), got '20'." in str(
            e.detail)
Example #9
0
def division_view(request: HttpRequest):
    """
    GET /api/divide?
    param a : int
    param b : int, nonzero

    Example: GET /api/divide?a=10&b=2&token=abcdefghijkl -> 200, {"answer": 5}
    """
    # Parameter validation occurs in the context manager.
    # If validation fails or user code throws an error, context manager
    # will raise InvalidQueryParamException or APIException respectively.
    # In Django, these exception will be processed and result
    # in the error codes 400 and 500 on the client side.
    params = (
        validate(request, a=int, b=int)
        # `b` must be anything but zero
        .nonzero("b"))
    with params as p:
        return JsonResponse({"answer": p.a // p.b})
Example #10
0
def test_supported_errors_handled():
    """
    Only TypeError, ValueError and KeyError occurred during the validation
    are handled as expected. Any error thrown inside of the context will raise APIError.
    See `test_unsupported_errors_handled()`.
    """
    def exc_factory(exc):
        def f(_):
            raise exc

        return f

    params = {"param": "value"}
    for r in builder.iterbuild(params):
        for exc in (TypeError, ValueError, KeyError):
            with pytest.raises(InvalidQueryParamException) as e, validate(
                    r, param=exc_factory(exc)):
                pass
            assert e.value.status_code == HTTP_400_BAD_REQUEST