summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2013-02-12 11:22:41 +0100
committerCarl Meyer <carl@oddbird.net>2013-02-19 10:37:54 -0700
commit0cc350a896f70ace18280410eb616a9197d862b0 (patch)
treefd6c30263e36aa3a22058e9ffd82132d9bb760a7 /tests
parent0e7861aec73702f7933ce2a93056f7983939f0d6 (diff)
[1.4.x] Added a default limit to the maximum number of forms in a formset.
This is a security fix. Disclosure and advisory coming shortly.
Diffstat (limited to 'tests')
-rw-r--r--tests/regressiontests/forms/tests/formsets.py70
-rw-r--r--tests/regressiontests/generic_inline_admin/tests.py3
2 files changed, 66 insertions, 7 deletions
diff --git a/tests/regressiontests/forms/tests/formsets.py b/tests/regressiontests/forms/tests/formsets.py
index 05ef978c45..7c69e7e20a 100644
--- a/tests/regressiontests/forms/tests/formsets.py
+++ b/tests/regressiontests/forms/tests/formsets.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from django.forms import Form, CharField, IntegerField, ValidationError, DateField
+from django.forms import Form, CharField, IntegerField, ValidationError, DateField, formsets
from django.forms.formsets import formset_factory, BaseFormSet
from django.test import TestCase
@@ -47,7 +47,7 @@ class FormsFormsetTestCase(TestCase):
# for adding data. By default, it displays 1 blank form. It can display more,
# but we'll look at how to do so later.
formset = ChoiceFormSet(auto_id=False, prefix='choices')
- self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" />
+ self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="1000" />
<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr>
<tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>""")
@@ -650,8 +650,8 @@ class FormsFormsetTestCase(TestCase):
# Limiting the maximum number of forms ########################################
# Base case for max_num.
- # When not passed, max_num will take its default value of None, i.e. unlimited
- # number of forms, only controlled by the value of the extra parameter.
+ # When not passed, max_num will take a high default value, leaving the
+ # number of forms only controlled by the value of the extra parameter.
LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3)
formset = LimitedFavoriteDrinkFormSet()
@@ -698,8 +698,8 @@ class FormsFormsetTestCase(TestCase):
def test_max_num_with_initial_data(self):
# max_num with initial data
- # When not passed, max_num will take its default value of None, i.e. unlimited
- # number of forms, only controlled by the values of the initial and extra
+ # When not passed, max_num will take a high default value, leaving the
+ # number of forms only controlled by the value of the initial and extra
# parameters.
initial = [
@@ -844,6 +844,64 @@ class FormsFormsetTestCase(TestCase):
self.assertEqual(len(formset.forms), 0)
self.assertTrue(formset)
+ def test_hard_limit_on_instantiated_forms(self):
+ """A formset has a hard limit on the number of forms instantiated."""
+ # reduce the default limit of 1000 temporarily for testing
+ _old_DEFAULT_MAX_NUM = formsets.DEFAULT_MAX_NUM
+ try:
+ formsets.DEFAULT_MAX_NUM = 3
+ ChoiceFormSet = formset_factory(Choice)
+ # someone fiddles with the mgmt form data...
+ formset = ChoiceFormSet(
+ {
+ 'choices-TOTAL_FORMS': '4',
+ 'choices-INITIAL_FORMS': '0',
+ 'choices-MAX_NUM_FORMS': '4',
+ 'choices-0-choice': 'Zero',
+ 'choices-0-votes': '0',
+ 'choices-1-choice': 'One',
+ 'choices-1-votes': '1',
+ 'choices-2-choice': 'Two',
+ 'choices-2-votes': '2',
+ 'choices-3-choice': 'Three',
+ 'choices-3-votes': '3',
+ },
+ prefix='choices',
+ )
+ # But we still only instantiate 3 forms
+ self.assertEqual(len(formset.forms), 3)
+ finally:
+ formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM
+
+ def test_increase_hard_limit(self):
+ """Can increase the built-in forms limit via a higher max_num."""
+ # reduce the default limit of 1000 temporarily for testing
+ _old_DEFAULT_MAX_NUM = formsets.DEFAULT_MAX_NUM
+ try:
+ formsets.DEFAULT_MAX_NUM = 3
+ # for this form, we want a limit of 4
+ ChoiceFormSet = formset_factory(Choice, max_num=4)
+ formset = ChoiceFormSet(
+ {
+ 'choices-TOTAL_FORMS': '4',
+ 'choices-INITIAL_FORMS': '0',
+ 'choices-MAX_NUM_FORMS': '4',
+ 'choices-0-choice': 'Zero',
+ 'choices-0-votes': '0',
+ 'choices-1-choice': 'One',
+ 'choices-1-votes': '1',
+ 'choices-2-choice': 'Two',
+ 'choices-2-votes': '2',
+ 'choices-3-choice': 'Three',
+ 'choices-3-votes': '3',
+ },
+ prefix='choices',
+ )
+ # This time four forms are instantiated
+ self.assertEqual(len(formset.forms), 4)
+ finally:
+ formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM
+
data = {
'choices-TOTAL_FORMS': '1', # the number of forms rendered
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index db81eec47a..237e396dd2 100644
--- a/tests/regressiontests/generic_inline_admin/tests.py
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -7,6 +7,7 @@ from django.contrib import admin
from django.contrib.admin.sites import AdminSite
from django.contrib.contenttypes.generic import (
generic_inlineformset_factory, GenericTabularInline)
+from django.forms.formsets import DEFAULT_MAX_NUM
from django.forms.models import ModelForm
from django.test import TestCase
@@ -241,7 +242,7 @@ class GenericInlineModelAdminTest(TestCase):
# Create a formset with default arguments
formset = media_inline.get_formset(request)
- self.assertEqual(formset.max_num, None)
+ self.assertEqual(formset.max_num, DEFAULT_MAX_NUM)
self.assertEqual(formset.can_order, False)
# Create a formset with custom keyword arguments