Spaces:
Build error
Build error
"""Unit tests for DTO validation utilities""" | |
import pytest | |
from unittest.mock import Mock | |
from src.application.dtos.dto_validation import ( | |
ValidationError, | |
validate_dto, | |
validation_required, | |
validate_field, | |
validate_required, | |
validate_type, | |
validate_range, | |
validate_choices | |
) | |
class TestValidationError: | |
"""Test cases for ValidationError""" | |
def test_validation_error_basic(self): | |
"""Test basic ValidationError creation""" | |
error = ValidationError("Test error message") | |
assert str(error) == "Validation error: Test error message" | |
assert error.message == "Test error message" | |
assert error.field is None | |
assert error.value is None | |
def test_validation_error_with_field(self): | |
"""Test ValidationError with field information""" | |
error = ValidationError("Invalid value", field="test_field", value="invalid_value") | |
assert str(error) == "Validation error for field 'test_field': Invalid value" | |
assert error.message == "Invalid value" | |
assert error.field == "test_field" | |
assert error.value == "invalid_value" | |
def test_validation_error_without_field_but_with_value(self): | |
"""Test ValidationError without field but with value""" | |
error = ValidationError("Invalid value", value="test_value") | |
assert str(error) == "Validation error: Invalid value" | |
assert error.message == "Invalid value" | |
assert error.field is None | |
assert error.value == "test_value" | |
class TestValidateDto: | |
"""Test cases for validate_dto function""" | |
def test_validate_dto_success_with_validate_method(self): | |
"""Test successful DTO validation with _validate method""" | |
mock_dto = Mock() | |
mock_dto._validate = Mock() | |
result = validate_dto(mock_dto) | |
assert result is True | |
mock_dto._validate.assert_called_once() | |
def test_validate_dto_success_without_validate_method(self): | |
"""Test successful DTO validation without _validate method""" | |
mock_dto = Mock() | |
del mock_dto._validate # Remove the _validate method | |
result = validate_dto(mock_dto) | |
assert result is True | |
def test_validate_dto_failure_value_error(self): | |
"""Test DTO validation failure with ValueError""" | |
mock_dto = Mock() | |
mock_dto._validate.side_effect = ValueError("Validation failed") | |
with pytest.raises(ValidationError, match="Validation failed"): | |
validate_dto(mock_dto) | |
def test_validate_dto_failure_unexpected_error(self): | |
"""Test DTO validation failure with unexpected error""" | |
mock_dto = Mock() | |
mock_dto._validate.side_effect = RuntimeError("Unexpected error") | |
with pytest.raises(ValidationError, match="Validation failed: Unexpected error"): | |
validate_dto(mock_dto) | |
class TestValidationRequired: | |
"""Test cases for validation_required decorator""" | |
def test_validation_required_success(self): | |
"""Test validation_required decorator with successful validation""" | |
mock_instance = Mock() | |
mock_instance._validate = Mock() | |
def test_method(self): | |
return "success" | |
result = test_method(mock_instance) | |
assert result == "success" | |
mock_instance._validate.assert_called_once() | |
def test_validation_required_validation_error(self): | |
"""Test validation_required decorator with validation error""" | |
mock_instance = Mock() | |
mock_instance._validate.side_effect = ValueError("Validation failed") | |
def test_method(self): | |
return "success" | |
with pytest.raises(ValidationError, match="Validation failed"): | |
test_method(mock_instance) | |
def test_validation_required_method_error(self): | |
"""Test validation_required decorator with method execution error""" | |
mock_instance = Mock() | |
mock_instance._validate = Mock() | |
def test_method(self): | |
raise RuntimeError("Method error") | |
with pytest.raises(ValidationError, match="Error in test_method: Method error"): | |
test_method(mock_instance) | |
def test_validation_required_preserves_function_metadata(self): | |
"""Test that validation_required preserves function metadata""" | |
def test_method(self): | |
"""Test method docstring""" | |
return "success" | |
assert test_method.__name__ == "test_method" | |
assert test_method.__doc__ == "Test method docstring" | |
class TestValidateField: | |
"""Test cases for validate_field function""" | |
def test_validate_field_success(self): | |
"""Test successful field validation""" | |
def is_positive(value): | |
return value > 0 | |
result = validate_field(5, "test_field", is_positive) | |
assert result == 5 | |
def test_validate_field_failure_with_custom_message(self): | |
"""Test field validation failure with custom error message""" | |
def is_positive(value): | |
return value > 0 | |
with pytest.raises(ValidationError, match="Custom error message"): | |
validate_field(-1, "test_field", is_positive, "Custom error message") | |
def test_validate_field_failure_with_default_message(self): | |
"""Test field validation failure with default error message""" | |
def is_positive(value): | |
return value > 0 | |
with pytest.raises(ValidationError, match="Invalid value for field 'test_field'"): | |
validate_field(-1, "test_field", is_positive) | |
def test_validate_field_validator_exception(self): | |
"""Test field validation with validator raising exception""" | |
def failing_validator(value): | |
raise RuntimeError("Validator error") | |
with pytest.raises(ValidationError, match="Validation error for field 'test_field': Validator error"): | |
validate_field(5, "test_field", failing_validator) | |
class TestValidateRequired: | |
"""Test cases for validate_required function""" | |
def test_validate_required_success_with_value(self): | |
"""Test successful required validation with valid value""" | |
result = validate_required("test_value", "test_field") | |
assert result == "test_value" | |
def test_validate_required_success_with_zero(self): | |
"""Test successful required validation with zero (falsy but valid)""" | |
result = validate_required(0, "test_field") | |
assert result == 0 | |
def test_validate_required_success_with_false(self): | |
"""Test successful required validation with False (falsy but valid)""" | |
result = validate_required(False, "test_field") | |
assert result is False | |
def test_validate_required_failure_with_none(self): | |
"""Test required validation failure with None""" | |
with pytest.raises(ValidationError, match="Field 'test_field' is required"): | |
validate_required(None, "test_field") | |
def test_validate_required_failure_with_empty_string(self): | |
"""Test required validation failure with empty string""" | |
with pytest.raises(ValidationError, match="Field 'test_field' cannot be empty"): | |
validate_required("", "test_field") | |
def test_validate_required_failure_with_empty_list(self): | |
"""Test required validation failure with empty list""" | |
with pytest.raises(ValidationError, match="Field 'test_field' cannot be empty"): | |
validate_required([], "test_field") | |
def test_validate_required_failure_with_empty_dict(self): | |
"""Test required validation failure with empty dict""" | |
with pytest.raises(ValidationError, match="Field 'test_field' cannot be empty"): | |
validate_required({}, "test_field") | |
class TestValidateType: | |
"""Test cases for validate_type function""" | |
def test_validate_type_success_single_type(self): | |
"""Test successful type validation with single type""" | |
result = validate_type("test", "test_field", str) | |
assert result == "test" | |
def test_validate_type_success_multiple_types(self): | |
"""Test successful type validation with multiple types""" | |
result1 = validate_type("test", "test_field", (str, int)) | |
assert result1 == "test" | |
result2 = validate_type(123, "test_field", (str, int)) | |
assert result2 == 123 | |
def test_validate_type_failure_single_type(self): | |
"""Test type validation failure with single type""" | |
with pytest.raises(ValidationError, match="Field 'test_field' must be of type str, got int"): | |
validate_type(123, "test_field", str) | |
def test_validate_type_failure_multiple_types(self): | |
"""Test type validation failure with multiple types""" | |
with pytest.raises(ValidationError, match="Field 'test_field' must be of type str or int, got float"): | |
validate_type(1.5, "test_field", (str, int)) | |
class TestValidateRange: | |
"""Test cases for validate_range function""" | |
def test_validate_range_success_within_range(self): | |
"""Test successful range validation within range""" | |
result = validate_range(5, "test_field", min_value=1, max_value=10) | |
assert result == 5 | |
def test_validate_range_success_at_boundaries(self): | |
"""Test successful range validation at boundaries""" | |
result1 = validate_range(1, "test_field", min_value=1, max_value=10) | |
assert result1 == 1 | |
result2 = validate_range(10, "test_field", min_value=1, max_value=10) | |
assert result2 == 10 | |
def test_validate_range_success_only_min(self): | |
"""Test successful range validation with only minimum""" | |
result = validate_range(5, "test_field", min_value=1) | |
assert result == 5 | |
def test_validate_range_success_only_max(self): | |
"""Test successful range validation with only maximum""" | |
result = validate_range(5, "test_field", max_value=10) | |
assert result == 5 | |
def test_validate_range_success_no_limits(self): | |
"""Test successful range validation with no limits""" | |
result = validate_range(5, "test_field") | |
assert result == 5 | |
def test_validate_range_failure_below_minimum(self): | |
"""Test range validation failure below minimum""" | |
with pytest.raises(ValidationError, match="Field 'test_field' must be >= 1, got 0"): | |
validate_range(0, "test_field", min_value=1, max_value=10) | |
def test_validate_range_failure_above_maximum(self): | |
"""Test range validation failure above maximum""" | |
with pytest.raises(ValidationError, match="Field 'test_field' must be <= 10, got 11"): | |
validate_range(11, "test_field", min_value=1, max_value=10) | |
def test_validate_range_with_float_values(self): | |
"""Test range validation with float values""" | |
result = validate_range(1.5, "test_field", min_value=1.0, max_value=2.0) | |
assert result == 1.5 | |
class TestValidateChoices: | |
"""Test cases for validate_choices function""" | |
def test_validate_choices_success(self): | |
"""Test successful choices validation""" | |
choices = ["option1", "option2", "option3"] | |
result = validate_choices("option2", "test_field", choices) | |
assert result == "option2" | |
def test_validate_choices_failure(self): | |
"""Test choices validation failure""" | |
choices = ["option1", "option2", "option3"] | |
with pytest.raises(ValidationError, match="Field 'test_field' must be one of \\['option1', 'option2', 'option3'\\], got 'invalid'"): | |
validate_choices("invalid", "test_field", choices) | |
def test_validate_choices_with_different_types(self): | |
"""Test choices validation with different value types""" | |
choices = [1, 2, 3, "four"] | |
result1 = validate_choices(2, "test_field", choices) | |
assert result1 == 2 | |
result2 = validate_choices("four", "test_field", choices) | |
assert result2 == "four" | |
def test_validate_choices_empty_choices(self): | |
"""Test choices validation with empty choices list""" | |
with pytest.raises(ValidationError, match="Field 'test_field' must be one of \\[\\], got 'value'"): | |
validate_choices("value", "test_field", []) |