import re import types from datetime import datetime, timedelta from decimal import Decimal from unittest import TestCase, mock from django.core.exceptions import ValidationError from django.core.files.base import ContentFile from django.core.validators import ( BaseValidator, DecimalValidator, EmailValidator, FileExtensionValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, MinValueValidator, ProhibitNullCharactersValidator, RegexValidator, StepValueValidator, URLValidator, int_list_validator, validate_comma_separated_integer_list, validate_email, validate_image_file_extension, validate_integer, validate_ipv4_address, validate_ipv6_address, validate_ipv46_address, validate_slug, validate_unicode_slug, ) from django.test import SimpleTestCase try: from PIL import Image # noqa except ImportError: PILLOW_IS_INSTALLED = False else: PILLOW_IS_INSTALLED = True NOW = datetime.now() EXTENDED_SCHEMES = ["http", "https", "ftp", "ftps", "git", "file", "git+ssh"] VALID_URLS = [ "http://www.djangoproject.com/", "HTTP://WWW.DJANGOPROJECT.COM/", "http://localhost/", "http://example.com/", "http://example.com:0", "http://example.com:0/", "http://example.com:65535", "http://example.com:65535/", "http://example.com./", "http://www.example.com/", "http://www.example.com:8000/test", "http://valid-with-hyphens.com/", "http://subdomain.example.com/", "http://a.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "http://200.8.9.10/", "http://200.8.9.10:8000/test", "http://su--b.valid-----hyphens.com/", "http://example.com?something=value", "http://example.com/index.php?something=value&another=value2", "https://example.com/", "ftp://example.com/", "ftps://example.com/", "http://foo.com/blah_blah", "http://foo.com/blah_blah/", "http://foo.com/blah_blah_(wikipedia)", "http://foo.com/blah_blah_(wikipedia)_(again)", "http://www.example.com/wpstyle/?p=364", "https://www.example.com/foo/?bar=baz&inga=42&quux", "http://✪df.ws/123", "http://userid@example.com", "http://userid@example.com/", "http://userid@example.com:8080", "http://userid@example.com:8080/", "http://userid@example.com:65535", "http://userid@example.com:65535/", "http://userid:@example.com", "http://userid:@example.com/", "http://userid:@example.com:8080", "http://userid:@example.com:8080/", "http://userid:password@example.com", "http://userid:password@example.com/", "http://userid:password@example.com:8", "http://userid:password@example.com:8/", "http://userid:password@example.com:8080", "http://userid:password@example.com:8080/", "http://userid:password@example.com:65535", "http://userid:password@example.com:65535/", "https://userid:paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaassword@example.com", "https://userid:paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaassword@example.com:8080", "https://useridddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "dddddddddddddddddddddd:password@example.com", "https://useridddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddd:password@example.com:8080", "http://userid:password" + "d" * 2000 + "@example.aaaaaaaaaaaaa.com", "http://142.42.1.1/", "http://142.42.1.1:8080/", "http://➡.ws/䨹", "http://⌘.ws", "http://⌘.ws/", "http://foo.com/blah_(wikipedia)#cite-1", "http://foo.com/blah_(wikipedia)_blah#cite-1", "http://foo.com/unicode_(✪)_in_parens", "http://foo.com/(something)?after=parens", "http://☺.damowmow.com/", "http://djangoproject.com/events/#&product=browser", "http://j.mp", "ftp://foo.bar/baz", "http://foo.bar/?q=Test%20URL-encoded%20stuff", "http://مثال.إختبار", "http://例子.测试", "http://उदाहरण.परीक्षा", "http://-.~_!$&'()*+,;=%40:80%2f@example.com", "http://xn--7sbb4ac0ad0be6cf.xn--p1ai", "http://1337.net", "http://a.b-c.de", "http://223.255.255.254", "ftps://foo.bar/", "http://10.1.1.254", "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", "http://[::192.9.5.5]/ipng", "http://[::ffff:192.9.5.5]/ipng", "http://[::1]:8080/", "http://0.0.0.0/", "http://255.255.255.255", "http://224.0.0.0", "http://224.1.1.1", "http://111.112.113.114/", "http://88.88.88.88/", "http://11.12.13.14/", "http://10.20.30.40/", "http://1.2.3.4/", "http://127.0.01.09.home.lan", "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.ex" "ample.com", "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaa.com", "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "http://dashintld.c-m", "http://multipledashintld.a-b-c", "http://evenmoredashintld.a---c", "http://dashinpunytld.xn---c", ] INVALID_URLS = [ None, 56, "no_scheme", "foo", "http://", "http://example", "http://example.", "http://example.com:-1", "http://example.com:-1/", "http://example.com:000000080", "http://example.com:000000080/", "http://.com", "http://invalid-.com", "http://-invalid.com", "http://invalid.com-", "http://invalid.-com", "http://inv-.alid-.com", "http://inv-.-alid.com", "file://localhost/path", "git://example.com/", "http://.", "http://..", "http://../", "http://?", "http://??", "http://??/", "http://#", "http://##", "http://##/", "http://foo.bar?q=Spaces should be encoded", "//", "//a", "///a", "///", "http:///a", "foo.com", "rdar://1234", "h://test", "http:// shouldfail.com", ":// should fail", "http://foo.bar/foo(bar)baz quux", "http://-error-.invalid/", "http://dashinpunytld.trailingdot.xn--.", "http://dashinpunytld.xn---", "http://-a.b.co", "http://a.b-.co", "http://a.-b.co", "http://a.b-.c.co", "http:/", "http://", "http://", "http://1.1.1.1.1", "http://123.123.123", "http://3628126748", "http://123", "http://000.000.000.000", "http://016.016.016.016", "http://192.168.000.001", "http://01.2.3.4", "http://01.2.3.4", "http://1.02.3.4", "http://1.2.03.4", "http://1.2.3.04", "http://.www.foo.bar/", "http://.www.foo.bar./", "http://[::1:2::3]:8/", "http://[::1:2::3]:8080/", "http://[]", "http://[]:8080", "http://example..com/", "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.e" "xample.com", "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaa.com", "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaa", "http://example." + ("a" * 63 + ".") * 1000 + "com", "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaa." "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaa", "https://test.[com", "http://@example.com", "http://:@example.com", "http://:bar@example.com", "http://foo@bar@example.com", "http://foo/bar@example.com", "http://foo:bar:baz@example.com", "http://foo:bar@baz@example.com", "http://foo:bar/baz@example.com", "http://invalid-.com/?m=foo@example.com", # Newlines and tabs are not accepted. "http://www.djangoproject.com/\n", "http://[::ffff:192.9.5.5]\n", "http://www.djangoproject.com/\r", "http://[::ffff:192.9.5.5]\r", "http://www.django\rproject.com/", "http://[::\rffff:192.9.5.5]", "http://\twww.djangoproject.com/", "http://\t[::ffff:192.9.5.5]", # Trailing junk does not take forever to reject. "http://www.asdasdasdasdsadfm.com.br ", "http://www.asdasdasdasdsadfm.com.br z", ] TEST_DATA = [ # (validator, value, expected), (validate_integer, "42", None), (validate_integer, "-42", None), (validate_integer, -42, None), (validate_integer, -42.5, ValidationError), (validate_integer, None, ValidationError), (validate_integer, "a", ValidationError), (validate_integer, "\n42", ValidationError), (validate_integer, "42\n", ValidationError), (validate_email, "email@here.com", None), (validate_email, "weirder-email@here.and.there.com", None), (validate_email, "email@[127.0.0.1]", None), (validate_email, "email@[2001:dB8::1]", None), (validate_email, "email@[2001:dB8:0:0:0:0:0:1]", None), (validate_email, "email@[::fffF:127.0.0.1]", None), (validate_email, "example@valid-----hyphens.com", None), (validate_email, "example@valid-with-hyphens.com", None), (validate_email, "test@domain.with.idn.tld.उदाहरण.परीक्षा", None), (validate_email, "email@localhost", None), (EmailValidator(allowlist=["localdomain"]), "email@localdomain", None), (validate_email, '"test@test"@example.com', None), (validate_email, "example@atm.%s" % ("a" * 63), None), (validate_email, "example@%s.atm" % ("a" * 63), None), (validate_email, "example@%s.%s.atm" % ("a" * 63, "b" * 10), None), (validate_email, "example@atm.%s" % ("a" * 64), ValidationError), (validate_email, "example@%s.atm.%s" % ("b" * 64, "a" * 63), ValidationError), (validate_email, "example@%scom" % (("a" * 63 + ".") * 100), ValidationError), (validate_email, None, ValidationError), (validate_email, "", ValidationError), (validate_email, "abc", ValidationError), (validate_email, "abc@", ValidationError), (validate_email, "abc@bar", ValidationError), (validate_email, "a @x.cz", ValidationError), (validate_email, "abc@.com", ValidationError), (validate_email, "something@@somewhere.com", ValidationError), (validate_email, "email@127.0.0.1", ValidationError), (validate_email, "email@[127.0.0.256]", ValidationError), (validate_email, "email@[2001:db8::12345]", ValidationError), (validate_email, "email@[2001:db8:0:0:0:0:1]", ValidationError), (validate_email, "email@[::ffff:127.0.0.256]", ValidationError), (validate_email, "email@[2001:dg8::1]", ValidationError), (validate_email, "email@[2001:dG8:0:0:0:0:0:1]", ValidationError), (validate_email, "email@[::fTzF:127.0.0.1]", ValidationError), (validate_email, "example@invalid-.com", ValidationError), (validate_email, "example@-invalid.com", ValidationError), (validate_email, "example@invalid.com-", ValidationError), (validate_email, "example@inv-.alid-.com", ValidationError), (validate_email, "example@inv-.-alid.com", ValidationError), (validate_email, 'test@example.com\n\n