1. import re
    
  2. import types
    
  3. from datetime import datetime, timedelta
    
  4. from decimal import Decimal
    
  5. from unittest import TestCase, mock
    
  6. 
    
  7. from django.core.exceptions import ValidationError
    
  8. from django.core.files.base import ContentFile
    
  9. from django.core.validators import (
    
  10.     BaseValidator,
    
  11.     DecimalValidator,
    
  12.     EmailValidator,
    
  13.     FileExtensionValidator,
    
  14.     MaxLengthValidator,
    
  15.     MaxValueValidator,
    
  16.     MinLengthValidator,
    
  17.     MinValueValidator,
    
  18.     ProhibitNullCharactersValidator,
    
  19.     RegexValidator,
    
  20.     StepValueValidator,
    
  21.     URLValidator,
    
  22.     int_list_validator,
    
  23.     validate_comma_separated_integer_list,
    
  24.     validate_email,
    
  25.     validate_image_file_extension,
    
  26.     validate_integer,
    
  27.     validate_ipv4_address,
    
  28.     validate_ipv6_address,
    
  29.     validate_ipv46_address,
    
  30.     validate_slug,
    
  31.     validate_unicode_slug,
    
  32. )
    
  33. from django.test import SimpleTestCase
    
  34. 
    
  35. try:
    
  36.     from PIL import Image  # noqa
    
  37. except ImportError:
    
  38.     PILLOW_IS_INSTALLED = False
    
  39. else:
    
  40.     PILLOW_IS_INSTALLED = True
    
  41. 
    
  42. NOW = datetime.now()
    
  43. EXTENDED_SCHEMES = ["http", "https", "ftp", "ftps", "git", "file", "git+ssh"]
    
  44. 
    
  45. VALID_URLS = [
    
  46.     "http://www.djangoproject.com/",
    
  47.     "HTTP://WWW.DJANGOPROJECT.COM/",
    
  48.     "http://localhost/",
    
  49.     "http://example.com/",
    
  50.     "http://example.com:0",
    
  51.     "http://example.com:0/",
    
  52.     "http://example.com:65535",
    
  53.     "http://example.com:65535/",
    
  54.     "http://example.com./",
    
  55.     "http://www.example.com/",
    
  56.     "http://www.example.com:8000/test",
    
  57.     "http://valid-with-hyphens.com/",
    
  58.     "http://subdomain.example.com/",
    
  59.     "http://a.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    
  60.     "http://200.8.9.10/",
    
  61.     "http://200.8.9.10:8000/test",
    
  62.     "http://su--b.valid-----hyphens.com/",
    
  63.     "http://example.com?something=value",
    
  64.     "http://example.com/index.php?something=value&another=value2",
    
  65.     "https://example.com/",
    
  66.     "ftp://example.com/",
    
  67.     "ftps://example.com/",
    
  68.     "http://foo.com/blah_blah",
    
  69.     "http://foo.com/blah_blah/",
    
  70.     "http://foo.com/blah_blah_(wikipedia)",
    
  71.     "http://foo.com/blah_blah_(wikipedia)_(again)",
    
  72.     "http://www.example.com/wpstyle/?p=364",
    
  73.     "https://www.example.com/foo/?bar=baz&inga=42&quux",
    
  74.     "http://✪df.ws/123",
    
  75.     "http://[email protected]",
    
  76.     "http://[email protected]/",
    
  77.     "http://[email protected]:8080",
    
  78.     "http://[email protected]:8080/",
    
  79.     "http://[email protected]:65535",
    
  80.     "http://[email protected]:65535/",
    
  81.     "http://userid:@example.com",
    
  82.     "http://userid:@example.com/",
    
  83.     "http://userid:@example.com:8080",
    
  84.     "http://userid:@example.com:8080/",
    
  85.     "http://userid:[email protected]",
    
  86.     "http://userid:[email protected]/",
    
  87.     "http://userid:[email protected]:8",
    
  88.     "http://userid:[email protected]:8/",
    
  89.     "http://userid:[email protected]:8080",
    
  90.     "http://userid:[email protected]:8080/",
    
  91.     "http://userid:[email protected]:65535",
    
  92.     "http://userid:[email protected]:65535/",
    
  93.     "https://userid:paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  94.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  95.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  96.     "[email protected]",
    
  97.     "https://userid:paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  98.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  99.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  100.     "[email protected]:8080",
    
  101.     "https://useridddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  102.     "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  103.     "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  104.     "dddddddddddddddddddddd:[email protected]",
    
  105.     "https://useridddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  106.     "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  107.     "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
    
  108.     "ddddddddddddddddd:[email protected]:8080",
    
  109.     "http://userid:password" + "d" * 2000 + "@example.aaaaaaaaaaaaa.com",
    
  110.     "http://142.42.1.1/",
    
  111.     "http://142.42.1.1:8080/",
    
  112.     "http://➡.ws/䨹",
    
  113.     "http://⌘.ws",
    
  114.     "http://⌘.ws/",
    
  115.     "http://foo.com/blah_(wikipedia)#cite-1",
    
  116.     "http://foo.com/blah_(wikipedia)_blah#cite-1",
    
  117.     "http://foo.com/unicode_(✪)_in_parens",
    
  118.     "http://foo.com/(something)?after=parens",
    
  119.     "http://☺.damowmow.com/",
    
  120.     "http://djangoproject.com/events/#&product=browser",
    
  121.     "http://j.mp",
    
  122.     "ftp://foo.bar/baz",
    
  123.     "http://foo.bar/?q=Test%20URL-encoded%20stuff",
    
  124.     "http://مثال.إختبار",
    
  125.     "http://例子.测试",
    
  126.     "http://उदाहरण.परीक्षा",
    
  127.     "http://-.~_!$&'()*+,;=%40:80%2f@example.com",
    
  128.     "http://xn--7sbb4ac0ad0be6cf.xn--p1ai",
    
  129.     "http://1337.net",
    
  130.     "http://a.b-c.de",
    
  131.     "http://223.255.255.254",
    
  132.     "ftps://foo.bar/",
    
  133.     "http://10.1.1.254",
    
  134.     "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html",
    
  135.     "http://[::192.9.5.5]/ipng",
    
  136.     "http://[::ffff:192.9.5.5]/ipng",
    
  137.     "http://[::1]:8080/",
    
  138.     "http://0.0.0.0/",
    
  139.     "http://255.255.255.255",
    
  140.     "http://224.0.0.0",
    
  141.     "http://224.1.1.1",
    
  142.     "http://111.112.113.114/",
    
  143.     "http://88.88.88.88/",
    
  144.     "http://11.12.13.14/",
    
  145.     "http://10.20.30.40/",
    
  146.     "http://1.2.3.4/",
    
  147.     "http://127.0.01.09.home.lan",
    
  148.     "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.ex"
    
  149.     "ample.com",
    
  150.     "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  151.     "aaaaa.com",
    
  152.     "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    
  153.     "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaa"
    
  154.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaa"
    
  155.     "aaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaa"
    
  156.     "aaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    
  157.     "http://dashintld.c-m",
    
  158.     "http://multipledashintld.a-b-c",
    
  159.     "http://evenmoredashintld.a---c",
    
  160.     "http://dashinpunytld.xn---c",
    
  161. ]
    
  162. 
    
  163. INVALID_URLS = [
    
  164.     None,
    
  165.     56,
    
  166.     "no_scheme",
    
  167.     "foo",
    
  168.     "http://",
    
  169.     "http://example",
    
  170.     "http://example.",
    
  171.     "http://example.com:-1",
    
  172.     "http://example.com:-1/",
    
  173.     "http://example.com:000000080",
    
  174.     "http://example.com:000000080/",
    
  175.     "http://.com",
    
  176.     "http://invalid-.com",
    
  177.     "http://-invalid.com",
    
  178.     "http://invalid.com-",
    
  179.     "http://invalid.-com",
    
  180.     "http://inv-.alid-.com",
    
  181.     "http://inv-.-alid.com",
    
  182.     "file://localhost/path",
    
  183.     "git://example.com/",
    
  184.     "http://.",
    
  185.     "http://..",
    
  186.     "http://../",
    
  187.     "http://?",
    
  188.     "http://??",
    
  189.     "http://??/",
    
  190.     "http://#",
    
  191.     "http://##",
    
  192.     "http://##/",
    
  193.     "http://foo.bar?q=Spaces should be encoded",
    
  194.     "//",
    
  195.     "//a",
    
  196.     "///a",
    
  197.     "///",
    
  198.     "http:///a",
    
  199.     "foo.com",
    
  200.     "rdar://1234",
    
  201.     "h://test",
    
  202.     "http:// shouldfail.com",
    
  203.     ":// should fail",
    
  204.     "http://foo.bar/foo(bar)baz quux",
    
  205.     "http://-error-.invalid/",
    
  206.     "http://dashinpunytld.trailingdot.xn--.",
    
  207.     "http://dashinpunytld.xn---",
    
  208.     "http://-a.b.co",
    
  209.     "http://a.b-.co",
    
  210.     "http://a.-b.co",
    
  211.     "http://a.b-.c.co",
    
  212.     "http:/",
    
  213.     "http://",
    
  214.     "http://",
    
  215.     "http://1.1.1.1.1",
    
  216.     "http://123.123.123",
    
  217.     "http://3628126748",
    
  218.     "http://123",
    
  219.     "http://000.000.000.000",
    
  220.     "http://016.016.016.016",
    
  221.     "http://192.168.000.001",
    
  222.     "http://01.2.3.4",
    
  223.     "http://01.2.3.4",
    
  224.     "http://1.02.3.4",
    
  225.     "http://1.2.03.4",
    
  226.     "http://1.2.3.04",
    
  227.     "http://.www.foo.bar/",
    
  228.     "http://.www.foo.bar./",
    
  229.     "http://[::1:2::3]:8/",
    
  230.     "http://[::1:2::3]:8080/",
    
  231.     "http://[]",
    
  232.     "http://[]:8080",
    
  233.     "http://example..com/",
    
  234.     "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.e"
    
  235.     "xample.com",
    
  236.     "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  237.     "aaaaaa.com",
    
  238.     "http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    
  239.     "aaaaaa",
    
  240.     "http://example." + ("a" * 63 + ".") * 1000 + "com",
    
  241.     "http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
    
  242.     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaa"
    
  243.     "aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaa"
    
  244.     "aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaa",
    
  245.     "https://test.[com",
    
  246.     "http://@example.com",
    
  247.     "http://:@example.com",
    
  248.     "http://:[email protected]",
    
  249.     "http://foo@[email protected]",
    
  250.     "http://foo/[email protected]",
    
  251.     "http://foo:bar:[email protected]",
    
  252.     "http://foo:bar@[email protected]",
    
  253.     "http://foo:bar/[email protected]",
    
  254.     "http://invalid-.com/[email protected]",
    
  255.     # Newlines and tabs are not accepted.
    
  256.     "http://www.djangoproject.com/\n",
    
  257.     "http://[::ffff:192.9.5.5]\n",
    
  258.     "http://www.djangoproject.com/\r",
    
  259.     "http://[::ffff:192.9.5.5]\r",
    
  260.     "http://www.django\rproject.com/",
    
  261.     "http://[::\rffff:192.9.5.5]",
    
  262.     "http://\twww.djangoproject.com/",
    
  263.     "http://\t[::ffff:192.9.5.5]",
    
  264.     # Trailing junk does not take forever to reject.
    
  265.     "http://www.asdasdasdasdsadfm.com.br ",
    
  266.     "http://www.asdasdasdasdsadfm.com.br z",
    
  267. ]
    
  268. 
    
  269. TEST_DATA = [
    
  270.     # (validator, value, expected),
    
  271.     (validate_integer, "42", None),
    
  272.     (validate_integer, "-42", None),
    
  273.     (validate_integer, -42, None),
    
  274.     (validate_integer, -42.5, ValidationError),
    
  275.     (validate_integer, None, ValidationError),
    
  276.     (validate_integer, "a", ValidationError),
    
  277.     (validate_integer, "\n42", ValidationError),
    
  278.     (validate_integer, "42\n", ValidationError),
    
  279.     (validate_email, "[email protected]", None),
    
  280.     (validate_email, "[email protected]", None),
    
  281.     (validate_email, "email@[127.0.0.1]", None),
    
  282.     (validate_email, "email@[2001:dB8::1]", None),
    
  283.     (validate_email, "email@[2001:dB8:0:0:0:0:0:1]", None),
    
  284.     (validate_email, "email@[::fffF:127.0.0.1]", None),
    
  285.     (validate_email, "[email protected]", None),
    
  286.     (validate_email, "[email protected]", None),
    
  287.     (validate_email, "[email protected].उदाहरण.परीक्षा", None),
    
  288.     (validate_email, "email@localhost", None),
    
  289.     (EmailValidator(allowlist=["localdomain"]), "email@localdomain", None),
    
  290.     (validate_email, '"test@test"@example.com', None),
    
  291.     (validate_email, "example@atm.%s" % ("a" * 63), None),
    
  292.     (validate_email, "example@%s.atm" % ("a" * 63), None),
    
  293.     (validate_email, "example@%s.%s.atm" % ("a" * 63, "b" * 10), None),
    
  294.     (validate_email, "example@atm.%s" % ("a" * 64), ValidationError),
    
  295.     (validate_email, "example@%s.atm.%s" % ("b" * 64, "a" * 63), ValidationError),
    
  296.     (validate_email, "example@%scom" % (("a" * 63 + ".") * 100), ValidationError),
    
  297.     (validate_email, None, ValidationError),
    
  298.     (validate_email, "", ValidationError),
    
  299.     (validate_email, "abc", ValidationError),
    
  300.     (validate_email, "abc@", ValidationError),
    
  301.     (validate_email, "abc@bar", ValidationError),
    
  302.     (validate_email, "a @x.cz", ValidationError),
    
  303.     (validate_email, "[email protected]", ValidationError),
    
  304.     (validate_email, "something@@somewhere.com", ValidationError),
    
  305.     (validate_email, "[email protected]", ValidationError),
    
  306.     (validate_email, "email@[127.0.0.256]", ValidationError),
    
  307.     (validate_email, "email@[2001:db8::12345]", ValidationError),
    
  308.     (validate_email, "email@[2001:db8:0:0:0:0:1]", ValidationError),
    
  309.     (validate_email, "email@[::ffff:127.0.0.256]", ValidationError),
    
  310.     (validate_email, "email@[2001:dg8::1]", ValidationError),
    
  311.     (validate_email, "email@[2001:dG8:0:0:0:0:0:1]", ValidationError),
    
  312.     (validate_email, "email@[::fTzF:127.0.0.1]", ValidationError),
    
  313.     (validate_email, "[email protected]", ValidationError),
    
  314.     (validate_email, "[email protected]", ValidationError),
    
  315.     (validate_email, "[email protected]", ValidationError),
    
  316.     (validate_email, "[email protected]", ValidationError),
    
  317.     (validate_email, "[email protected]", ValidationError),
    
  318.     (validate_email, '[email protected]\n\n<script src="x.js">', ValidationError),
    
  319.     # Quoted-string format (CR not allowed)
    
  320.     (validate_email, '"\\\011"@here.com', None),
    
  321.     (validate_email, '"\\\012"@here.com', ValidationError),
    
  322.     (validate_email, "[email protected].", ValidationError),
    
  323.     # Max length of domain name labels is 63 characters per RFC 1034.
    
  324.     (validate_email, "a@%s.us" % ("a" * 63), None),
    
  325.     (validate_email, "a@%s.us" % ("a" * 64), ValidationError),
    
  326.     # Trailing newlines in username or domain not allowed
    
  327.     (validate_email, "[email protected]\n", ValidationError),
    
  328.     (validate_email, "a\n@b.com", ValidationError),
    
  329.     (validate_email, '"test@test"\n@example.com', ValidationError),
    
  330.     (validate_email, "a@[127.0.0.1]\n", ValidationError),
    
  331.     (validate_slug, "slug-ok", None),
    
  332.     (validate_slug, "longer-slug-still-ok", None),
    
  333.     (validate_slug, "--------", None),
    
  334.     (validate_slug, "nohyphensoranything", None),
    
  335.     (validate_slug, "a", None),
    
  336.     (validate_slug, "1", None),
    
  337.     (validate_slug, "a1", None),
    
  338.     (validate_slug, "", ValidationError),
    
  339.     (validate_slug, " text ", ValidationError),
    
  340.     (validate_slug, " ", ValidationError),
    
  341.     (validate_slug, "[email protected]", ValidationError),
    
  342.     (validate_slug, "你好", ValidationError),
    
  343.     (validate_slug, "你 好", ValidationError),
    
  344.     (validate_slug, "\n", ValidationError),
    
  345.     (validate_slug, "trailing-newline\n", ValidationError),
    
  346.     (validate_unicode_slug, "slug-ok", None),
    
  347.     (validate_unicode_slug, "longer-slug-still-ok", None),
    
  348.     (validate_unicode_slug, "--------", None),
    
  349.     (validate_unicode_slug, "nohyphensoranything", None),
    
  350.     (validate_unicode_slug, "a", None),
    
  351.     (validate_unicode_slug, "1", None),
    
  352.     (validate_unicode_slug, "a1", None),
    
  353.     (validate_unicode_slug, "你好", None),
    
  354.     (validate_unicode_slug, "", ValidationError),
    
  355.     (validate_unicode_slug, " text ", ValidationError),
    
  356.     (validate_unicode_slug, " ", ValidationError),
    
  357.     (validate_unicode_slug, "[email protected]", ValidationError),
    
  358.     (validate_unicode_slug, "\n", ValidationError),
    
  359.     (validate_unicode_slug, "你 好", ValidationError),
    
  360.     (validate_unicode_slug, "trailing-newline\n", ValidationError),
    
  361.     (validate_ipv4_address, "1.1.1.1", None),
    
  362.     (validate_ipv4_address, "255.0.0.0", None),
    
  363.     (validate_ipv4_address, "0.0.0.0", None),
    
  364.     (validate_ipv4_address, "256.1.1.1", ValidationError),
    
  365.     (validate_ipv4_address, "25.1.1.", ValidationError),
    
  366.     (validate_ipv4_address, "25,1,1,1", ValidationError),
    
  367.     (validate_ipv4_address, "25.1 .1.1", ValidationError),
    
  368.     (validate_ipv4_address, "1.1.1.1\n", ValidationError),
    
  369.     (validate_ipv4_address, "٧.2٥.3٣.243", ValidationError),
    
  370.     # Leading zeros are forbidden to avoid ambiguity with the octal notation.
    
  371.     (validate_ipv4_address, "000.000.000.000", ValidationError),
    
  372.     (validate_ipv4_address, "016.016.016.016", ValidationError),
    
  373.     (validate_ipv4_address, "192.168.000.001", ValidationError),
    
  374.     (validate_ipv4_address, "01.2.3.4", ValidationError),
    
  375.     (validate_ipv4_address, "01.2.3.4", ValidationError),
    
  376.     (validate_ipv4_address, "1.02.3.4", ValidationError),
    
  377.     (validate_ipv4_address, "1.2.03.4", ValidationError),
    
  378.     (validate_ipv4_address, "1.2.3.04", ValidationError),
    
  379.     # validate_ipv6_address uses django.utils.ipv6, which
    
  380.     # is tested in much greater detail in its own testcase
    
  381.     (validate_ipv6_address, "fe80::1", None),
    
  382.     (validate_ipv6_address, "::1", None),
    
  383.     (validate_ipv6_address, "1:2:3:4:5:6:7:8", None),
    
  384.     (validate_ipv6_address, "1:2", ValidationError),
    
  385.     (validate_ipv6_address, "::zzz", ValidationError),
    
  386.     (validate_ipv6_address, "12345::", ValidationError),
    
  387.     (validate_ipv46_address, "1.1.1.1", None),
    
  388.     (validate_ipv46_address, "255.0.0.0", None),
    
  389.     (validate_ipv46_address, "0.0.0.0", None),
    
  390.     (validate_ipv46_address, "fe80::1", None),
    
  391.     (validate_ipv46_address, "::1", None),
    
  392.     (validate_ipv46_address, "1:2:3:4:5:6:7:8", None),
    
  393.     (validate_ipv46_address, "256.1.1.1", ValidationError),
    
  394.     (validate_ipv46_address, "25.1.1.", ValidationError),
    
  395.     (validate_ipv46_address, "25,1,1,1", ValidationError),
    
  396.     (validate_ipv46_address, "25.1 .1.1", ValidationError),
    
  397.     (validate_ipv46_address, "1:2", ValidationError),
    
  398.     (validate_ipv46_address, "::zzz", ValidationError),
    
  399.     (validate_ipv46_address, "12345::", ValidationError),
    
  400.     # Leading zeros are forbidden to avoid ambiguity with the octal notation.
    
  401.     (validate_ipv46_address, "000.000.000.000", ValidationError),
    
  402.     (validate_ipv46_address, "016.016.016.016", ValidationError),
    
  403.     (validate_ipv46_address, "192.168.000.001", ValidationError),
    
  404.     (validate_ipv46_address, "01.2.3.4", ValidationError),
    
  405.     (validate_ipv46_address, "01.2.3.4", ValidationError),
    
  406.     (validate_ipv46_address, "1.02.3.4", ValidationError),
    
  407.     (validate_ipv46_address, "1.2.03.4", ValidationError),
    
  408.     (validate_ipv46_address, "1.2.3.04", ValidationError),
    
  409.     (validate_comma_separated_integer_list, "1", None),
    
  410.     (validate_comma_separated_integer_list, "12", None),
    
  411.     (validate_comma_separated_integer_list, "1,2", None),
    
  412.     (validate_comma_separated_integer_list, "1,2,3", None),
    
  413.     (validate_comma_separated_integer_list, "10,32", None),
    
  414.     (validate_comma_separated_integer_list, "", ValidationError),
    
  415.     (validate_comma_separated_integer_list, "a", ValidationError),
    
  416.     (validate_comma_separated_integer_list, "a,b,c", ValidationError),
    
  417.     (validate_comma_separated_integer_list, "1, 2, 3", ValidationError),
    
  418.     (validate_comma_separated_integer_list, ",", ValidationError),
    
  419.     (validate_comma_separated_integer_list, "1,2,3,", ValidationError),
    
  420.     (validate_comma_separated_integer_list, "1,2,", ValidationError),
    
  421.     (validate_comma_separated_integer_list, ",1", ValidationError),
    
  422.     (validate_comma_separated_integer_list, "1,,2", ValidationError),
    
  423.     (int_list_validator(sep="."), "1.2.3", None),
    
  424.     (int_list_validator(sep=".", allow_negative=True), "1.2.3", None),
    
  425.     (int_list_validator(allow_negative=True), "-1,-2,3", None),
    
  426.     (int_list_validator(allow_negative=True), "1,-2,-12", None),
    
  427.     (int_list_validator(), "-1,2,3", ValidationError),
    
  428.     (int_list_validator(sep="."), "1,2,3", ValidationError),
    
  429.     (int_list_validator(sep="."), "1.2.3\n", ValidationError),
    
  430.     (MaxValueValidator(10), 10, None),
    
  431.     (MaxValueValidator(10), -10, None),
    
  432.     (MaxValueValidator(10), 0, None),
    
  433.     (MaxValueValidator(NOW), NOW, None),
    
  434.     (MaxValueValidator(NOW), NOW - timedelta(days=1), None),
    
  435.     (MaxValueValidator(0), 1, ValidationError),
    
  436.     (MaxValueValidator(NOW), NOW + timedelta(days=1), ValidationError),
    
  437.     (MinValueValidator(-10), -10, None),
    
  438.     (MinValueValidator(-10), 10, None),
    
  439.     (MinValueValidator(-10), 0, None),
    
  440.     (MinValueValidator(NOW), NOW, None),
    
  441.     (MinValueValidator(NOW), NOW + timedelta(days=1), None),
    
  442.     (MinValueValidator(0), -1, ValidationError),
    
  443.     (MinValueValidator(NOW), NOW - timedelta(days=1), ValidationError),
    
  444.     # limit_value may be a callable.
    
  445.     (MinValueValidator(lambda: 1), 0, ValidationError),
    
  446.     (MinValueValidator(lambda: 1), 1, None),
    
  447.     (StepValueValidator(3), 0, None),
    
  448.     (MaxLengthValidator(10), "", None),
    
  449.     (MaxLengthValidator(10), 10 * "x", None),
    
  450.     (MaxLengthValidator(10), 15 * "x", ValidationError),
    
  451.     (MinLengthValidator(10), 15 * "x", None),
    
  452.     (MinLengthValidator(10), 10 * "x", None),
    
  453.     (MinLengthValidator(10), "", ValidationError),
    
  454.     (StepValueValidator(3), 1, ValidationError),
    
  455.     (StepValueValidator(3), 8, ValidationError),
    
  456.     (StepValueValidator(3), 9, None),
    
  457.     (StepValueValidator(0.001), 0.55, None),
    
  458.     (StepValueValidator(0.001), 0.5555, ValidationError),
    
  459.     (StepValueValidator(Decimal(0.02)), 0.88, None),
    
  460.     (StepValueValidator(Decimal(0.02)), Decimal(0.88), None),
    
  461.     (StepValueValidator(Decimal(0.02)), Decimal(0.77), ValidationError),
    
  462.     (URLValidator(EXTENDED_SCHEMES), "file://localhost/path", None),
    
  463.     (URLValidator(EXTENDED_SCHEMES), "git://example.com/", None),
    
  464.     (
    
  465.         URLValidator(EXTENDED_SCHEMES),
    
  466.         "git+ssh://[email protected]/example/hg-git.git",
    
  467.         None,
    
  468.     ),
    
  469.     (URLValidator(EXTENDED_SCHEMES), "git://-invalid.com", ValidationError),
    
  470.     (BaseValidator(True), True, None),
    
  471.     (BaseValidator(True), False, ValidationError),
    
  472.     (RegexValidator(), "", None),
    
  473.     (RegexValidator(), "x1x2", None),
    
  474.     (RegexValidator("[0-9]+"), "xxxxxx", ValidationError),
    
  475.     (RegexValidator("[0-9]+"), "1234", None),
    
  476.     (RegexValidator(re.compile("[0-9]+")), "1234", None),
    
  477.     (RegexValidator(".*"), "", None),
    
  478.     (RegexValidator(re.compile(".*")), "", None),
    
  479.     (RegexValidator(".*"), "xxxxx", None),
    
  480.     (RegexValidator("x"), "y", ValidationError),
    
  481.     (RegexValidator(re.compile("x")), "y", ValidationError),
    
  482.     (RegexValidator("x", inverse_match=True), "y", None),
    
  483.     (RegexValidator(re.compile("x"), inverse_match=True), "y", None),
    
  484.     (RegexValidator("x", inverse_match=True), "x", ValidationError),
    
  485.     (RegexValidator(re.compile("x"), inverse_match=True), "x", ValidationError),
    
  486.     (RegexValidator("x", flags=re.IGNORECASE), "y", ValidationError),
    
  487.     (RegexValidator("a"), "A", ValidationError),
    
  488.     (RegexValidator("a", flags=re.IGNORECASE), "A", None),
    
  489.     (
    
  490.         FileExtensionValidator(["txt"]),
    
  491.         ContentFile("contents", name="fileWithUnsupportedExt.jpg"),
    
  492.         ValidationError,
    
  493.     ),
    
  494.     (
    
  495.         FileExtensionValidator(["txt"]),
    
  496.         ContentFile("contents", name="fileWithUnsupportedExt.JPG"),
    
  497.         ValidationError,
    
  498.     ),
    
  499.     (
    
  500.         FileExtensionValidator(["txt"]),
    
  501.         ContentFile("contents", name="fileWithNoExtension"),
    
  502.         ValidationError,
    
  503.     ),
    
  504.     (
    
  505.         FileExtensionValidator([""]),
    
  506.         ContentFile("contents", name="fileWithAnExtension.txt"),
    
  507.         ValidationError,
    
  508.     ),
    
  509.     (
    
  510.         FileExtensionValidator([]),
    
  511.         ContentFile("contents", name="file.txt"),
    
  512.         ValidationError,
    
  513.     ),
    
  514.     (
    
  515.         FileExtensionValidator([""]),
    
  516.         ContentFile("contents", name="fileWithNoExtension"),
    
  517.         None,
    
  518.     ),
    
  519.     (FileExtensionValidator(["txt"]), ContentFile("contents", name="file.txt"), None),
    
  520.     (FileExtensionValidator(["txt"]), ContentFile("contents", name="file.TXT"), None),
    
  521.     (FileExtensionValidator(["TXT"]), ContentFile("contents", name="file.txt"), None),
    
  522.     (FileExtensionValidator(), ContentFile("contents", name="file.jpg"), None),
    
  523.     (DecimalValidator(max_digits=2, decimal_places=2), Decimal("0.99"), None),
    
  524.     (
    
  525.         DecimalValidator(max_digits=2, decimal_places=1),
    
  526.         Decimal("0.99"),
    
  527.         ValidationError,
    
  528.     ),
    
  529.     (DecimalValidator(max_digits=3, decimal_places=1), Decimal("999"), ValidationError),
    
  530.     (DecimalValidator(max_digits=4, decimal_places=1), Decimal("999"), None),
    
  531.     (
    
  532.         DecimalValidator(max_digits=20, decimal_places=2),
    
  533.         Decimal("742403889818000000"),
    
  534.         None,
    
  535.     ),
    
  536.     (DecimalValidator(20, 2), Decimal("7.42403889818E+17"), None),
    
  537.     (
    
  538.         DecimalValidator(max_digits=20, decimal_places=2),
    
  539.         Decimal("7424742403889818000000"),
    
  540.         ValidationError,
    
  541.     ),
    
  542.     (DecimalValidator(max_digits=5, decimal_places=2), Decimal("7304E-1"), None),
    
  543.     (
    
  544.         DecimalValidator(max_digits=5, decimal_places=2),
    
  545.         Decimal("7304E-3"),
    
  546.         ValidationError,
    
  547.     ),
    
  548.     (DecimalValidator(max_digits=5, decimal_places=5), Decimal("70E-5"), None),
    
  549.     (
    
  550.         DecimalValidator(max_digits=5, decimal_places=5),
    
  551.         Decimal("70E-6"),
    
  552.         ValidationError,
    
  553.     ),
    
  554.     # 'Enter a number.' errors
    
  555.     *[
    
  556.         (
    
  557.             DecimalValidator(decimal_places=2, max_digits=10),
    
  558.             Decimal(value),
    
  559.             ValidationError,
    
  560.         )
    
  561.         for value in (
    
  562.             "NaN",
    
  563.             "-NaN",
    
  564.             "+NaN",
    
  565.             "sNaN",
    
  566.             "-sNaN",
    
  567.             "+sNaN",
    
  568.             "Inf",
    
  569.             "-Inf",
    
  570.             "+Inf",
    
  571.             "Infinity",
    
  572.             "-Infinity",
    
  573.             "+Infinity",
    
  574.         )
    
  575.     ],
    
  576.     (validate_image_file_extension, ContentFile("contents", name="file.jpg"), None),
    
  577.     (validate_image_file_extension, ContentFile("contents", name="file.png"), None),
    
  578.     (validate_image_file_extension, ContentFile("contents", name="file.PNG"), None),
    
  579.     (
    
  580.         validate_image_file_extension,
    
  581.         ContentFile("contents", name="file.txt"),
    
  582.         ValidationError,
    
  583.     ),
    
  584.     (
    
  585.         validate_image_file_extension,
    
  586.         ContentFile("contents", name="file"),
    
  587.         ValidationError,
    
  588.     ),
    
  589.     (ProhibitNullCharactersValidator(), "\x00something", ValidationError),
    
  590.     (ProhibitNullCharactersValidator(), "something", None),
    
  591.     (ProhibitNullCharactersValidator(), None, None),
    
  592. ]
    
  593. 
    
  594. # Add valid and invalid URL tests.
    
  595. # This only tests the validator without extended schemes.
    
  596. TEST_DATA.extend((URLValidator(), url, None) for url in VALID_URLS)
    
  597. TEST_DATA.extend((URLValidator(), url, ValidationError) for url in INVALID_URLS)
    
  598. 
    
  599. 
    
  600. class TestValidators(SimpleTestCase):
    
  601.     def test_validators(self):
    
  602.         for validator, value, expected in TEST_DATA:
    
  603.             name = (
    
  604.                 validator.__name__
    
  605.                 if isinstance(validator, types.FunctionType)
    
  606.                 else validator.__class__.__name__
    
  607.             )
    
  608.             exception_expected = expected is not None and issubclass(
    
  609.                 expected, Exception
    
  610.             )
    
  611.             with self.subTest(name, value=value):
    
  612.                 if (
    
  613.                     validator is validate_image_file_extension
    
  614.                     and not PILLOW_IS_INSTALLED
    
  615.                 ):
    
  616.                     self.skipTest(
    
  617.                         "Pillow is required to test validate_image_file_extension."
    
  618.                     )
    
  619.                 if exception_expected:
    
  620.                     with self.assertRaises(expected):
    
  621.                         validator(value)
    
  622.                 else:
    
  623.                     self.assertEqual(expected, validator(value))
    
  624. 
    
  625.     def test_single_message(self):
    
  626.         v = ValidationError("Not Valid")
    
  627.         self.assertEqual(str(v), "['Not Valid']")
    
  628.         self.assertEqual(repr(v), "ValidationError(['Not Valid'])")
    
  629. 
    
  630.     def test_message_list(self):
    
  631.         v = ValidationError(["First Problem", "Second Problem"])
    
  632.         self.assertEqual(str(v), "['First Problem', 'Second Problem']")
    
  633.         self.assertEqual(
    
  634.             repr(v), "ValidationError(['First Problem', 'Second Problem'])"
    
  635.         )
    
  636. 
    
  637.     def test_message_dict(self):
    
  638.         v = ValidationError({"first": ["First Problem"]})
    
  639.         self.assertEqual(str(v), "{'first': ['First Problem']}")
    
  640.         self.assertEqual(repr(v), "ValidationError({'first': ['First Problem']})")
    
  641. 
    
  642.     def test_regex_validator_flags(self):
    
  643.         msg = "If the flags are set, regex must be a regular expression string."
    
  644.         with self.assertRaisesMessage(TypeError, msg):
    
  645.             RegexValidator(re.compile("a"), flags=re.IGNORECASE)
    
  646. 
    
  647.     def test_max_length_validator_message(self):
    
  648.         v = MaxLengthValidator(
    
  649.             16, message='"%(value)s" has more than %(limit_value)d characters.'
    
  650.         )
    
  651.         with self.assertRaisesMessage(
    
  652.             ValidationError, '"djangoproject.com" has more than 16 characters.'
    
  653.         ):
    
  654.             v("djangoproject.com")
    
  655. 
    
  656. 
    
  657. class TestValidatorEquality(TestCase):
    
  658.     """
    
  659.     Validators have valid equality operators (#21638)
    
  660.     """
    
  661. 
    
  662.     def test_regex_equality(self):
    
  663.         self.assertEqual(
    
  664.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://"),
    
  665.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://"),
    
  666.         )
    
  667.         self.assertNotEqual(
    
  668.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://"),
    
  669.             RegexValidator(r"^(?:[0-9\.\-]*)://"),
    
  670.         )
    
  671.         self.assertEqual(
    
  672.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://", "oh noes", "invalid"),
    
  673.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://", "oh noes", "invalid"),
    
  674.         )
    
  675.         self.assertNotEqual(
    
  676.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://", "oh", "invalid"),
    
  677.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://", "oh noes", "invalid"),
    
  678.         )
    
  679.         self.assertNotEqual(
    
  680.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://", "oh noes", "invalid"),
    
  681.             RegexValidator(r"^(?:[a-z0-9\.\-]*)://"),
    
  682.         )
    
  683. 
    
  684.         self.assertNotEqual(
    
  685.             RegexValidator("", flags=re.IGNORECASE),
    
  686.             RegexValidator(""),
    
  687.         )
    
  688. 
    
  689.         self.assertNotEqual(
    
  690.             RegexValidator(""),
    
  691.             RegexValidator("", inverse_match=True),
    
  692.         )
    
  693. 
    
  694.     def test_regex_equality_nocache(self):
    
  695.         pattern = r"^(?:[a-z0-9\.\-]*)://"
    
  696.         left = RegexValidator(pattern)
    
  697.         re.purge()
    
  698.         right = RegexValidator(pattern)
    
  699. 
    
  700.         self.assertEqual(
    
  701.             left,
    
  702.             right,
    
  703.         )
    
  704. 
    
  705.     def test_regex_equality_blank(self):
    
  706.         self.assertEqual(
    
  707.             RegexValidator(),
    
  708.             RegexValidator(),
    
  709.         )
    
  710. 
    
  711.     def test_email_equality(self):
    
  712.         self.assertEqual(
    
  713.             EmailValidator(),
    
  714.             EmailValidator(),
    
  715.         )
    
  716.         self.assertNotEqual(
    
  717.             EmailValidator(message="BAD EMAIL"),
    
  718.             EmailValidator(),
    
  719.         )
    
  720.         self.assertEqual(
    
  721.             EmailValidator(message="BAD EMAIL", code="bad"),
    
  722.             EmailValidator(message="BAD EMAIL", code="bad"),
    
  723.         )
    
  724. 
    
  725.     def test_basic_equality(self):
    
  726.         self.assertEqual(
    
  727.             MaxValueValidator(44),
    
  728.             MaxValueValidator(44),
    
  729.         )
    
  730.         self.assertEqual(MaxValueValidator(44), mock.ANY)
    
  731.         self.assertEqual(
    
  732.             StepValueValidator(0.003),
    
  733.             StepValueValidator(0.003),
    
  734.         )
    
  735.         self.assertNotEqual(
    
  736.             MaxValueValidator(44),
    
  737.             MinValueValidator(44),
    
  738.         )
    
  739.         self.assertNotEqual(
    
  740.             MinValueValidator(45),
    
  741.             MinValueValidator(11),
    
  742.         )
    
  743.         self.assertNotEqual(
    
  744.             StepValueValidator(3),
    
  745.             StepValueValidator(2),
    
  746.         )
    
  747. 
    
  748.     def test_decimal_equality(self):
    
  749.         self.assertEqual(
    
  750.             DecimalValidator(1, 2),
    
  751.             DecimalValidator(1, 2),
    
  752.         )
    
  753.         self.assertNotEqual(
    
  754.             DecimalValidator(1, 2),
    
  755.             DecimalValidator(1, 1),
    
  756.         )
    
  757.         self.assertNotEqual(
    
  758.             DecimalValidator(1, 2),
    
  759.             DecimalValidator(2, 2),
    
  760.         )
    
  761.         self.assertNotEqual(
    
  762.             DecimalValidator(1, 2),
    
  763.             MinValueValidator(11),
    
  764.         )
    
  765. 
    
  766.     def test_file_extension_equality(self):
    
  767.         self.assertEqual(FileExtensionValidator(), FileExtensionValidator())
    
  768.         self.assertEqual(
    
  769.             FileExtensionValidator(["txt"]), FileExtensionValidator(["txt"])
    
  770.         )
    
  771.         self.assertEqual(
    
  772.             FileExtensionValidator(["TXT"]), FileExtensionValidator(["txt"])
    
  773.         )
    
  774.         self.assertEqual(
    
  775.             FileExtensionValidator(["TXT", "png"]),
    
  776.             FileExtensionValidator(["txt", "png"]),
    
  777.         )
    
  778.         self.assertEqual(
    
  779.             FileExtensionValidator(["txt"]),
    
  780.             FileExtensionValidator(["txt"], code="invalid_extension"),
    
  781.         )
    
  782.         self.assertNotEqual(
    
  783.             FileExtensionValidator(["txt"]), FileExtensionValidator(["png"])
    
  784.         )
    
  785.         self.assertNotEqual(
    
  786.             FileExtensionValidator(["txt"]), FileExtensionValidator(["png", "jpg"])
    
  787.         )
    
  788.         self.assertNotEqual(
    
  789.             FileExtensionValidator(["txt"]),
    
  790.             FileExtensionValidator(["txt"], code="custom_code"),
    
  791.         )
    
  792.         self.assertNotEqual(
    
  793.             FileExtensionValidator(["txt"]),
    
  794.             FileExtensionValidator(["txt"], message="custom error message"),
    
  795.         )
    
  796. 
    
  797.     def test_prohibit_null_characters_validator_equality(self):
    
  798.         self.assertEqual(
    
  799.             ProhibitNullCharactersValidator(message="message", code="code"),
    
  800.             ProhibitNullCharactersValidator(message="message", code="code"),
    
  801.         )
    
  802.         self.assertEqual(
    
  803.             ProhibitNullCharactersValidator(), ProhibitNullCharactersValidator()
    
  804.         )
    
  805.         self.assertNotEqual(
    
  806.             ProhibitNullCharactersValidator(message="message1", code="code"),
    
  807.             ProhibitNullCharactersValidator(message="message2", code="code"),
    
  808.         )
    
  809.         self.assertNotEqual(
    
  810.             ProhibitNullCharactersValidator(message="message", code="code1"),
    
  811.             ProhibitNullCharactersValidator(message="message", code="code2"),
    
  812.         )