Ticket #11797: test_client_form_parsing.diff
File test_client_form_parsing.diff, 11.0 KB (added by , 15 years ago) |
---|
-
django/test/client.py
1 1 import urllib 2 2 from urlparse import urlparse, urlunparse, urlsplit 3 from HTMLParser import HTMLParser 3 4 import sys 4 5 import os 5 6 import re … … 13 14 from django.core.handlers.base import BaseHandler 14 15 from django.core.handlers.wsgi import WSGIRequest 15 16 from django.core.signals import got_request_exception 16 from django.http import SimpleCookie, HttpRequest, QueryDict17 from django.http import SimpleCookie, HttpRequest, HttpResponse, QueryDict 17 18 from django.template import TemplateDoesNotExist 18 19 from django.test import signals 19 20 from django.utils.functional import curry … … 84 85 85 86 return response 86 87 88 89 class FormHTMLParser(HTMLParser): 90 """ 91 Exctracts the list of forms and fields with their values to 92 facilitate re-submission 93 """ 94 95 _tag_list = ['form', 'input', 'textarea', 'select', 'option'] 96 97 def __init__(self): 98 self._curTagName = None 99 self._curTagType = None 100 self.forms = None 101 self.forms_count = 0 102 HTMLParser.__init__(self) 103 104 def handle_starttag(self, tag, attrs): 105 if tag in self._tag_list: 106 attrs = dict(attrs) 107 self._curTagType = tag 108 109 if tag == 'form': 110 if self.forms is None: 111 self.forms = {} 112 self.forms_count = 0 113 # We can use either the name or id here because it will 114 # not be passed back to the server. It's only used for 115 # easier (more plain) reference in testing code. 116 if attrs.has_key('name'): 117 self._curForm = attrs['name'] 118 elif attrs.has_key('id'): 119 self._curForm = attrs['id'] 120 else: 121 # ? Should this be a string (for consistancy) or a real number? 122 self._curForm = str(self.forms_count) 123 self.forms[self._curForm] = {} 124 self.forms_count = self.forms_count + 1 125 126 elif tag == 'input' and attrs['type'] not in ('checkbox', 'radio'): 127 if attrs.has_key('name'): 128 if not attrs.has_key('value'): 129 attrs['value'] = '' 130 self.forms[self._curForm][attrs['name']] = attrs['value'] 131 self._curTagName = attrs['name'] 132 133 elif tag == 'input' and attrs['type'] in ('checkbox', 'radio'): 134 if attrs.has_key('checked'): 135 if not attrs.has_key('value'): 136 attrs['value'] = 'on' 137 if self.forms[self._curForm].has_key(attrs['name']): 138 self.forms[self._curForm][attrs['name']].append(attrs['value']) 139 else: 140 self.forms[self._curForm][attrs['name']] = [attrs['value']] 141 self._curTagName = attrs['name'] 142 143 elif tag == 'textarea': 144 self.forms[self._curForm][attrs['name']] = '' 145 self._curTagName = attrs['name'] 146 147 elif tag == 'select': 148 self.forms[self._curForm][attrs['name']] = [] 149 self._curTagName = attrs['name'] 150 151 elif tag == 'option': 152 if attrs.has_key('selected'): 153 self.forms[self._curForm][self._curTagName].append(attrs['value']) 154 155 def handle_data(self, data): 156 if self._curTagName: 157 if self._curTagType == 'textarea': 158 # This is to ensure that there is always just a \r\n, as is the observed 159 # behavior of web browsers. 160 self.forms[self._curForm][self._curTagName] = data.replace('\r\n', '\n').replace('\n', '\r\n') 161 162 def handle_endtag(self, tag): 163 if self._curTagName and tag != 'option': 164 self._curTagName = None 165 166 class FieldNotFound(KeyError): 167 "Raised when a requested field or form is not found" 168 pass 169 170 def castHttpResponse(curResponse): 171 172 class _TestHttpResponse(curResponse.__class__): 173 174 def form_data(self, search_name): 175 """ 176 Returns the entire set of form values associated with form of the given field or form name 177 """ 178 if getattr(self, "_form_data", None) is None: 179 self._form_data = self._get_form_data() 180 if self._form_data.has_key(search_name): 181 return self._form_data[search_name] 182 for form_name, data in self._form_data.items(): 183 if data.has_key(search_name): 184 return data 185 raise FieldNotFound("A field or form with the name %s was not found." % search_name) 186 187 def _get_form_data(self): 188 curParser = FormHTMLParser() 189 curParser.feed(self.content) 190 curParser.close() 191 return curParser.forms 192 193 curResponse.__class__ = _TestHttpResponse 194 195 return curResponse 196 197 87 198 def store_rendered_templates(store, signal, sender, template, context, **kwargs): 88 199 """ 89 200 Stores templates and contexts that are rendered. … … 246 357 exc_info = self.exc_info 247 358 self.exc_info = None 248 359 raise exc_info[1], None, exc_info[2] 360 361 # Add the form field processing to response object 362 response = castHttpResponse(response) 249 363 250 364 # Save the client and request that stimulated the response. 251 365 response.client = self -
docs/topics/testing.txt
836 836 >>> response = client.get('/foo/') 837 837 >>> response.context['name'] 838 838 'Arthur' 839 840 .. method:: form_data(name) 841 842 .. versionadded:: 1.2 843 844 Returns a dictionary of values for a given form. If you give a name to your 845 buttons their values will also be returned. You can supply either the name or 846 id of the form or the name of any field or button and you will receive all 847 values for the form. 848 849 >>> response = client.get('/foo/') 850 >>> response.form_data('subject_field') 851 {'subject_field': 'Please visit my site', 'email_field': 'joe@xyz.com'} 852 853 The resulting dictionary can then be used to easily change form data and 854 submit the form. 855 856 >>> my_form_data = response.form_data('subject_field') 857 >>> my_form_data['email_field'] = 'mark@mycompany.com' 858 >>> response = client.post('/foo/', my_form_data) 859 839 860 840 861 .. attribute:: request 841 862 -
tests/regressiontests/test_client_regress/models.py
821 821 response = self.client.post("/test_client_regress/parse_unicode_json/", json, 822 822 content_type="application/json; charset=koi8-r") 823 823 self.assertEqual(response.content, json.encode('koi8-r')) 824 825 class FormProcessingTests(TestCase): 826 def test_extraction(self): 827 "The form values can be extracted, submitted, and re-extracted reliably." 828 # Regression test for #11797 829 from django.test.client import FieldNotFound 830 831 response = self.client.get('/test_client_regress/form_processing/') 832 self.failUnlessEqual(response.status_code, 200, 'Failed to retrieve the form test page. (Status code: %s)' % response.status_code) 833 834 curVals = response.form_data('frmTest') 835 curVals2 = response.form_data('choiceFld') 836 837 self.assert_(curVals == curVals2, 'The form name did not return the same data as the field name.') 838 839 self.assertRaises(FieldNotFound, response.form_data, 'badField') 840 841 response = self.client.post('/test_client_regress/form_processing/', curVals) 842 self.failUnlessEqual(response.status_code, 200, 'Failed to retrieve the form test page. (Status code: %s)' % response.status_code) 843 self.assert_(response.context['form'].errors == {}, 'There was a problem detected in the view: %s' % response.context['form'].errors) 844 845 curVals2 = response.form_data('charFld') 846 847 self.assert_(curVals == curVals2, 'The test client did not return the same data after submission.') 848 849 curVals2['MultiChoiceFld'] = ['pt', 'es'] 850 response = self.client.post('/test_client_regress/form_processing/', curVals2) 851 self.failUnlessEqual(response.status_code, 200, 'Failed to retrieve the form test page. (Status code: %s)' % response.status_code) 852 self.assert_(response.context['form'].errors == {}, 'There was a problem detected in the view: %s' % response.context['form'].errors) 853 854 curVals3 = response.form_data('rChoiceFld') 855 self.assert_(curVals != curVals3 and curVals3 == curVals2, 'The test client did not properly return the modification data after submission.') -
tests/regressiontests/test_client_regress/urls.py
24 24 (r'^request_methods/$', views.request_methods_view), 25 25 (r'^check_unicode/$', views.return_unicode), 26 26 (r'^parse_unicode_json/$', views.return_json_file), 27 (r'^form_processing/$', views.test_form_proc), 27 28 ) -
tests/regressiontests/test_client_regress/views.py
86 86 mimetype='application/json; charset=' + charset) 87 87 response['Content-Disposition'] = 'attachment; filename=testfile.json' 88 88 return response 89 90 def test_form_proc(request): 91 "A view that captures and returns the form fields processed by the test client" 92 from forms import TestFormProcForm 93 94 if request.method == 'POST': 95 form = TestFormProcForm(request.POST) 96 form.is_valid() 97 else: 98 form = TestFormProcForm() 99 return render_to_response('form_view.html', {'form': form}) -
tests/templates/form_view.html
2 2 {% block title %}Submit data{% endblock %} 3 3 {% block content %} 4 4 <h1>{{ message }}</h1> 5 <form method='post' action='.' >5 <form method='post' action='.' name="frmTest"> 6 6 {% if form.errors %} 7 7 <p class='warning'>Please correct the errors below:</p> 8 8 {% endif %}