| import os |
| |
| from django import forms, http |
| from django.conf import settings |
| from django.contrib.formtools import preview, wizard, utils |
| from django.test import TestCase |
| from django.utils import unittest |
| |
| |
| success_string = "Done was called!" |
| |
| class TestFormPreview(preview.FormPreview): |
| def get_context(self, request, form): |
| context = super(TestFormPreview, self).get_context(request, form) |
| context.update({'custom_context': True}) |
| return context |
| |
| def get_initial(self, request): |
| return {'field1': 'Works!'} |
| |
| def done(self, request, cleaned_data): |
| return http.HttpResponse(success_string) |
| |
| |
| class TestForm(forms.Form): |
| field1 = forms.CharField() |
| field1_ = forms.CharField() |
| bool1 = forms.BooleanField(required=False) |
| |
| |
| class UserSecuredFormPreview(TestFormPreview): |
| """ |
| FormPreview with a custum security_hash method |
| """ |
| def security_hash(self, request, form): |
| return "123" |
| |
| |
| class PreviewTests(TestCase): |
| urls = 'django.contrib.formtools.tests.urls' |
| |
| def setUp(self): |
| # Create a FormPreview instance to share between tests |
| self.preview = preview.FormPreview(TestForm) |
| input_template = '<input type="hidden" name="%s" value="%s" />' |
| self.input = input_template % (self.preview.unused_name('stage'), "%d") |
| self.test_data = {'field1':u'foo', 'field1_':u'asdf'} |
| |
| def test_unused_name(self): |
| """ |
| Verifies name mangling to get uniue field name. |
| """ |
| self.assertEqual(self.preview.unused_name('field1'), 'field1__') |
| |
| def test_form_get(self): |
| """ |
| Test contrib.formtools.preview form retrieval. |
| |
| Use the client library to see if we can sucessfully retrieve |
| the form (mostly testing the setup ROOT_URLCONF |
| process). Verify that an additional hidden input field |
| is created to manage the stage. |
| |
| """ |
| response = self.client.get('/test1/') |
| stage = self.input % 1 |
| self.assertContains(response, stage, 1) |
| self.assertEquals(response.context['custom_context'], True) |
| self.assertEquals(response.context['form'].initial, {'field1': 'Works!'}) |
| |
| def test_form_preview(self): |
| """ |
| Test contrib.formtools.preview form preview rendering. |
| |
| Use the client library to POST to the form to see if a preview |
| is returned. If we do get a form back check that the hidden |
| value is correctly managing the state of the form. |
| |
| """ |
| # Pass strings for form submittal and add stage variable to |
| # show we previously saw first stage of the form. |
| self.test_data.update({'stage': 1}) |
| response = self.client.post('/test1/', self.test_data) |
| # Check to confirm stage is set to 2 in output form. |
| stage = self.input % 2 |
| self.assertContains(response, stage, 1) |
| |
| def test_form_submit(self): |
| """ |
| Test contrib.formtools.preview form submittal. |
| |
| Use the client library to POST to the form with stage set to 3 |
| to see if our forms done() method is called. Check first |
| without the security hash, verify failure, retry with security |
| hash and verify sucess. |
| |
| """ |
| # Pass strings for form submittal and add stage variable to |
| # show we previously saw first stage of the form. |
| self.test_data.update({'stage':2}) |
| response = self.client.post('/test1/', self.test_data) |
| self.assertNotEqual(response.content, success_string) |
| hash = self.preview.security_hash(None, TestForm(self.test_data)) |
| self.test_data.update({'hash': hash}) |
| response = self.client.post('/test1/', self.test_data) |
| self.assertEqual(response.content, success_string) |
| |
| def test_bool_submit(self): |
| """ |
| Test contrib.formtools.preview form submittal when form contains: |
| BooleanField(required=False) |
| |
| Ticket: #6209 - When an unchecked BooleanField is previewed, the preview |
| form's hash would be computed with no value for ``bool1``. However, when |
| the preview form is rendered, the unchecked hidden BooleanField would be |
| rendered with the string value 'False'. So when the preview form is |
| resubmitted, the hash would be computed with the value 'False' for |
| ``bool1``. We need to make sure the hashes are the same in both cases. |
| |
| """ |
| self.test_data.update({'stage':2}) |
| hash = self.preview.security_hash(None, TestForm(self.test_data)) |
| self.test_data.update({'hash':hash, 'bool1':u'False'}) |
| response = self.client.post('/test1/', self.test_data) |
| self.assertEqual(response.content, success_string) |
| |
| def test_form_submit_django12_hash(self): |
| """ |
| Test contrib.formtools.preview form submittal, using the hash function |
| used in Django 1.2 |
| """ |
| # Pass strings for form submittal and add stage variable to |
| # show we previously saw first stage of the form. |
| self.test_data.update({'stage':2}) |
| response = self.client.post('/test1/', self.test_data) |
| self.assertNotEqual(response.content, success_string) |
| hash = utils.security_hash(None, TestForm(self.test_data)) |
| self.test_data.update({'hash': hash}) |
| response = self.client.post('/test1/', self.test_data) |
| self.assertEqual(response.content, success_string) |
| |
| |
| def test_form_submit_django12_hash_custom_hash(self): |
| """ |
| Test contrib.formtools.preview form submittal, using the hash function |
| used in Django 1.2 and a custom security_hash method. |
| """ |
| # Pass strings for form submittal and add stage variable to |
| # show we previously saw first stage of the form. |
| self.test_data.update({'stage':2}) |
| response = self.client.post('/test2/', self.test_data) |
| self.assertEqual(response.status_code, 200) |
| self.assertNotEqual(response.content, success_string) |
| hash = utils.security_hash(None, TestForm(self.test_data)) |
| self.test_data.update({'hash': hash}) |
| response = self.client.post('/test2/', self.test_data) |
| self.assertNotEqual(response.content, success_string) |
| |
| |
| class SecurityHashTests(unittest.TestCase): |
| |
| def test_textfield_hash(self): |
| """ |
| Regression test for #10034: the hash generation function should ignore |
| leading/trailing whitespace so as to be friendly to broken browsers that |
| submit it (usually in textareas). |
| """ |
| f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'}) |
| f2 = HashTestForm({'name': ' joe', 'bio': 'Nothing notable. '}) |
| hash1 = utils.security_hash(None, f1) |
| hash2 = utils.security_hash(None, f2) |
| self.assertEqual(hash1, hash2) |
| |
| def test_empty_permitted(self): |
| """ |
| Regression test for #10643: the security hash should allow forms with |
| empty_permitted = True, or forms where data has not changed. |
| """ |
| f1 = HashTestBlankForm({}) |
| f2 = HashTestForm({}, empty_permitted=True) |
| hash1 = utils.security_hash(None, f1) |
| hash2 = utils.security_hash(None, f2) |
| self.assertEqual(hash1, hash2) |
| |
| |
| class FormHmacTests(unittest.TestCase): |
| """ |
| Same as SecurityHashTests, but with form_hmac |
| """ |
| |
| def test_textfield_hash(self): |
| """ |
| Regression test for #10034: the hash generation function should ignore |
| leading/trailing whitespace so as to be friendly to broken browsers that |
| submit it (usually in textareas). |
| """ |
| f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'}) |
| f2 = HashTestForm({'name': ' joe', 'bio': 'Nothing notable. '}) |
| hash1 = utils.form_hmac(f1) |
| hash2 = utils.form_hmac(f2) |
| self.assertEqual(hash1, hash2) |
| |
| def test_empty_permitted(self): |
| """ |
| Regression test for #10643: the security hash should allow forms with |
| empty_permitted = True, or forms where data has not changed. |
| """ |
| f1 = HashTestBlankForm({}) |
| f2 = HashTestForm({}, empty_permitted=True) |
| hash1 = utils.form_hmac(f1) |
| hash2 = utils.form_hmac(f2) |
| self.assertEqual(hash1, hash2) |
| |
| |
| class HashTestForm(forms.Form): |
| name = forms.CharField() |
| bio = forms.CharField() |
| |
| |
| class HashTestBlankForm(forms.Form): |
| name = forms.CharField(required=False) |
| bio = forms.CharField(required=False) |
| |
| # |
| # FormWizard tests |
| # |
| |
| |
| class WizardPageOneForm(forms.Form): |
| field = forms.CharField() |
| |
| |
| class WizardPageTwoForm(forms.Form): |
| field = forms.CharField() |
| |
| |
| class WizardPageThreeForm(forms.Form): |
| field = forms.CharField() |
| |
| |
| class WizardClass(wizard.FormWizard): |
| |
| def get_template(self, step): |
| return 'formwizard/wizard.html' |
| |
| def done(self, request, cleaned_data): |
| return http.HttpResponse(success_string) |
| |
| |
| class UserSecuredWizardClass(WizardClass): |
| """ |
| Wizard with a custum security_hash method |
| """ |
| def security_hash(self, request, form): |
| return "123" |
| |
| |
| class DummyRequest(http.HttpRequest): |
| |
| def __init__(self, POST=None): |
| super(DummyRequest, self).__init__() |
| self.method = POST and "POST" or "GET" |
| if POST is not None: |
| self.POST.update(POST) |
| self._dont_enforce_csrf_checks = True |
| |
| |
| class WizardTests(TestCase): |
| urls = 'django.contrib.formtools.tests.urls' |
| |
| def setUp(self): |
| self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS |
| settings.TEMPLATE_DIRS = ( |
| os.path.join( |
| os.path.dirname(__file__), |
| 'templates' |
| ), |
| ) |
| # Use a known SECRET_KEY to make security_hash tests deterministic |
| self.old_SECRET_KEY = settings.SECRET_KEY |
| settings.SECRET_KEY = "123" |
| |
| def tearDown(self): |
| settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS |
| settings.SECRET_KEY = self.old_SECRET_KEY |
| |
| def test_step_starts_at_zero(self): |
| """ |
| step should be zero for the first form |
| """ |
| response = self.client.get('/wizard/') |
| self.assertEquals(0, response.context['step0']) |
| |
| def test_step_increments(self): |
| """ |
| step should be incremented when we go to the next page |
| """ |
| response = self.client.post('/wizard/', {"0-field":"test", "wizard_step":"0"}) |
| self.assertEquals(1, response.context['step0']) |
| |
| def test_bad_hash(self): |
| """ |
| Form should not advance if the hash is missing or bad |
| """ |
| response = self.client.post('/wizard/', |
| {"0-field":"test", |
| "1-field":"test2", |
| "wizard_step": "1"}) |
| self.assertEquals(0, response.context['step0']) |
| |
| def test_good_hash_django12(self): |
| """ |
| Form should advance if the hash is present and good, as calculated using |
| django 1.2 method. |
| """ |
| # We are hard-coding a hash value here, but that is OK, since we want to |
| # ensure that we don't accidentally change the algorithm. |
| data = {"0-field": "test", |
| "1-field": "test2", |
| "hash_0": "2fdbefd4c0cad51509478fbacddf8b13", |
| "wizard_step": "1"} |
| response = self.client.post('/wizard/', data) |
| self.assertEquals(2, response.context['step0']) |
| |
| def test_good_hash_django12_subclass(self): |
| """ |
| The Django 1.2 method of calulating hashes should *not* be used as a |
| fallback if the FormWizard subclass has provided their own method |
| of calculating a hash. |
| """ |
| # We are hard-coding a hash value here, but that is OK, since we want to |
| # ensure that we don't accidentally change the algorithm. |
| data = {"0-field": "test", |
| "1-field": "test2", |
| "hash_0": "2fdbefd4c0cad51509478fbacddf8b13", |
| "wizard_step": "1"} |
| response = self.client.post('/wizard2/', data) |
| self.assertEquals(0, response.context['step0']) |
| |
| def test_good_hash_current(self): |
| """ |
| Form should advance if the hash is present and good, as calculated using |
| current method. |
| """ |
| data = {"0-field": "test", |
| "1-field": "test2", |
| "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c", |
| "wizard_step": "1"} |
| response = self.client.post('/wizard/', data) |
| self.assertEquals(2, response.context['step0']) |
| |
| def test_14498(self): |
| """ |
| Regression test for ticket #14498. |
| """ |
| that = self |
| |
| class WizardWithProcessStep(WizardClass): |
| def process_step(self, request, form, step): |
| that.assertTrue(hasattr(form, 'cleaned_data')) |
| |
| wizard = WizardWithProcessStep([WizardPageOneForm, |
| WizardPageTwoForm, |
| WizardPageThreeForm]) |
| data = {"0-field": "test", |
| "1-field": "test2", |
| "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c", |
| "wizard_step": "1"} |
| wizard(DummyRequest(POST=data)) |
| |
| def test_14576(self): |
| """ |
| Regression test for ticket #14576. |
| |
| The form of the last step is not passed to the done method. |
| """ |
| reached = [False] |
| that = self |
| |
| class Wizard(WizardClass): |
| def done(self, request, form_list): |
| reached[0] = True |
| that.assertTrue(len(form_list) == 2) |
| |
| wizard = Wizard([WizardPageOneForm, |
| WizardPageTwoForm]) |
| |
| data = {"0-field": "test", |
| "1-field": "test2", |
| "hash_0": "2fdbefd4c0cad51509478fbacddf8b13", |
| "wizard_step": "1"} |
| wizard(DummyRequest(POST=data)) |
| self.assertTrue(reached[0]) |