1. from django.core.exceptions import ValidationError
    
  2. from django.forms import URLField
    
  3. from django.test import SimpleTestCase
    
  4. 
    
  5. from . import FormFieldAssertionsMixin
    
  6. 
    
  7. 
    
  8. class URLFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
    
  9.     def test_urlfield_widget(self):
    
  10.         f = URLField()
    
  11.         self.assertWidgetRendersTo(f, '<input type="url" name="f" id="id_f" required>')
    
  12. 
    
  13.     def test_urlfield_widget_max_min_length(self):
    
  14.         f = URLField(min_length=15, max_length=20)
    
  15.         self.assertEqual("http://example.com", f.clean("http://example.com"))
    
  16.         self.assertWidgetRendersTo(
    
  17.             f,
    
  18.             '<input id="id_f" type="url" name="f" maxlength="20" '
    
  19.             'minlength="15" required>',
    
  20.         )
    
  21.         msg = "'Ensure this value has at least 15 characters (it has 12).'"
    
  22.         with self.assertRaisesMessage(ValidationError, msg):
    
  23.             f.clean("http://f.com")
    
  24.         msg = "'Ensure this value has at most 20 characters (it has 37).'"
    
  25.         with self.assertRaisesMessage(ValidationError, msg):
    
  26.             f.clean("http://abcdefghijklmnopqrstuvwxyz.com")
    
  27. 
    
  28.     def test_urlfield_clean(self):
    
  29.         f = URLField(required=False)
    
  30.         tests = [
    
  31.             ("http://localhost", "http://localhost"),
    
  32.             ("http://example.com", "http://example.com"),
    
  33.             ("http://example.com/test", "http://example.com/test"),
    
  34.             ("http://example.com.", "http://example.com."),
    
  35.             ("http://www.example.com", "http://www.example.com"),
    
  36.             ("http://www.example.com:8000/test", "http://www.example.com:8000/test"),
    
  37.             (
    
  38.                 "http://example.com?some_param=some_value",
    
  39.                 "http://example.com?some_param=some_value",
    
  40.             ),
    
  41.             ("valid-with-hyphens.com", "http://valid-with-hyphens.com"),
    
  42.             ("subdomain.domain.com", "http://subdomain.domain.com"),
    
  43.             ("http://200.8.9.10", "http://200.8.9.10"),
    
  44.             ("http://200.8.9.10:8000/test", "http://200.8.9.10:8000/test"),
    
  45.             ("http://valid-----hyphens.com", "http://valid-----hyphens.com"),
    
  46.             (
    
  47.                 "http://some.idn.xyzäöüßabc.domain.com:123/blah",
    
  48.                 "http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah",
    
  49.             ),
    
  50.             (
    
  51.                 "www.example.com/s/http://code.djangoproject.com/ticket/13804",
    
  52.                 "http://www.example.com/s/http://code.djangoproject.com/ticket/13804",
    
  53.             ),
    
  54.             # Normalization.
    
  55.             ("http://example.com/     ", "http://example.com/"),
    
  56.             # Valid IDN.
    
  57.             ("http://עברית.idn.icann.org/", "http://עברית.idn.icann.org/"),
    
  58.             ("http://sãopaulo.com/", "http://sãopaulo.com/"),
    
  59.             ("http://sãopaulo.com.br/", "http://sãopaulo.com.br/"),
    
  60.             ("http://пример.испытание/", "http://пример.испытание/"),
    
  61.             ("http://مثال.إختبار/", "http://مثال.إختبار/"),
    
  62.             ("http://例子.测试/", "http://例子.测试/"),
    
  63.             ("http://例子.測試/", "http://例子.測試/"),
    
  64.             (
    
  65.                 "http://उदाहरण.परीक्षा/",
    
  66.                 "http://उदाहरण.परीक्षा/",
    
  67.             ),
    
  68.             ("http://例え.テスト/", "http://例え.テスト/"),
    
  69.             ("http://مثال.آزمایشی/", "http://مثال.آزمایشی/"),
    
  70.             ("http://실례.테스트/", "http://실례.테스트/"),
    
  71.             ("http://العربية.idn.icann.org/", "http://العربية.idn.icann.org/"),
    
  72.             # IPv6.
    
  73.             ("http://[12:34::3a53]/", "http://[12:34::3a53]/"),
    
  74.             ("http://[a34:9238::]:8080/", "http://[a34:9238::]:8080/"),
    
  75.         ]
    
  76.         for url, expected in tests:
    
  77.             with self.subTest(url=url):
    
  78.                 self.assertEqual(f.clean(url), expected)
    
  79. 
    
  80.     def test_urlfield_clean_invalid(self):
    
  81.         f = URLField()
    
  82.         tests = [
    
  83.             "foo",
    
  84.             "com.",
    
  85.             ".",
    
  86.             "http://",
    
  87.             "http://example",
    
  88.             "http://example.",
    
  89.             "http://.com",
    
  90.             "http://invalid-.com",
    
  91.             "http://-invalid.com",
    
  92.             "http://inv-.alid-.com",
    
  93.             "http://inv-.-alid.com",
    
  94.             "[a",
    
  95.             "http://[a",
    
  96.             # Non-string.
    
  97.             23,
    
  98.             # Hangs "forever" before fixing a catastrophic backtracking,
    
  99.             # see #11198.
    
  100.             "http://%s" % ("X" * 60,),
    
  101.             # A second example, to make sure the problem is really addressed,
    
  102.             # even on domains that don't fail the domain label length check in
    
  103.             # the regex.
    
  104.             "http://%s" % ("X" * 200,),
    
  105.             # urlsplit() raises ValueError.
    
  106.             "////]@N.AN",
    
  107.             # Empty hostname.
    
  108.             "#@A.bO",
    
  109.         ]
    
  110.         msg = "'Enter a valid URL.'"
    
  111.         for value in tests:
    
  112.             with self.subTest(value=value):
    
  113.                 with self.assertRaisesMessage(ValidationError, msg):
    
  114.                     f.clean(value)
    
  115. 
    
  116.     def test_urlfield_clean_required(self):
    
  117.         f = URLField()
    
  118.         msg = "'This field is required.'"
    
  119.         with self.assertRaisesMessage(ValidationError, msg):
    
  120.             f.clean(None)
    
  121.         with self.assertRaisesMessage(ValidationError, msg):
    
  122.             f.clean("")
    
  123. 
    
  124.     def test_urlfield_clean_not_required(self):
    
  125.         f = URLField(required=False)
    
  126.         self.assertEqual(f.clean(None), "")
    
  127.         self.assertEqual(f.clean(""), "")
    
  128. 
    
  129.     def test_urlfield_strip_on_none_value(self):
    
  130.         f = URLField(required=False, empty_value=None)
    
  131.         self.assertIsNone(f.clean(""))
    
  132.         self.assertIsNone(f.clean(None))
    
  133. 
    
  134.     def test_urlfield_unable_to_set_strip_kwarg(self):
    
  135.         msg = "__init__() got multiple values for keyword argument 'strip'"
    
  136.         with self.assertRaisesMessage(TypeError, msg):
    
  137.             URLField(strip=False)