"""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: def test_all_of_passes_when_all_checks_pass(self) -> None: 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: 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: 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: 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: 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: with pytest.raises(ValueError, match="cannot be empty"): AllOf(checks=[]) def test_all_of_name_property(self) -> None: validator = AllOf(checks=[length(min_chars=1)]) assert validator.name == "all_of" def test_all_of_factory_function(self) -> None: validator = all_of(checks=[length(min_chars=1)]) assert isinstance(validator, AllOf) class TestAnyOf: def test_any_of_passes_when_any_check_passes(self) -> None: 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: 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: 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: 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: 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: with pytest.raises(ValueError, match="cannot be empty"): AnyOf(checks=[]) def test_any_of_name_property(self) -> None: validator = AnyOf(checks=[length(min_chars=1)]) assert validator.name == "any_of" def test_any_of_factory_function(self) -> None: validator = any_of(checks=[length(min_chars=1)]) assert isinstance(validator, AnyOf)