summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2016-09-09 08:55:29 -0400
committerGitHub <noreply@github.com>2016-09-09 08:55:29 -0400
commitdab653cadcd22a442fa4082f24304a0567de6cd2 (patch)
tree838e1ebee0389875067526738a483fa65152d0ba
parentaca939b6e545debd64c6464976abac8fd716b589 (diff)
Organized forms_tests test_regressions.py.
-rw-r--r--tests/forms_tests/field_tests/test_choicefield.py16
-rw-r--r--tests/forms_tests/models.py4
-rw-r--r--tests/forms_tests/tests/test_error_messages.py44
-rw-r--r--tests/forms_tests/tests/test_forms.py27
-rw-r--r--tests/forms_tests/tests/test_i18n.py97
-rw-r--r--tests/forms_tests/tests/test_regressions.py222
-rw-r--r--tests/model_forms/tests.py16
7 files changed, 198 insertions, 228 deletions
diff --git a/tests/forms_tests/field_tests/test_choicefield.py b/tests/forms_tests/field_tests/test_choicefield.py
index 69b4d9e342..4c70177dac 100644
--- a/tests/forms_tests/field_tests/test_choicefield.py
+++ b/tests/forms_tests/field_tests/test_choicefield.py
@@ -1,7 +1,8 @@
+# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.forms import ChoiceField, Form, ValidationError
-from django.test import SimpleTestCase
+from django.test import SimpleTestCase, ignore_warnings
from . import FormFieldAssertionsMixin
@@ -84,3 +85,16 @@ class ChoiceFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
'<select id="id_f" name="f" disabled required><option value="J">John</option>'
'<option value="P">Paul</option></select>'
)
+
+ @ignore_warnings(category=UnicodeWarning)
+ def test_utf8_bytesrings(self):
+ # Choice validation with UTF-8 bytestrings as input (these are the
+ # Russian abbreviations "мес." and "шт.".
+ f = ChoiceField(
+ choices=(
+ (b'\xd0\xbc\xd0\xb5\xd1\x81.', b'\xd0\xbc\xd0\xb5\xd1\x81.'),
+ (b'\xd1\x88\xd1\x82.', b'\xd1\x88\xd1\x82.'),
+ ),
+ )
+ self.assertEqual(f.clean('\u0448\u0442.'), '\u0448\u0442.')
+ self.assertEqual(f.clean(b'\xd1\x88\xd1\x82.'), '\u0448\u0442.')
diff --git a/tests/forms_tests/models.py b/tests/forms_tests/models.py
index 511a3d0d44..cf770abb02 100644
--- a/tests/forms_tests/models.py
+++ b/tests/forms_tests/models.py
@@ -143,9 +143,5 @@ class Group(models.Model):
return '%s' % self.name
-class Cheese(models.Model):
- name = models.CharField(max_length=100)
-
-
class Article(models.Model):
content = models.TextField()
diff --git a/tests/forms_tests/tests/test_error_messages.py b/tests/forms_tests/tests/test_error_messages.py
index 315e72604d..4ae550efc2 100644
--- a/tests/forms_tests/tests/test_error_messages.py
+++ b/tests/forms_tests/tests/test_error_messages.py
@@ -9,10 +9,13 @@ from django.forms import (
ModelMultipleChoiceField, MultipleChoiceField, RegexField,
SplitDateTimeField, TimeField, URLField, ValidationError, utils,
)
+from django.template import Context, Template
from django.test import SimpleTestCase, TestCase
from django.utils.encoding import python_2_unicode_compatible
from django.utils.safestring import mark_safe
+from ..models import ChoiceModel
+
class AssertFormErrorsMixin(object):
def assertFormErrors(self, expected, the_callable, *args, **kwargs):
@@ -242,11 +245,50 @@ class FormsErrorMessagesTestCase(SimpleTestCase, AssertFormErrorsMixin):
self.assertHTMLEqual(str(form2['last_name'].errors), '<div class="error"><p>This field is required.</p></div>')
self.assertHTMLEqual(str(form2.errors['__all__']), '<div class="error"><p>I like to be awkward.</p></div>')
+ def test_error_messages_escaping(self):
+ # The forms layer doesn't escape input values directly because error
+ # messages might be presented in non-HTML contexts. Instead, the
+ # message is marked for escaping by the template engine, so a template
+ # is needed to trigger the escaping.
+ t = Template('{{ form.errors }}')
+
+ class SomeForm(Form):
+ field = ChoiceField(choices=[('one', 'One')])
+
+ f = SomeForm({'field': '<script>'})
+ self.assertHTMLEqual(
+ t.render(Context({'form': f})),
+ '<ul class="errorlist"><li>field<ul class="errorlist">'
+ '<li>Select a valid choice. &lt;script&gt; is not one of the '
+ 'available choices.</li></ul></li></ul>'
+ )
+
+ class SomeForm(Form):
+ field = MultipleChoiceField(choices=[('one', 'One')])
+
+ f = SomeForm({'field': ['<script>']})
+ self.assertHTMLEqual(
+ t.render(Context({'form': f})),
+ '<ul class="errorlist"><li>field<ul class="errorlist">'
+ '<li>Select a valid choice. &lt;script&gt; is not one of the '
+ 'available choices.</li></ul></li></ul>'
+ )
+
+ class SomeForm(Form):
+ field = ModelMultipleChoiceField(ChoiceModel.objects.all())
+
+ f = SomeForm({'field': ['<script>']})
+ self.assertHTMLEqual(
+ t.render(Context({'form': f})),
+ '<ul class="errorlist"><li>field<ul class="errorlist">'
+ '<li>&quot;&lt;script&gt;&quot; is not a valid value for a '
+ 'primary key.</li></ul></li></ul>'
+ )
+
class ModelChoiceFieldErrorMessagesTestCase(TestCase, AssertFormErrorsMixin):
def test_modelchoicefield(self):
# Create choices for the model choice field tests below.
- from forms_tests.models import ChoiceModel
ChoiceModel.objects.create(pk=1, name='a')
ChoiceModel.objects.create(pk=2, name='b')
ChoiceModel.objects.create(pk=3, name='c')
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 183caa354c..f86ab2d43c 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -3549,3 +3549,30 @@ Good luck picking a username that doesn&#39;t already exist.</p>
'<option value="J">Java</option>'
'</select></td></tr>',
)
+
+ def test_only_hidden_fields(self):
+ # A form with *only* hidden fields that has errors is going to be very unusual.
+ class HiddenForm(Form):
+ data = IntegerField(widget=HiddenInput)
+
+ f = HiddenForm({})
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<ul class="errorlist nonfield">'
+ '<li>(Hidden field data) This field is required.</li></ul>\n<p> '
+ '<input type="hidden" name="data" id="id_data" /></p>'
+ )
+ self.assertHTMLEqual(
+ f.as_table(),
+ '<tr><td colspan="2"><ul class="errorlist nonfield">'
+ '<li>(Hidden field data) This field is required.</li></ul>'
+ '<input type="hidden" name="data" id="id_data" /></td></tr>'
+ )
+
+ def test_field_named_data(self):
+ class DataForm(Form):
+ data = CharField(max_length=10)
+
+ f = DataForm({'data': 'xyzzy'})
+ self.assertTrue(f.is_valid())
+ self.assertEqual(f.cleaned_data, {'data': 'xyzzy'})
diff --git a/tests/forms_tests/tests/test_i18n.py b/tests/forms_tests/tests/test_i18n.py
new file mode 100644
index 0000000000..56225e0dd5
--- /dev/null
+++ b/tests/forms_tests/tests/test_i18n.py
@@ -0,0 +1,97 @@
+from __future__ import unicode_literals
+
+from django.forms import (
+ CharField, ChoiceField, Form, IntegerField, RadioSelect, Select, TextInput,
+)
+from django.test import SimpleTestCase
+from django.utils import translation
+from django.utils.translation import gettext_lazy, ugettext_lazy
+
+
+class FormsI18nTests(SimpleTestCase):
+ def test_lazy_labels(self):
+ class SomeForm(Form):
+ username = CharField(max_length=10, label=ugettext_lazy('username'))
+
+ f = SomeForm()
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<p><label for="id_username">username:</label>'
+ '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
+ )
+
+ # Translations are done at rendering time, so multi-lingual apps can define forms)
+ with translation.override('de'):
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<p><label for="id_username">Benutzername:</label>'
+ '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
+ )
+ with translation.override('pl'):
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<p><label for="id_username">u\u017cytkownik:</label>'
+ '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
+ )
+
+ def test_non_ascii_label(self):
+ class SomeForm(Form):
+ field_1 = CharField(max_length=10, label=ugettext_lazy('field_1'))
+ field_2 = CharField(
+ max_length=10,
+ label=ugettext_lazy('field_2'),
+ widget=TextInput(attrs={'id': 'field_2_id'}),
+ )
+
+ f = SomeForm()
+ self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>')
+ self.assertHTMLEqual(f['field_2'].label_tag(), '<label for="field_2_id">field_2:</label>')
+
+ def test_non_ascii_choices(self):
+ class SomeForm(Form):
+ somechoice = ChoiceField(
+ choices=(('\xc5', 'En tied\xe4'), ('\xf8', 'Mies'), ('\xdf', 'Nainen')),
+ widget=RadioSelect(),
+ label='\xc5\xf8\xdf',
+ )
+
+ f = SomeForm()
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
+ '<ul id="id_somechoice">\n'
+ '<li><label for="id_somechoice_0">'
+ '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> '
+ 'En tied\xe4</label></li>\n'
+ '<li><label for="id_somechoice_1">'
+ '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required /> '
+ 'Mies</label></li>\n<li><label for="id_somechoice_2">'
+ '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required /> '
+ 'Nainen</label></li>\n</ul></p>'
+ )
+
+ # Translated error messages
+ with translation.override('ru'):
+ f = SomeForm({})
+ self.assertHTMLEqual(
+ f.as_p(),
+ '<ul class="errorlist"><li>'
+ '\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c'
+ '\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n'
+ '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
+ ' <ul id="id_somechoice">\n<li><label for="id_somechoice_0">'
+ '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> '
+ 'En tied\xe4</label></li>\n'
+ '<li><label for="id_somechoice_1">'
+ '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required /> '
+ 'Mies</label></li>\n<li><label for="id_somechoice_2">'
+ '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required /> '
+ 'Nainen</label></li>\n</ul></p>'
+ )
+
+ def test_select_translated_text(self):
+ # Deep copying translated text shouldn't raise an error.
+ class CopyForm(Form):
+ degree = IntegerField(widget=Select(choices=((1, gettext_lazy('test')),)))
+
+ CopyForm()
diff --git a/tests/forms_tests/tests/test_regressions.py b/tests/forms_tests/tests/test_regressions.py
deleted file mode 100644
index e183694234..0000000000
--- a/tests/forms_tests/tests/test_regressions.py
+++ /dev/null
@@ -1,222 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.forms import (
- CharField, ChoiceField, Form, HiddenInput, IntegerField, ModelForm,
- ModelMultipleChoiceField, MultipleChoiceField, RadioSelect, Select,
- TextInput,
-)
-from django.test import TestCase, ignore_warnings
-from django.utils import translation
-from django.utils.translation import gettext_lazy, ugettext_lazy
-
-from ..models import Cheese
-
-
-class FormsRegressionsTestCase(TestCase):
- def test_class(self):
- # Tests to prevent against recurrences of earlier bugs.
- extra_attrs = {'class': 'special'}
-
- class TestForm(Form):
- f1 = CharField(max_length=10, widget=TextInput(attrs=extra_attrs))
- f2 = CharField(widget=TextInput(attrs=extra_attrs))
-
- self.assertHTMLEqual(
- TestForm(auto_id=False).as_p(),
- '<p>F1: <input type="text" class="special" name="f1" maxlength="10" required /></p>\n'
- '<p>F2: <input type="text" class="special" name="f2" required /></p>'
- )
-
- def test_regression_3600(self):
- # Tests for form i18n #
- # There were some problems with form translations in #3600
-
- class SomeForm(Form):
- username = CharField(max_length=10, label=ugettext_lazy('username'))
-
- f = SomeForm()
- self.assertHTMLEqual(
- f.as_p(),
- '<p><label for="id_username">username:</label>'
- '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
- )
-
- # Translations are done at rendering time, so multi-lingual apps can define forms)
- with translation.override('de'):
- self.assertHTMLEqual(
- f.as_p(),
- '<p><label for="id_username">Benutzername:</label>'
- '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
- )
- with translation.override('pl'):
- self.assertHTMLEqual(
- f.as_p(),
- '<p><label for="id_username">u\u017cytkownik:</label>'
- '<input id="id_username" type="text" name="username" maxlength="10" required /></p>'
- )
-
- def test_regression_5216(self):
- # There was some problems with form translations in #5216
- class SomeForm(Form):
- field_1 = CharField(max_length=10, label=ugettext_lazy('field_1'))
- field_2 = CharField(
- max_length=10,
- label=ugettext_lazy('field_2'),
- widget=TextInput(attrs={'id': 'field_2_id'}),
- )
-
- f = SomeForm()
- self.assertHTMLEqual(f['field_1'].label_tag(), '<label for="id_field_1">field_1:</label>')
- self.assertHTMLEqual(f['field_2'].label_tag(), '<label for="field_2_id">field_2:</label>')
-
- # Unicode decoding problems...
- GENDERS = (('\xc5', 'En tied\xe4'), ('\xf8', 'Mies'), ('\xdf', 'Nainen'))
-
- class SomeForm(Form):
- somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf')
-
- f = SomeForm()
- self.assertHTMLEqual(
- f.as_p(),
- '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
- '<ul id="id_somechoice">\n'
- '<li><label for="id_somechoice_0">'
- '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> '
- 'En tied\xe4</label></li>\n'
- '<li><label for="id_somechoice_1">'
- '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required /> '
- 'Mies</label></li>\n<li><label for="id_somechoice_2">'
- '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required /> '
- 'Nainen</label></li>\n</ul></p>'
- )
-
- # Translated error messages used to be buggy.
- with translation.override('ru'):
- f = SomeForm({})
- self.assertHTMLEqual(
- f.as_p(),
- '<ul class="errorlist"><li>'
- '\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c'
- '\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n'
- '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label>'
- ' <ul id="id_somechoice">\n<li><label for="id_somechoice_0">'
- '<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required /> '
- 'En tied\xe4</label></li>\n'
- '<li><label for="id_somechoice_1">'
- '<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required /> '
- 'Mies</label></li>\n<li><label for="id_somechoice_2">'
- '<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required /> '
- 'Nainen</label></li>\n</ul></p>'
- )
-
- # Deep copying translated text shouldn't raise an error)
- class CopyForm(Form):
- degree = IntegerField(widget=Select(choices=((1, gettext_lazy('test')),)))
-
- f = CopyForm()
-
- @ignore_warnings(category=UnicodeWarning)
- def test_regression_5216_b(self):
- # Testing choice validation with UTF-8 bytestrings as input (these are the
- # Russian abbreviations "мес." and "шт.".
- UNITS = ((b'\xd0\xbc\xd0\xb5\xd1\x81.', b'\xd0\xbc\xd0\xb5\xd1\x81.'),
- (b'\xd1\x88\xd1\x82.', b'\xd1\x88\xd1\x82.'))
- f = ChoiceField(choices=UNITS)
- self.assertEqual(f.clean('\u0448\u0442.'), '\u0448\u0442.')
- self.assertEqual(f.clean(b'\xd1\x88\xd1\x82.'), '\u0448\u0442.')
-
- def test_misc(self):
- # There once was a problem with Form fields called "data". Let's make sure that
- # doesn't come back.
- class DataForm(Form):
- data = CharField(max_length=10)
-
- f = DataForm({'data': 'xyzzy'})
- self.assertTrue(f.is_valid())
- self.assertEqual(f.cleaned_data, {'data': 'xyzzy'})
-
- # A form with *only* hidden fields that has errors is going to be very unusual.
- class HiddenForm(Form):
- data = IntegerField(widget=HiddenInput)
-
- f = HiddenForm({})
- self.assertHTMLEqual(
- f.as_p(),
- '<ul class="errorlist nonfield">'
- '<li>(Hidden field data) This field is required.</li></ul>\n<p> '
- '<input type="hidden" name="data" id="id_data" /></p>'
- )
- self.assertHTMLEqual(
- f.as_table(),
- '<tr><td colspan="2"><ul class="errorlist nonfield">'
- '<li>(Hidden field data) This field is required.</li></ul>'
- '<input type="hidden" name="data" id="id_data" /></td></tr>'
- )
-
- def test_xss_error_messages(self):
- ###################################################
- # Tests for XSS vulnerabilities in error messages #
- ###################################################
-
- # The forms layer doesn't escape input values directly because error messages
- # might be presented in non-HTML contexts. Instead, the message is just marked
- # for escaping by the template engine. So we'll need to construct a little
- # silly template to trigger the escaping.
- from django.template import Template, Context
- t = Template('{{ form.errors }}')
-
- class SomeForm(Form):
- field = ChoiceField(choices=[('one', 'One')])
-
- f = SomeForm({'field': '<script>'})
- self.assertHTMLEqual(
- t.render(Context({'form': f})),
- '<ul class="errorlist"><li>field<ul class="errorlist">'
- '<li>Select a valid choice. &lt;script&gt; is not one of the '
- 'available choices.</li></ul></li></ul>'
- )
-
- class SomeForm(Form):
- field = MultipleChoiceField(choices=[('one', 'One')])
-
- f = SomeForm({'field': ['<script>']})
- self.assertHTMLEqual(
- t.render(Context({'form': f})),
- '<ul class="errorlist"><li>field<ul class="errorlist">'
- '<li>Select a valid choice. &lt;script&gt; is not one of the '
- 'available choices.</li></ul></li></ul>'
- )
-
- from forms_tests.models import ChoiceModel
-
- class SomeForm(Form):
- field = ModelMultipleChoiceField(ChoiceModel.objects.all())
-
- f = SomeForm({'field': ['<script>']})
- self.assertHTMLEqual(
- t.render(Context({'form': f})),
- '<ul class="errorlist"><li>field<ul class="errorlist">'
- '<li>&quot;&lt;script&gt;&quot; is not a valid value for a '
- 'primary key.</li></ul></li></ul>'
- )
-
- def test_regression_14234(self):
- """
- Re-cleaning an instance that was added via a ModelForm should not raise
- a pk uniqueness error.
- """
- class CheeseForm(ModelForm):
- class Meta:
- model = Cheese
- fields = '__all__'
-
- form = CheeseForm({
- 'name': 'Brie',
- })
-
- self.assertTrue(form.is_valid())
-
- obj = form.save()
- obj.name = 'Camembert'
- obj.full_clean()
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index 3974bec1e9..e4a73b0c46 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -1453,6 +1453,22 @@ class ModelFormBasicTests(TestCase):
<option value="3">Live</option>
</select></li>''' % (self.w_woodward.pk, w_bernstein.pk, self.w_royko.pk, self.c1.pk, self.c2.pk, self.c3.pk, c4.pk))
+ def test_recleaning_model_form_instance(self):
+ """
+ Re-cleaning an instance that was added via a ModelForm shouldn't raise
+ a pk uniqueness error.
+ """
+ class AuthorForm(forms.ModelForm):
+ class Meta:
+ model = Author
+ fields = '__all__'
+
+ form = AuthorForm({'full_name': 'Bob'})
+ self.assertTrue(form.is_valid())
+ obj = form.save()
+ obj.name = 'Alice'
+ obj.full_clean()
+
class ModelChoiceFieldTests(TestCase):
def setUp(self):