1. from django.core.exceptions import ValidationError
    
  2. from django.forms import CharField, HiddenInput, PasswordInput, Textarea, TextInput
    
  3. from django.test import SimpleTestCase
    
  4. 
    
  5. from . import FormFieldAssertionsMixin
    
  6. 
    
  7. 
    
  8. class CharFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
    
  9.     def test_charfield_1(self):
    
  10.         f = CharField()
    
  11.         self.assertEqual("1", f.clean(1))
    
  12.         self.assertEqual("hello", f.clean("hello"))
    
  13.         with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
    
  14.             f.clean(None)
    
  15.         with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
    
  16.             f.clean("")
    
  17.         self.assertEqual("[1, 2, 3]", f.clean([1, 2, 3]))
    
  18.         self.assertIsNone(f.max_length)
    
  19.         self.assertIsNone(f.min_length)
    
  20. 
    
  21.     def test_charfield_2(self):
    
  22.         f = CharField(required=False)
    
  23.         self.assertEqual("1", f.clean(1))
    
  24.         self.assertEqual("hello", f.clean("hello"))
    
  25.         self.assertEqual("", f.clean(None))
    
  26.         self.assertEqual("", f.clean(""))
    
  27.         self.assertEqual("[1, 2, 3]", f.clean([1, 2, 3]))
    
  28.         self.assertIsNone(f.max_length)
    
  29.         self.assertIsNone(f.min_length)
    
  30. 
    
  31.     def test_charfield_3(self):
    
  32.         f = CharField(max_length=10, required=False)
    
  33.         self.assertEqual("12345", f.clean("12345"))
    
  34.         self.assertEqual("1234567890", f.clean("1234567890"))
    
  35.         msg = "'Ensure this value has at most 10 characters (it has 11).'"
    
  36.         with self.assertRaisesMessage(ValidationError, msg):
    
  37.             f.clean("1234567890a")
    
  38.         self.assertEqual(f.max_length, 10)
    
  39.         self.assertIsNone(f.min_length)
    
  40. 
    
  41.     def test_charfield_4(self):
    
  42.         f = CharField(min_length=10, required=False)
    
  43.         self.assertEqual("", f.clean(""))
    
  44.         msg = "'Ensure this value has at least 10 characters (it has 5).'"
    
  45.         with self.assertRaisesMessage(ValidationError, msg):
    
  46.             f.clean("12345")
    
  47.         self.assertEqual("1234567890", f.clean("1234567890"))
    
  48.         self.assertEqual("1234567890a", f.clean("1234567890a"))
    
  49.         self.assertIsNone(f.max_length)
    
  50.         self.assertEqual(f.min_length, 10)
    
  51. 
    
  52.     def test_charfield_5(self):
    
  53.         f = CharField(min_length=10, required=True)
    
  54.         with self.assertRaisesMessage(ValidationError, "'This field is required.'"):
    
  55.             f.clean("")
    
  56.         msg = "'Ensure this value has at least 10 characters (it has 5).'"
    
  57.         with self.assertRaisesMessage(ValidationError, msg):
    
  58.             f.clean("12345")
    
  59.         self.assertEqual("1234567890", f.clean("1234567890"))
    
  60.         self.assertEqual("1234567890a", f.clean("1234567890a"))
    
  61.         self.assertIsNone(f.max_length)
    
  62.         self.assertEqual(f.min_length, 10)
    
  63. 
    
  64.     def test_charfield_length_not_int(self):
    
  65.         """
    
  66.         Setting min_length or max_length to something that is not a number
    
  67.         raises an exception.
    
  68.         """
    
  69.         with self.assertRaises(ValueError):
    
  70.             CharField(min_length="a")
    
  71.         with self.assertRaises(ValueError):
    
  72.             CharField(max_length="a")
    
  73.         msg = "__init__() takes 1 positional argument but 2 were given"
    
  74.         with self.assertRaisesMessage(TypeError, msg):
    
  75.             CharField("a")
    
  76. 
    
  77.     def test_charfield_widget_attrs(self):
    
  78.         """
    
  79.         CharField.widget_attrs() always returns a dictionary and includes
    
  80.         minlength/maxlength if min_length/max_length are defined on the field
    
  81.         and the widget is not hidden.
    
  82.         """
    
  83.         # Return an empty dictionary if max_length and min_length are both None.
    
  84.         f = CharField()
    
  85.         self.assertEqual(f.widget_attrs(TextInput()), {})
    
  86.         self.assertEqual(f.widget_attrs(Textarea()), {})
    
  87. 
    
  88.         # Return a maxlength attribute equal to max_length.
    
  89.         f = CharField(max_length=10)
    
  90.         self.assertEqual(f.widget_attrs(TextInput()), {"maxlength": "10"})
    
  91.         self.assertEqual(f.widget_attrs(PasswordInput()), {"maxlength": "10"})
    
  92.         self.assertEqual(f.widget_attrs(Textarea()), {"maxlength": "10"})
    
  93. 
    
  94.         # Return a minlength attribute equal to min_length.
    
  95.         f = CharField(min_length=5)
    
  96.         self.assertEqual(f.widget_attrs(TextInput()), {"minlength": "5"})
    
  97.         self.assertEqual(f.widget_attrs(PasswordInput()), {"minlength": "5"})
    
  98.         self.assertEqual(f.widget_attrs(Textarea()), {"minlength": "5"})
    
  99. 
    
  100.         # Return both maxlength and minlength when both max_length and
    
  101.         # min_length are set.
    
  102.         f = CharField(max_length=10, min_length=5)
    
  103.         self.assertEqual(
    
  104.             f.widget_attrs(TextInput()), {"maxlength": "10", "minlength": "5"}
    
  105.         )
    
  106.         self.assertEqual(
    
  107.             f.widget_attrs(PasswordInput()), {"maxlength": "10", "minlength": "5"}
    
  108.         )
    
  109.         self.assertEqual(
    
  110.             f.widget_attrs(Textarea()), {"maxlength": "10", "minlength": "5"}
    
  111.         )
    
  112.         self.assertEqual(f.widget_attrs(HiddenInput()), {})
    
  113. 
    
  114.     def test_charfield_strip(self):
    
  115.         """
    
  116.         Values have whitespace stripped but not if strip=False.
    
  117.         """
    
  118.         f = CharField()
    
  119.         self.assertEqual(f.clean(" 1"), "1")
    
  120.         self.assertEqual(f.clean("1 "), "1")
    
  121. 
    
  122.         f = CharField(strip=False)
    
  123.         self.assertEqual(f.clean(" 1"), " 1")
    
  124.         self.assertEqual(f.clean("1 "), "1 ")
    
  125. 
    
  126.     def test_strip_before_checking_empty(self):
    
  127.         """
    
  128.         A whitespace-only value, ' ', is stripped to an empty string and then
    
  129.         converted to the empty value, None.
    
  130.         """
    
  131.         f = CharField(required=False, empty_value=None)
    
  132.         self.assertIsNone(f.clean(" "))
    
  133. 
    
  134.     def test_clean_non_string(self):
    
  135.         """CharField.clean() calls str(value) before stripping it."""
    
  136. 
    
  137.         class StringWrapper:
    
  138.             def __init__(self, v):
    
  139.                 self.v = v
    
  140. 
    
  141.             def __str__(self):
    
  142.                 return self.v
    
  143. 
    
  144.         value = StringWrapper(" ")
    
  145.         f1 = CharField(required=False, empty_value=None)
    
  146.         self.assertIsNone(f1.clean(value))
    
  147.         f2 = CharField(strip=False)
    
  148.         self.assertEqual(f2.clean(value), " ")
    
  149. 
    
  150.     def test_charfield_disabled(self):
    
  151.         f = CharField(disabled=True)
    
  152.         self.assertWidgetRendersTo(
    
  153.             f, '<input type="text" name="f" id="id_f" disabled required>'
    
  154.         )
    
  155. 
    
  156.     def test_null_characters_prohibited(self):
    
  157.         f = CharField()
    
  158.         msg = "Null characters are not allowed."
    
  159.         with self.assertRaisesMessage(ValidationError, msg):
    
  160.             f.clean("\x00something")