diff --git a/django/core/validators.py b/django/core/validators.py index 5559bca28f7..6f4f5707656 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -40,6 +40,9 @@ class RegexValidator(object): if not self.regex.search(force_text(value)): raise ValidationError(self.message, code=self.code) + def __eq__(self, other): + return isinstance(other, RegexValidator) and (self.regex == other.regex) and (self.message == other.message) and (self.code == other.code) + @deconstructible class URLValidator(RegexValidator): @@ -139,6 +142,9 @@ class EmailValidator(object): pass raise ValidationError(self.message, code=self.code) + def __eq__(self, other): + return isinstance(other, EmailValidator) and (self.domain_whitelist == other.domain_whitelist) and (self.message == other.message) and (self.code == other.code) + validate_email = EmailValidator() slug_re = re.compile(r'^[-a-zA-Z0-9_]+$') @@ -205,6 +211,9 @@ class BaseValidator(object): if self.compare(cleaned, self.limit_value): raise ValidationError(self.message, code=self.code, params=params) + def __eq__(self, other): + return isinstance(other, self.__class__) and (self.limit_value == other.limit_value) and (self.message == other.message) and (self.code == other.code) + @deconstructible class MaxValueValidator(BaseValidator): diff --git a/tests/validators/tests.py b/tests/validators/tests.py index 23fa1e38303..ec91486658a 100644 --- a/tests/validators/tests.py +++ b/tests/validators/tests.py @@ -244,3 +244,59 @@ for validator, value, expected in TEST_DATA: name, method = create_simple_test_method(validator, expected, value, test_counter) setattr(TestSimpleValidators, name, method) test_counter += 1 + + +class TestValidatorEquality(TestCase): + """ + Tests that validators have valid equality operators (#21638) + """ + + def test_regex_equality(self): + self.assertEqual( + RegexValidator(r'^(?:[a-z0-9\.\-]*)://'), + RegexValidator(r'^(?:[a-z0-9\.\-]*)://'), + ) + self.assertNotEqual( + RegexValidator(r'^(?:[a-z0-9\.\-]*)://'), + RegexValidator(r'^(?:[0-9\.\-]*)://'), + ) + self.assertEqual( + RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"), + RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"), + ) + self.assertNotEqual( + RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh", "invalid"), + RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"), + ) + self.assertNotEqual( + RegexValidator(r'^(?:[a-z0-9\.\-]*)://', "oh noes", "invalid"), + RegexValidator(r'^(?:[a-z0-9\.\-]*)://'), + ) + + def test_email_equality(self): + self.assertEqual( + EmailValidator(), + EmailValidator(), + ) + self.assertNotEqual( + EmailValidator(message="BAD EMAIL"), + EmailValidator(), + ) + self.assertEqual( + EmailValidator(message="BAD EMAIL", code="bad"), + EmailValidator(message="BAD EMAIL", code="bad"), + ) + + def test_basic_equality(self): + self.assertEqual( + MaxValueValidator(44), + MaxValueValidator(44), + ) + self.assertNotEqual( + MaxValueValidator(44), + MinValueValidator(44), + ) + self.assertNotEqual( + MinValueValidator(45), + MinValueValidator(11), + )