test(validators): add validator tests
Add comprehensive tests for metric validators, constraint validators, and composite validators covering pass/fail cases and error handling.
This commit is contained in:
198
tests/test_validators/test_composite.py
Normal file
198
tests/test_validators/test_composite.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""Tests for composite validators."""
|
||||
|
||||
import pytest
|
||||
|
||||
from veritext.core.types import ValidationContext
|
||||
from veritext.validators import all_of, any_of, bleu, contains, excludes, length
|
||||
from veritext.validators.composite import AllOf, AnyOf
|
||||
|
||||
|
||||
class TestAllOf:
|
||||
"""Tests for AllOf composite validator."""
|
||||
|
||||
def test_all_of_passes_when_all_checks_pass(self) -> None:
|
||||
"""Test that AllOf passes when all checks pass."""
|
||||
validator = AllOf(
|
||||
checks=[
|
||||
length(min_words=2),
|
||||
contains(patterns=["hello"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello world", context)
|
||||
|
||||
assert result.passed is True
|
||||
assert len(result.checks) == 2
|
||||
assert all(c.passed for c in result.checks)
|
||||
|
||||
def test_all_of_fails_when_one_check_fails(self) -> None:
|
||||
"""Test that AllOf fails when any check fails."""
|
||||
validator = AllOf(
|
||||
checks=[
|
||||
length(min_words=2),
|
||||
contains(patterns=["goodbye"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello world", context)
|
||||
|
||||
assert result.passed is False
|
||||
assert len(result.checks) == 2
|
||||
assert len(result.failed_checks) == 1
|
||||
|
||||
def test_all_of_fails_when_all_checks_fail(self) -> None:
|
||||
"""Test that AllOf fails when all checks fail."""
|
||||
validator = AllOf(
|
||||
checks=[
|
||||
length(min_words=10),
|
||||
contains(patterns=["goodbye"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello", context)
|
||||
|
||||
assert result.passed is False
|
||||
assert len(result.failed_checks) == 2
|
||||
|
||||
def test_all_of_with_metric_validators(self) -> None:
|
||||
"""Test AllOf with metric-based validators."""
|
||||
validator = AllOf(
|
||||
checks=[
|
||||
bleu(min_score=0.5),
|
||||
length(min_words=3),
|
||||
]
|
||||
)
|
||||
context = ValidationContext(reference="the quick brown fox")
|
||||
result = validator.check("the quick brown fox jumps", context)
|
||||
|
||||
assert result.passed is True
|
||||
assert len(result.checks) == 2
|
||||
|
||||
def test_all_of_failure_summary(self) -> None:
|
||||
"""Test the failure summary property."""
|
||||
validator = AllOf(
|
||||
checks=[
|
||||
length(min_words=10),
|
||||
contains(patterns=["goodbye"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello", context)
|
||||
|
||||
summary = result.failure_summary
|
||||
assert "failed" in summary.lower()
|
||||
assert "length" in summary
|
||||
assert "contains" in summary
|
||||
|
||||
def test_all_of_raises_on_empty_checks(self) -> None:
|
||||
"""Test that empty checks list raises error."""
|
||||
with pytest.raises(ValueError, match="cannot be empty"):
|
||||
AllOf(checks=[])
|
||||
|
||||
def test_all_of_name_property(self) -> None:
|
||||
"""Test the name property."""
|
||||
validator = AllOf(checks=[length(min_chars=1)])
|
||||
assert validator.name == "all_of"
|
||||
|
||||
def test_all_of_factory_function(self) -> None:
|
||||
"""Test the all_of() factory function."""
|
||||
validator = all_of(checks=[length(min_chars=1)])
|
||||
assert isinstance(validator, AllOf)
|
||||
|
||||
|
||||
class TestAnyOf:
|
||||
"""Tests for AnyOf composite validator."""
|
||||
|
||||
def test_any_of_passes_when_any_check_passes(self) -> None:
|
||||
"""Test that AnyOf passes when any check passes."""
|
||||
validator = AnyOf(
|
||||
checks=[
|
||||
length(min_words=10), # Will fail
|
||||
contains(patterns=["hello"]), # Will pass
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello world", context)
|
||||
|
||||
assert result.passed is True
|
||||
assert len(result.checks) == 2
|
||||
# At least one check passed
|
||||
assert any(c.passed for c in result.checks)
|
||||
|
||||
def test_any_of_passes_when_all_checks_pass(self) -> None:
|
||||
"""Test that AnyOf passes when all checks pass."""
|
||||
validator = AnyOf(
|
||||
checks=[
|
||||
length(min_words=2),
|
||||
contains(patterns=["hello"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello world", context)
|
||||
|
||||
assert result.passed is True
|
||||
assert all(c.passed for c in result.checks)
|
||||
|
||||
def test_any_of_fails_when_all_checks_fail(self) -> None:
|
||||
"""Test that AnyOf fails when all checks fail."""
|
||||
validator = AnyOf(
|
||||
checks=[
|
||||
length(min_words=10),
|
||||
contains(patterns=["goodbye"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
result = validator.check("hello", context)
|
||||
|
||||
assert result.passed is False
|
||||
assert not any(c.passed for c in result.checks)
|
||||
|
||||
def test_any_of_with_metric_validators(self) -> None:
|
||||
"""Test AnyOf with metric-based validators."""
|
||||
validator = AnyOf(
|
||||
checks=[
|
||||
bleu(min_score=0.9), # Might fail
|
||||
length(min_words=3), # Should pass
|
||||
]
|
||||
)
|
||||
context = ValidationContext(reference="different text entirely")
|
||||
result = validator.check("the quick brown fox jumps", context)
|
||||
|
||||
assert result.passed is True # Length check passes
|
||||
|
||||
def test_any_of_with_excludes(self) -> None:
|
||||
"""Test AnyOf with excludes validator."""
|
||||
validator = AnyOf(
|
||||
checks=[
|
||||
excludes(patterns=["error"]),
|
||||
excludes(patterns=["warning"]),
|
||||
]
|
||||
)
|
||||
context = ValidationContext()
|
||||
|
||||
# Should pass - neither pattern found
|
||||
result = validator.check("All is well", context)
|
||||
assert result.passed is True
|
||||
|
||||
# Should pass - one pattern found, other not
|
||||
result = validator.check("This is an error", context)
|
||||
assert result.passed is True
|
||||
|
||||
# Should fail - both patterns found
|
||||
result = validator.check("error and warning", context)
|
||||
assert result.passed is False
|
||||
|
||||
def test_any_of_raises_on_empty_checks(self) -> None:
|
||||
"""Test that empty checks list raises error."""
|
||||
with pytest.raises(ValueError, match="cannot be empty"):
|
||||
AnyOf(checks=[])
|
||||
|
||||
def test_any_of_name_property(self) -> None:
|
||||
"""Test the name property."""
|
||||
validator = AnyOf(checks=[length(min_chars=1)])
|
||||
assert validator.name == "any_of"
|
||||
|
||||
def test_any_of_factory_function(self) -> None:
|
||||
"""Test the any_of() factory function."""
|
||||
validator = any_of(checks=[length(min_chars=1)])
|
||||
assert isinstance(validator, AnyOf)
|
||||
Reference in New Issue
Block a user