def test_must_raise_validation_exception_when_input_is_greater_than_maximum_allowed( self, input, max): with pytest.raises(ValidationException) as exc_info: is_int(max=max)(input) assert exc_info.value.args[ 0] == "'{}' is greater than maximum allowed ({})".format( input, max)
def test_must_raise_validation_exception_only_when_all_entries_are_invalid_when_all_is_false( self): input = [-1, 2, 8] try: is_list(validator=is_int(min=1), all=False)(input) except ValidationException: raise AssertionError("should not throw")
def test_validate_must_include_hook_errors_in_returned_errors(self): repo = {"name": "finicky", "version": "1.0.0", "stars": "2000"} schema = {"name": is_str(), "version": is_str(), "stars": is_int()} hook_mock = Mock() hook_mock.side_effect = ValidationException("Hook error") errors, _ = validate(schema=schema, data=repo, hook=hook_mock) assert "Hook error" in errors["___hook"]
def test_validate_must_return_what_the_hook_returns(self): repo = {"name": "finicky", "version": "1.0.0", "stars": "2000"} hook_return_val = {"name": "changed_by hook"} schema = {"name": is_str(), "version": is_str(), "stars": is_int()} hook = Mock() hook.return_value = hook_return_val _, validated_repo = validate(schema=schema, data=repo, hook=hook) assert validated_repo == hook_return_val
def test_must_return_default_provided_when_input_is_missing(self): assert is_int(default=8)(None) == 8
def test_must_return_input_upon_validation(self, input, min, max): assert is_int(min=min, max=max)(input) == int(input)
def test_must_return_only_valid_inputs_when_all_is_false(self): input = [1, -8, 3] assert is_list(validator=is_int(min=1), all=False)(input) == [1, 3]
def test_must_return_default_value_when_input_is_none(self): default = [1, 2] assert default == is_list(required=False, default=[1, 2], validator=is_int())(None)
class TestListValidator: """ 1. must reject none input whend field is required 2. must return default value when field isnot required and default is provided 4. must validate all entries against the validator. 5. must require all entries to pass validation by default 6. when all is set to false, must require that at least one entry pass valdiation 7. must return only validated entries 6. on error, must return all errors encountered """ def test_must_raise_validation_error_when_input_is_none_but_required_is_true( self): with pytest.raises(ValidationException) as exc_info: is_list(required=True, validator=is_int())(None) assert exc_info.value.errors == "required but was missing" def test_must_return_default_value_when_input_is_none(self): default = [1, 2] assert default == is_list(required=False, default=[1, 2], validator=is_int())(None) @pytest.mark.parametrize("input", ["value", {"id": 23}, object, 2.8]) def test_must_raise_validation_exception_for_non_list_input(self, input): with pytest.raises(ValidationException) as exc: is_list(validator=Mock())(input) assert exc.value.errors == "expected a list but got {}".format( type(input)) def test_must_validate_all_input_against_validator(self): validator = Mock() is_list(validator=validator)([-1, 8]) validator.assert_has_calls([call(-1), call(8)]) @pytest.mark.parametrize(("validator", "input", "errors"), [ (is_int(min=1), [-1, 2, 8], ["'-1' is less than minimum allowed (1)"]), (is_int(max=5), [8, 10], [ "'8' is greater than maximum allowed (5)", "'10' is greater than maximum allowed (5)" ]), (is_str(pattern=r"\A\d{3}\Z"), ["2323", "128"], ["'2323' does not match expected pattern(\\A\\d{3}\\Z)"]) ]) def test_must_raise_validation_when_at_least_one_entry_is_invalid_by_default( self, validator, input, errors): with pytest.raises(ValidationException) as exc: is_list(validator=validator)(input) assert exc.value.errors == errors def test_must_raise_validation_exception_only_when_all_entries_are_invalid_when_all_is_false( self): input = [-1, 2, 8] try: is_list(validator=is_int(min=1), all=False)(input) except ValidationException: raise AssertionError("should not throw") @pytest.mark.parametrize( ("validator", "input", "return_val"), [(is_int(required=True), [-3, 8, 112], [-3, 8, 112]), (is_str(required=True), ["one", "three ", " four " ], ["one", "three", "four"]), (is_date(format="%Y-%m-%d"), ["2021-02-07 "], [datetime.datetime(year=2021, month=2, day=7)])]) def test_must_return_newly_validated_input(self, validator, input, return_val): assert is_list(validator=validator)(input) == return_val def test_must_return_only_valid_inputs_when_all_is_false(self): input = [1, -8, 3] assert is_list(validator=is_int(min=1), all=False)(input) == [1, 3]
def test_must_raise_validation_exception_when_input_is_less_than_minimum_allowed( self, input, min): with pytest.raises(ValidationException) as exc_info: is_int(min=min)(input) assert exc_info.value.args[ 0] == "'{}' is less than minimum allowed ({})".format(input, min)
class TestDictValidator: def test_must_raise_validation_exception_when_input_is_none_but_was_required( self): with pytest.raises(ValidationException) as exc: is_dict(required=True, schema={})(None) assert exc.value.args[0] == "required but was missing" def test_must_return_default_value_when_input_is_none(self): address = {"phone": "+233-282123233"} assert is_dict(required=False, default=address, schema={})(None) == address @pytest.mark.parametrize("input", ["input", ["entry1", "entry2"], 2, 2.3, object()]) def test_must_raise_validation_error_when_input_is_not_dict(self, input): with pytest.raises(ValidationException) as exc_info: is_dict(schema={"phone": is_str(required=True)})(input) assert exc_info.value.errors == "expected a dictionary but got {}".format( type(input)) @pytest.mark.parametrize( ("schema", "input_dict", "expected_errors"), [({ "phone": is_str(required=True) }, { "phone": None }, { "phone": "required but was missing" }), ({ "id": is_int(required=True, min=1) }, { "id": -2 }, { "id": "'-2' is less than minimum allowed (1)" }), ({ "user_name": is_str(required=True, max_len=5) }, { "user_name": "yaaminu" }, { "user_name": "'yaaminu' is longer than maximum required length(5)" })]) def test_must_validate_input_against_schema(self, schema, input_dict, expected_errors): with pytest.raises(ValidationException) as exc: is_dict(schema=schema)(input_dict) assert expected_errors == exc.value.errors def test_must_return_newly_validated_input(self): validated_input = is_dict(schema={"phone": is_str(required=True)})({ "phone": "+233-23-23283234" }) assert validated_input == {"phone": "+233-23-23283234"} def test_must_clean_validated_input_before_returning(self): validated_input = is_dict(schema={"phone": is_str(required=True)})({ "phone": " +233-23-23283234" }) assert validated_input == {"phone": "+233-23-23283234"}
def test_must_raise_validation_exception_when_input_is_not_a_valid_int( self, input): with pytest.raises(ValidationException) as exc_info: is_int()(input) assert exc_info.value.args[0] == "'{}' is not a valid integer".format( input)
def test_validate_must_return_newly_validated_data(self): repo = {"name": "finicky", "version": "1.0.0", "stars": "2000"} schema = {"name": is_str(), "version": is_str(), "stars": is_int()} _, validated_repo = validate(schema=schema, data=repo, hook=None) assert validated_repo == {"name": "finicky", "version": "1.0.0", "stars": 2000}
def test_must_return_none_when_input_is_none_and_required_is_false(self): assert is_int(required=False)(None) is None
def test_must_raise_validation_error_when_input_is_none_but_required_is_true( self): with pytest.raises(ValidationException) as exc_info: is_list(required=True, validator=is_int())(None) assert exc_info.value.errors == "required but was missing"
def test_must_raise_validation_exception_when_input_is_none_and_required_is_true( self): with pytest.raises(ValidationException) as exc_info: is_int(required=True)(None) assert exc_info.value.args[0] == "required but was missing"
def test_validate_must_run_invoke_hook_on_input_data_when_present(self): repo = {"name": "finicky", "version": "1.0.0", "stars": "2000"} schema = {"name": is_str(), "version": is_str(), "stars": is_int()} hook_mock = Mock() validate(schema=schema, data=repo, hook=hook_mock) hook_mock.assert_called_once_with(dict(name="finicky", version="1.0.0", stars=2000))