~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/regressiontests/forms/tests/widgets.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-11-07 15:33:49 UTC
  • mfrom: (1.3.12)
  • Revision ID: package-import@ubuntu.com-20131107153349-e31sc149l2szs3jb
Tags: 1.6-1
* New upstream version. Closes: #557474, #724637.
* python-django now also suggests the installation of ipython,
  bpython, python-django-doc, and libgdal1.
  Closes: #636511, #686333, #704203
* Set package maintainer to Debian Python Modules Team.
* Bump standards version to 3.9.5, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
from __future__ import unicode_literals
3
 
 
4
 
import copy
5
 
import datetime
6
 
 
7
 
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
8
 
from django.core.files.uploadedfile import SimpleUploadedFile
9
 
from django.core.urlresolvers import reverse
10
 
from django.forms import *
11
 
from django.forms.widgets import RadioFieldRenderer
12
 
from django.utils import formats
13
 
from django.utils.safestring import mark_safe
14
 
from django.utils import six
15
 
from django.utils.translation import activate, deactivate
16
 
from django.test import TestCase
17
 
from django.test.utils import override_settings
18
 
from django.utils.encoding import python_2_unicode_compatible
19
 
 
20
 
from ..models import Article
21
 
 
22
 
 
23
 
class FormsWidgetTestCase(TestCase):
24
 
    # Each Widget class corresponds to an HTML form widget. A Widget knows how to
25
 
    # render itself, given a field name and some data. Widgets don't perform
26
 
    # validation.
27
 
    def test_textinput(self):
28
 
        w = TextInput()
29
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="text" name="email" />')
30
 
        self.assertHTMLEqual(w.render('email', None), '<input type="text" name="email" />')
31
 
        self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="text" name="email" value="test@example.com" />')
32
 
        self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="text" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />')
33
 
        self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="text" name="email" value="test@example.com" class="fun" />')
34
 
 
35
 
        self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="text" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" class="fun" />')
36
 
 
37
 
        # You can also pass 'attrs' to the constructor:
38
 
        w = TextInput(attrs={'class': 'fun', 'type': 'email'})
39
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="email" class="fun" name="email" />')
40
 
        self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="email" class="fun" value="foo@example.com" name="email" />')
41
 
 
42
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
43
 
        w = TextInput(attrs={'class': 'pretty'})
44
 
        self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="text" class="special" name="email" />')
45
 
 
46
 
        # 'attrs' can be safe-strings if needed)
47
 
        w = TextInput(attrs={'onBlur': mark_safe("function('foo')")})
48
 
        self.assertHTMLEqual(w.render('email', ''), '<input onBlur="function(\'foo\')" type="text" name="email" />')
49
 
 
50
 
    def test_passwordinput(self):
51
 
        w = PasswordInput()
52
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="password" name="email" />')
53
 
        self.assertHTMLEqual(w.render('email', None), '<input type="password" name="email" />')
54
 
        self.assertHTMLEqual(w.render('email', 'secret'), '<input type="password" name="email" />')
55
 
 
56
 
        # The render_value argument lets you specify whether the widget should render
57
 
        # its value. For security reasons, this is off by default.
58
 
        w = PasswordInput(render_value=True)
59
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="password" name="email" />')
60
 
        self.assertHTMLEqual(w.render('email', None), '<input type="password" name="email" />')
61
 
        self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="password" name="email" value="test@example.com" />')
62
 
        self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="password" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />')
63
 
        self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="password" name="email" value="test@example.com" class="fun" />')
64
 
 
65
 
        # You can also pass 'attrs' to the constructor:
66
 
        w = PasswordInput(attrs={'class': 'fun'}, render_value=True)
67
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="password" class="fun" name="email" />')
68
 
        self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="password" class="fun" value="foo@example.com" name="email" />')
69
 
 
70
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
71
 
        w = PasswordInput(attrs={'class': 'pretty'}, render_value=True)
72
 
        self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="password" class="special" name="email" />')
73
 
 
74
 
        self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
75
 
 
76
 
    def test_hiddeninput(self):
77
 
        w = HiddenInput()
78
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="hidden" name="email" />')
79
 
        self.assertHTMLEqual(w.render('email', None), '<input type="hidden" name="email" />')
80
 
        self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="hidden" name="email" value="test@example.com" />')
81
 
        self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="hidden" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />')
82
 
        self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />')
83
 
 
84
 
        # You can also pass 'attrs' to the constructor:
85
 
        w = HiddenInput(attrs={'class': 'fun'})
86
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="hidden" class="fun" name="email" />')
87
 
        self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="hidden" class="fun" value="foo@example.com" name="email" />')
88
 
 
89
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
90
 
        w = HiddenInput(attrs={'class': 'pretty'})
91
 
        self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="hidden" class="special" name="email" />')
92
 
 
93
 
        self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
94
 
 
95
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
96
 
        w = HiddenInput(attrs={'class': 'pretty'})
97
 
        self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="hidden" class="special" name="email" />')
98
 
 
99
 
        # Boolean values are rendered to their string forms ("True" and "False").
100
 
        w = HiddenInput()
101
 
        self.assertHTMLEqual(w.render('get_spam', False), '<input type="hidden" name="get_spam" value="False" />')
102
 
        self.assertHTMLEqual(w.render('get_spam', True), '<input type="hidden" name="get_spam" value="True" />')
103
 
 
104
 
    def test_multiplehiddeninput(self):
105
 
        w = MultipleHiddenInput()
106
 
        self.assertHTMLEqual(w.render('email', []), '')
107
 
        self.assertHTMLEqual(w.render('email', None), '')
108
 
        self.assertHTMLEqual(w.render('email', ['test@example.com']), '<input type="hidden" name="email" value="test@example.com" />')
109
 
        self.assertHTMLEqual(w.render('email', ['some "quoted" & ampersanded value']), '<input type="hidden" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />')
110
 
        self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com']), '<input type="hidden" name="email" value="test@example.com" />\n<input type="hidden" name="email" value="foo@example.com" />')
111
 
        self.assertHTMLEqual(w.render('email', ['test@example.com'], attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />')
112
 
        self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />')
113
 
 
114
 
        # You can also pass 'attrs' to the constructor:
115
 
        w = MultipleHiddenInput(attrs={'class': 'fun'})
116
 
        self.assertHTMLEqual(w.render('email', []), '')
117
 
        self.assertHTMLEqual(w.render('email', ['foo@example.com']), '<input type="hidden" class="fun" value="foo@example.com" name="email" />')
118
 
        self.assertHTMLEqual(w.render('email', ['foo@example.com', 'test@example.com']), '<input type="hidden" class="fun" value="foo@example.com" name="email" />\n<input type="hidden" class="fun" value="test@example.com" name="email" />')
119
 
 
120
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
121
 
        w = MultipleHiddenInput(attrs={'class': 'pretty'})
122
 
        self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '<input type="hidden" class="special" value="foo@example.com" name="email" />')
123
 
 
124
 
        self.assertHTMLEqual(w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}), '<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
125
 
 
126
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
127
 
        w = MultipleHiddenInput(attrs={'class': 'pretty'})
128
 
        self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '<input type="hidden" class="special" value="foo@example.com" name="email" />')
129
 
 
130
 
        # Each input gets a separate ID.
131
 
        w = MultipleHiddenInput()
132
 
        self.assertHTMLEqual(w.render('letters', list('abc'), attrs={'id': 'hideme'}), '<input type="hidden" name="letters" value="a" id="hideme_0" />\n<input type="hidden" name="letters" value="b" id="hideme_1" />\n<input type="hidden" name="letters" value="c" id="hideme_2" />')
133
 
 
134
 
    def test_fileinput(self):
135
 
        # FileInput widgets don't ever show the value, because the old value is of no use
136
 
        # if you are updating the form or if the provided file generated an error.
137
 
        w = FileInput()
138
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="file" name="email" />')
139
 
        self.assertHTMLEqual(w.render('email', None), '<input type="file" name="email" />')
140
 
        self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="file" name="email" />')
141
 
        self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="file" name="email" />')
142
 
        self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="file" name="email" class="fun" />')
143
 
 
144
 
        # You can also pass 'attrs' to the constructor:
145
 
        w = FileInput(attrs={'class': 'fun'})
146
 
        self.assertHTMLEqual(w.render('email', ''), '<input type="file" class="fun" name="email" />')
147
 
        self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="file" class="fun" name="email" />')
148
 
 
149
 
        self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="file" class="fun" name="email" />')
150
 
 
151
 
        # Test for the behavior of _has_changed for FileInput. The value of data will
152
 
        # more than likely come from request.FILES. The value of initial data will
153
 
        # likely be a filename stored in the database. Since its value is of no use to
154
 
        # a FileInput it is ignored.
155
 
        w = FileInput()
156
 
 
157
 
        # No file was uploaded and no initial data.
158
 
        self.assertFalse(w._has_changed('', None))
159
 
 
160
 
        # A file was uploaded and no initial data.
161
 
        self.assertTrue(w._has_changed('', {'filename': 'resume.txt', 'content': 'My resume'}))
162
 
 
163
 
        # A file was not uploaded, but there is initial data
164
 
        self.assertFalse(w._has_changed('resume.txt', None))
165
 
 
166
 
        # A file was uploaded and there is initial data (file identity is not dealt
167
 
        # with here)
168
 
        self.assertTrue(w._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'}))
169
 
 
170
 
    def test_textarea(self):
171
 
        w = Textarea()
172
 
        self.assertHTMLEqual(w.render('msg', ''), '<textarea rows="10" cols="40" name="msg"></textarea>')
173
 
        self.assertHTMLEqual(w.render('msg', None), '<textarea rows="10" cols="40" name="msg"></textarea>')
174
 
        self.assertHTMLEqual(w.render('msg', 'value'), '<textarea rows="10" cols="40" name="msg">value</textarea>')
175
 
        self.assertHTMLEqual(w.render('msg', 'some "quoted" & ampersanded value'), '<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>')
176
 
        self.assertHTMLEqual(w.render('msg', mark_safe('pre &quot;quoted&quot; value')), '<textarea rows="10" cols="40" name="msg">pre &quot;quoted&quot; value</textarea>')
177
 
        self.assertHTMLEqual(w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}), '<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>')
178
 
 
179
 
        # You can also pass 'attrs' to the constructor:
180
 
        w = Textarea(attrs={'class': 'pretty'})
181
 
        self.assertHTMLEqual(w.render('msg', ''), '<textarea rows="10" cols="40" name="msg" class="pretty"></textarea>')
182
 
        self.assertHTMLEqual(w.render('msg', 'example'), '<textarea rows="10" cols="40" name="msg" class="pretty">example</textarea>')
183
 
 
184
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
185
 
        w = Textarea(attrs={'class': 'pretty'})
186
 
        self.assertHTMLEqual(w.render('msg', '', attrs={'class': 'special'}), '<textarea rows="10" cols="40" name="msg" class="special"></textarea>')
187
 
 
188
 
        self.assertHTMLEqual(w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>')
189
 
 
190
 
    def test_checkboxinput(self):
191
 
        w = CheckboxInput()
192
 
        self.assertHTMLEqual(w.render('is_cool', ''), '<input type="checkbox" name="is_cool" />')
193
 
        self.assertHTMLEqual(w.render('is_cool', None), '<input type="checkbox" name="is_cool" />')
194
 
        self.assertHTMLEqual(w.render('is_cool', False), '<input type="checkbox" name="is_cool" />')
195
 
        self.assertHTMLEqual(w.render('is_cool', True), '<input checked="checked" type="checkbox" name="is_cool" />')
196
 
 
197
 
        # Using any value that's not in ('', None, False, True) will check the checkbox
198
 
        # and set the 'value' attribute.
199
 
        self.assertHTMLEqual(w.render('is_cool', 'foo'), '<input checked="checked" type="checkbox" name="is_cool" value="foo" />')
200
 
 
201
 
        self.assertHTMLEqual(w.render('is_cool', False, attrs={'class': 'pretty'}), '<input type="checkbox" name="is_cool" class="pretty" />')
202
 
 
203
 
        # regression for #17114
204
 
        self.assertHTMLEqual(w.render('is_cool', 0), '<input checked="checked" type="checkbox" name="is_cool" value="0" />')
205
 
        self.assertHTMLEqual(w.render('is_cool', 1), '<input checked="checked" type="checkbox" name="is_cool" value="1" />')
206
 
 
207
 
        # You can also pass 'attrs' to the constructor:
208
 
        w = CheckboxInput(attrs={'class': 'pretty'})
209
 
        self.assertHTMLEqual(w.render('is_cool', ''), '<input type="checkbox" class="pretty" name="is_cool" />')
210
 
 
211
 
        # 'attrs' passed to render() get precedence over those passed to the constructor:
212
 
        w = CheckboxInput(attrs={'class': 'pretty'})
213
 
        self.assertHTMLEqual(w.render('is_cool', '', attrs={'class': 'special'}), '<input type="checkbox" class="special" name="is_cool" />')
214
 
 
215
 
        # You can pass 'check_test' to the constructor. This is a callable that takes the
216
 
        # value and returns True if the box should be checked.
217
 
        w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
218
 
        self.assertHTMLEqual(w.render('greeting', ''), '<input type="checkbox" name="greeting" />')
219
 
        self.assertHTMLEqual(w.render('greeting', 'hello'), '<input checked="checked" type="checkbox" name="greeting" value="hello" />')
220
 
        self.assertHTMLEqual(w.render('greeting', 'hello there'), '<input checked="checked" type="checkbox" name="greeting" value="hello there" />')
221
 
        self.assertHTMLEqual(w.render('greeting', 'hello & goodbye'), '<input checked="checked" type="checkbox" name="greeting" value="hello &amp; goodbye" />')
222
 
 
223
 
        # Ticket #17888: calling check_test shouldn't swallow exceptions
224
 
        with self.assertRaises(AttributeError):
225
 
            w.render('greeting', True)
226
 
 
227
 
        # The CheckboxInput widget will return False if the key is not found in the data
228
 
        # dictionary (because HTML form submission doesn't send any result for unchecked
229
 
        # checkboxes).
230
 
        self.assertFalse(w.value_from_datadict({}, {}, 'testing'))
231
 
 
232
 
        value = w.value_from_datadict({'testing': '0'}, {}, 'testing')
233
 
        self.assertIsInstance(value, bool)
234
 
        self.assertTrue(value)
235
 
 
236
 
        self.assertFalse(w._has_changed(None, None))
237
 
        self.assertFalse(w._has_changed(None, ''))
238
 
        self.assertFalse(w._has_changed('', None))
239
 
        self.assertFalse(w._has_changed('', ''))
240
 
        self.assertTrue(w._has_changed(False, 'on'))
241
 
        self.assertFalse(w._has_changed(True, 'on'))
242
 
        self.assertTrue(w._has_changed(True, ''))
243
 
        # Initial value may have mutated to a string due to show_hidden_initial (#19537)
244
 
        self.assertTrue(w._has_changed('False', 'on'))
245
 
 
246
 
    def test_select(self):
247
 
        w = Select()
248
 
        self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
249
 
<option value="J" selected="selected">John</option>
250
 
<option value="P">Paul</option>
251
 
<option value="G">George</option>
252
 
<option value="R">Ringo</option>
253
 
</select>""")
254
 
 
255
 
        # If the value is None, none of the options are selected:
256
 
        self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
257
 
<option value="J">John</option>
258
 
<option value="P">Paul</option>
259
 
<option value="G">George</option>
260
 
<option value="R">Ringo</option>
261
 
</select>""")
262
 
 
263
 
        # If the value corresponds to a label (but not to an option value), none of the options are selected:
264
 
        self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
265
 
<option value="J">John</option>
266
 
<option value="P">Paul</option>
267
 
<option value="G">George</option>
268
 
<option value="R">Ringo</option>
269
 
</select>""")
270
 
 
271
 
        # Only one option can be selected, see #8103:
272
 
        self.assertHTMLEqual(w.render('choices', '0', choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select name="choices">
273
 
<option value="0" selected="selected">0</option>
274
 
<option value="1">1</option>
275
 
<option value="2">2</option>
276
 
<option value="3">3</option>
277
 
<option value="0">extra</option>
278
 
</select>""")
279
 
 
280
 
        # The value is compared to its str():
281
 
        self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select name="num">
282
 
<option value="1">1</option>
283
 
<option value="2" selected="selected">2</option>
284
 
<option value="3">3</option>
285
 
</select>""")
286
 
        self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """<select name="num">
287
 
<option value="1">1</option>
288
 
<option value="2" selected="selected">2</option>
289
 
<option value="3">3</option>
290
 
</select>""")
291
 
        self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """<select name="num">
292
 
<option value="1">1</option>
293
 
<option value="2" selected="selected">2</option>
294
 
<option value="3">3</option>
295
 
</select>""")
296
 
 
297
 
        # The 'choices' argument can be any iterable:
298
 
        from itertools import chain
299
 
        def get_choices():
300
 
            for i in range(5):
301
 
                yield (i, i)
302
 
        self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """<select name="num">
303
 
<option value="0">0</option>
304
 
<option value="1">1</option>
305
 
<option value="2" selected="selected">2</option>
306
 
<option value="3">3</option>
307
 
<option value="4">4</option>
308
 
</select>""")
309
 
        things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
310
 
        class SomeForm(Form):
311
 
            somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
312
 
        f = SomeForm()
313
 
        self.assertHTMLEqual(f.as_table(), '<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>')
314
 
        self.assertHTMLEqual(f.as_table(), '<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>')
315
 
        f = SomeForm({'somechoice': 2})
316
 
        self.assertHTMLEqual(f.as_table(), '<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="">---------</option>\n<option value="1">And Boom</option>\n<option value="2" selected="selected">One More Thing!</option>\n</select></td></tr>')
317
 
 
318
 
        # You can also pass 'choices' to the constructor:
319
 
        w = Select(choices=[(1, 1), (2, 2), (3, 3)])
320
 
        self.assertHTMLEqual(w.render('num', 2), """<select name="num">
321
 
<option value="1">1</option>
322
 
<option value="2" selected="selected">2</option>
323
 
<option value="3">3</option>
324
 
</select>""")
325
 
 
326
 
        # If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
327
 
        self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """<select name="num">
328
 
<option value="1">1</option>
329
 
<option value="2" selected="selected">2</option>
330
 
<option value="3">3</option>
331
 
<option value="4">4</option>
332
 
<option value="5">5</option>
333
 
</select>""")
334
 
 
335
 
        # Choices are escaped correctly
336
 
        self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me')))), """<select name="escape">
337
 
<option value="1">1</option>
338
 
<option value="2">2</option>
339
 
<option value="3">3</option>
340
 
<option value="bad">you &amp; me</option>
341
 
<option value="good">you &gt; me</option>
342
 
</select>""")
343
 
 
344
 
        # Unicode choices are correctly rendered as HTML
345
 
        self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>')
346
 
 
347
 
        # If choices is passed to the constructor and is a generator, it can be iterated
348
 
        # over multiple times without getting consumed:
349
 
        w = Select(choices=get_choices())
350
 
        self.assertHTMLEqual(w.render('num', 2), """<select name="num">
351
 
<option value="0">0</option>
352
 
<option value="1">1</option>
353
 
<option value="2" selected="selected">2</option>
354
 
<option value="3">3</option>
355
 
<option value="4">4</option>
356
 
</select>""")
357
 
        self.assertHTMLEqual(w.render('num', 3), """<select name="num">
358
 
<option value="0">0</option>
359
 
<option value="1">1</option>
360
 
<option value="2">2</option>
361
 
<option value="3" selected="selected">3</option>
362
 
<option value="4">4</option>
363
 
</select>""")
364
 
 
365
 
        # Choices can be nested one level in order to create HTML optgroups:
366
 
        w.choices=(('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
367
 
        self.assertHTMLEqual(w.render('nestchoice', None), """<select name="nestchoice">
368
 
<option value="outer1">Outer 1</option>
369
 
<optgroup label="Group &quot;1&quot;">
370
 
<option value="inner1">Inner 1</option>
371
 
<option value="inner2">Inner 2</option>
372
 
</optgroup>
373
 
</select>""")
374
 
 
375
 
        self.assertHTMLEqual(w.render('nestchoice', 'outer1'), """<select name="nestchoice">
376
 
<option value="outer1" selected="selected">Outer 1</option>
377
 
<optgroup label="Group &quot;1&quot;">
378
 
<option value="inner1">Inner 1</option>
379
 
<option value="inner2">Inner 2</option>
380
 
</optgroup>
381
 
</select>""")
382
 
 
383
 
        self.assertHTMLEqual(w.render('nestchoice', 'inner1'), """<select name="nestchoice">
384
 
<option value="outer1">Outer 1</option>
385
 
<optgroup label="Group &quot;1&quot;">
386
 
<option value="inner1" selected="selected">Inner 1</option>
387
 
<option value="inner2">Inner 2</option>
388
 
</optgroup>
389
 
</select>""")
390
 
 
391
 
    def test_nullbooleanselect(self):
392
 
        w = NullBooleanSelect()
393
 
        self.assertTrue(w.render('is_cool', True), """<select name="is_cool">
394
 
<option value="1">Unknown</option>
395
 
<option value="2" selected="selected">Yes</option>
396
 
<option value="3">No</option>
397
 
</select>""")
398
 
        self.assertHTMLEqual(w.render('is_cool', False), """<select name="is_cool">
399
 
<option value="1">Unknown</option>
400
 
<option value="2">Yes</option>
401
 
<option value="3" selected="selected">No</option>
402
 
</select>""")
403
 
        self.assertHTMLEqual(w.render('is_cool', None), """<select name="is_cool">
404
 
<option value="1" selected="selected">Unknown</option>
405
 
<option value="2">Yes</option>
406
 
<option value="3">No</option>
407
 
</select>""")
408
 
        self.assertHTMLEqual(w.render('is_cool', '2'), """<select name="is_cool">
409
 
<option value="1">Unknown</option>
410
 
<option value="2" selected="selected">Yes</option>
411
 
<option value="3">No</option>
412
 
</select>""")
413
 
        self.assertHTMLEqual(w.render('is_cool', '3'), """<select name="is_cool">
414
 
<option value="1">Unknown</option>
415
 
<option value="2">Yes</option>
416
 
<option value="3" selected="selected">No</option>
417
 
</select>""")
418
 
        self.assertTrue(w._has_changed(False, None))
419
 
        self.assertTrue(w._has_changed(None, False))
420
 
        self.assertFalse(w._has_changed(None, None))
421
 
        self.assertFalse(w._has_changed(False, False))
422
 
        self.assertTrue(w._has_changed(True, False))
423
 
        self.assertTrue(w._has_changed(True, None))
424
 
        self.assertTrue(w._has_changed(True, False))
425
 
 
426
 
    def test_selectmultiple(self):
427
 
        w = SelectMultiple()
428
 
        self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
429
 
<option value="J" selected="selected">John</option>
430
 
<option value="P">Paul</option>
431
 
<option value="G">George</option>
432
 
<option value="R">Ringo</option>
433
 
</select>""")
434
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
435
 
<option value="J" selected="selected">John</option>
436
 
<option value="P" selected="selected">Paul</option>
437
 
<option value="G">George</option>
438
 
<option value="R">Ringo</option>
439
 
</select>""")
440
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
441
 
<option value="J" selected="selected">John</option>
442
 
<option value="P" selected="selected">Paul</option>
443
 
<option value="G">George</option>
444
 
<option value="R" selected="selected">Ringo</option>
445
 
</select>""")
446
 
 
447
 
        # If the value is None, none of the options are selected:
448
 
        self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
449
 
<option value="J">John</option>
450
 
<option value="P">Paul</option>
451
 
<option value="G">George</option>
452
 
<option value="R">Ringo</option>
453
 
</select>""")
454
 
 
455
 
        # If the value corresponds to a label (but not to an option value), none of the options are selected:
456
 
        self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
457
 
<option value="J">John</option>
458
 
<option value="P">Paul</option>
459
 
<option value="G">George</option>
460
 
<option value="R">Ringo</option>
461
 
</select>""")
462
 
 
463
 
        # Multiple options (with the same value) can be selected, see #8103:
464
 
        self.assertHTMLEqual(w.render('choices', ['0'], choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select multiple="multiple" name="choices">
465
 
<option value="0" selected="selected">0</option>
466
 
<option value="1">1</option>
467
 
<option value="2">2</option>
468
 
<option value="3">3</option>
469
 
<option value="0" selected="selected">extra</option>
470
 
</select>""")
471
 
 
472
 
        # If multiple values are given, but some of them are not valid, the valid ones are selected:
473
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
474
 
<option value="J" selected="selected">John</option>
475
 
<option value="P">Paul</option>
476
 
<option value="G" selected="selected">George</option>
477
 
<option value="R">Ringo</option>
478
 
</select>""")
479
 
 
480
 
        # The value is compared to its str():
481
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select multiple="multiple" name="nums">
482
 
<option value="1">1</option>
483
 
<option value="2" selected="selected">2</option>
484
 
<option value="3">3</option>
485
 
</select>""")
486
 
        self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """<select multiple="multiple" name="nums">
487
 
<option value="1">1</option>
488
 
<option value="2" selected="selected">2</option>
489
 
<option value="3">3</option>
490
 
</select>""")
491
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """<select multiple="multiple" name="nums">
492
 
<option value="1">1</option>
493
 
<option value="2" selected="selected">2</option>
494
 
<option value="3">3</option>
495
 
</select>""")
496
 
 
497
 
        # The 'choices' argument can be any iterable:
498
 
        def get_choices():
499
 
            for i in range(5):
500
 
                yield (i, i)
501
 
        self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """<select multiple="multiple" name="nums">
502
 
<option value="0">0</option>
503
 
<option value="1">1</option>
504
 
<option value="2" selected="selected">2</option>
505
 
<option value="3">3</option>
506
 
<option value="4">4</option>
507
 
</select>""")
508
 
 
509
 
        # You can also pass 'choices' to the constructor:
510
 
        w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
511
 
        self.assertHTMLEqual(w.render('nums', [2]), """<select multiple="multiple" name="nums">
512
 
<option value="1">1</option>
513
 
<option value="2" selected="selected">2</option>
514
 
<option value="3">3</option>
515
 
</select>""")
516
 
 
517
 
        # If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
518
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """<select multiple="multiple" name="nums">
519
 
<option value="1">1</option>
520
 
<option value="2" selected="selected">2</option>
521
 
<option value="3">3</option>
522
 
<option value="4">4</option>
523
 
<option value="5">5</option>
524
 
</select>""")
525
 
 
526
 
        # Choices are escaped correctly
527
 
        self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me')))), """<select multiple="multiple" name="escape">
528
 
<option value="1">1</option>
529
 
<option value="2">2</option>
530
 
<option value="3">3</option>
531
 
<option value="bad">you &amp; me</option>
532
 
<option value="good">you &gt; me</option>
533
 
</select>""")
534
 
 
535
 
        # Unicode choices are correctly rendered as HTML
536
 
        self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>')
537
 
 
538
 
        # Test the usage of _has_changed
539
 
        self.assertFalse(w._has_changed(None, None))
540
 
        self.assertFalse(w._has_changed([], None))
541
 
        self.assertTrue(w._has_changed(None, ['1']))
542
 
        self.assertFalse(w._has_changed([1, 2], ['1', '2']))
543
 
        self.assertTrue(w._has_changed([1, 2], ['1']))
544
 
        self.assertTrue(w._has_changed([1, 2], ['1', '3']))
545
 
 
546
 
        # Choices can be nested one level in order to create HTML optgroups:
547
 
        w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
548
 
        self.assertHTMLEqual(w.render('nestchoice', None), """<select multiple="multiple" name="nestchoice">
549
 
<option value="outer1">Outer 1</option>
550
 
<optgroup label="Group &quot;1&quot;">
551
 
<option value="inner1">Inner 1</option>
552
 
<option value="inner2">Inner 2</option>
553
 
</optgroup>
554
 
</select>""")
555
 
 
556
 
        self.assertHTMLEqual(w.render('nestchoice', ['outer1']), """<select multiple="multiple" name="nestchoice">
557
 
<option value="outer1" selected="selected">Outer 1</option>
558
 
<optgroup label="Group &quot;1&quot;">
559
 
<option value="inner1">Inner 1</option>
560
 
<option value="inner2">Inner 2</option>
561
 
</optgroup>
562
 
</select>""")
563
 
 
564
 
        self.assertHTMLEqual(w.render('nestchoice', ['inner1']), """<select multiple="multiple" name="nestchoice">
565
 
<option value="outer1">Outer 1</option>
566
 
<optgroup label="Group &quot;1&quot;">
567
 
<option value="inner1" selected="selected">Inner 1</option>
568
 
<option value="inner2">Inner 2</option>
569
 
</optgroup>
570
 
</select>""")
571
 
 
572
 
        self.assertHTMLEqual(w.render('nestchoice', ['outer1', 'inner2']), """<select multiple="multiple" name="nestchoice">
573
 
<option value="outer1" selected="selected">Outer 1</option>
574
 
<optgroup label="Group &quot;1&quot;">
575
 
<option value="inner1">Inner 1</option>
576
 
<option value="inner2" selected="selected">Inner 2</option>
577
 
</optgroup>
578
 
</select>""")
579
 
 
580
 
    def test_radioselect(self):
581
 
        w = RadioSelect()
582
 
        self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
583
 
<li><label><input checked="checked" type="radio" name="beatle" value="J" /> John</label></li>
584
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
585
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
586
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
587
 
</ul>""")
588
 
 
589
 
        # If the value is None, none of the options are checked:
590
 
        self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
591
 
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
592
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
593
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
594
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
595
 
</ul>""")
596
 
 
597
 
        # If the value corresponds to a label (but not to an option value), none of the options are checked:
598
 
        self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
599
 
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
600
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
601
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
602
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
603
 
</ul>""")
604
 
 
605
 
        # The value is compared to its str():
606
 
        self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<ul>
607
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
608
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
609
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
610
 
</ul>""")
611
 
        self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
612
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
613
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
614
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
615
 
</ul>""")
616
 
        self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
617
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
618
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
619
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
620
 
</ul>""")
621
 
 
622
 
        # The 'choices' argument can be any iterable:
623
 
        def get_choices():
624
 
            for i in range(5):
625
 
                yield (i, i)
626
 
        self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """<ul>
627
 
<li><label><input type="radio" name="num" value="0" /> 0</label></li>
628
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
629
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
630
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
631
 
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
632
 
</ul>""")
633
 
 
634
 
        # You can also pass 'choices' to the constructor:
635
 
        w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
636
 
        self.assertHTMLEqual(w.render('num', 2), """<ul>
637
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
638
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
639
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
640
 
</ul>""")
641
 
 
642
 
        # If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
643
 
        self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """<ul>
644
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
645
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
646
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
647
 
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
648
 
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
649
 
</ul>""")
650
 
 
651
 
        # RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
652
 
        # You can manipulate that object directly to customize the way the RadioSelect
653
 
        # is rendered.
654
 
        w = RadioSelect()
655
 
        r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
656
 
        inp_set1 = []
657
 
        inp_set2 = []
658
 
        inp_set3 = []
659
 
        inp_set4 = []
660
 
 
661
 
        for inp in r:
662
 
            inp_set1.append(str(inp))
663
 
            inp_set2.append('%s<br />' % inp)
664
 
            inp_set3.append('<p>%s %s</p>' % (inp.tag(), inp.choice_label))
665
 
            inp_set4.append('%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked()))
666
 
 
667
 
        self.assertHTMLEqual('\n'.join(inp_set1), """<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
668
 
<label><input type="radio" name="beatle" value="P" /> Paul</label>
669
 
<label><input type="radio" name="beatle" value="G" /> George</label>
670
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
671
 
        self.assertHTMLEqual('\n'.join(inp_set2), """<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label><br />
672
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
673
 
<label><input type="radio" name="beatle" value="G" /> George</label><br />
674
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label><br />""")
675
 
        self.assertHTMLEqual('\n'.join(inp_set3), """<p><input checked="checked" type="radio" name="beatle" value="J" /> John</p>
676
 
<p><input type="radio" name="beatle" value="P" /> Paul</p>
677
 
<p><input type="radio" name="beatle" value="G" /> George</p>
678
 
<p><input type="radio" name="beatle" value="R" /> Ringo</p>""")
679
 
        self.assertHTMLEqual('\n'.join(inp_set4), """beatle J J John True
680
 
beatle J P Paul False
681
 
beatle J G George False
682
 
beatle J R Ringo False""")
683
 
 
684
 
        # You can create your own custom renderers for RadioSelect to use.
685
 
        class MyRenderer(RadioFieldRenderer):
686
 
           def render(self):
687
 
               return '<br />\n'.join([six.text_type(choice) for choice in self])
688
 
        w = RadioSelect(renderer=MyRenderer)
689
 
        self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br />
690
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
691
 
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
692
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
693
 
 
694
 
        # Or you can use custom RadioSelect fields that use your custom renderer.
695
 
        class CustomRadioSelect(RadioSelect):
696
 
           renderer = MyRenderer
697
 
        w = CustomRadioSelect()
698
 
        self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br />
699
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
700
 
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
701
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
702
 
 
703
 
        # A RadioFieldRenderer object also allows index access to individual RadioInput
704
 
        w = RadioSelect()
705
 
        r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
706
 
        self.assertHTMLEqual(str(r[1]), '<label><input type="radio" name="beatle" value="P" /> Paul</label>')
707
 
        self.assertHTMLEqual(str(r[0]), '<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>')
708
 
        self.assertTrue(r[0].is_checked())
709
 
        self.assertFalse(r[1].is_checked())
710
 
        self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul'))
711
 
 
712
 
        try:
713
 
            r[10]
714
 
            self.fail("This offset should not exist.")
715
 
        except IndexError:
716
 
            pass
717
 
 
718
 
        # Choices are escaped correctly
719
 
        w = RadioSelect()
720
 
        self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me')))), """<ul>
721
 
<li><label><input type="radio" name="escape" value="bad" /> you &amp; me</label></li>
722
 
<li><label><input type="radio" name="escape" value="good" /> you &gt; me</label></li>
723
 
</ul>""")
724
 
 
725
 
        # Unicode choices are correctly rendered as HTML
726
 
        w = RadioSelect()
727
 
        self.assertHTMLEqual(six.text_type(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), '<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>')
728
 
 
729
 
        # Attributes provided at instantiation are passed to the constituent inputs
730
 
        w = RadioSelect(attrs={'id':'foo'})
731
 
        self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
732
 
<li><label for="foo_0"><input checked="checked" type="radio" id="foo_0" value="J" name="beatle" /> John</label></li>
733
 
<li><label for="foo_1"><input type="radio" id="foo_1" value="P" name="beatle" /> Paul</label></li>
734
 
<li><label for="foo_2"><input type="radio" id="foo_2" value="G" name="beatle" /> George</label></li>
735
 
<li><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle" /> Ringo</label></li>
736
 
</ul>""")
737
 
 
738
 
        # Attributes provided at render-time are passed to the constituent inputs
739
 
        w = RadioSelect()
740
 
        self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul>
741
 
<li><label for="bar_0"><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></li>
742
 
<li><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></li>
743
 
<li><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></li>
744
 
<li><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle" /> Ringo</label></li>
745
 
</ul>""")
746
 
 
747
 
    def test_checkboxselectmultiple(self):
748
 
        w = CheckboxSelectMultiple()
749
 
        self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
750
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
751
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
752
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
753
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
754
 
</ul>""")
755
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
756
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
757
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
758
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
759
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
760
 
</ul>""")
761
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
762
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
763
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
764
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
765
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li>
766
 
</ul>""")
767
 
 
768
 
        # If the value is None, none of the options are selected:
769
 
        self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
770
 
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
771
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
772
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
773
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
774
 
</ul>""")
775
 
 
776
 
        # If the value corresponds to a label (but not to an option value), none of the options are selected:
777
 
        self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
778
 
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
779
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
780
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
781
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
782
 
</ul>""")
783
 
 
784
 
        # If multiple values are given, but some of them are not valid, the valid ones are selected:
785
 
        self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
786
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
787
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
788
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li>
789
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
790
 
</ul>""")
791
 
 
792
 
        # The value is compared to its str():
793
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<ul>
794
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
795
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
796
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
797
 
</ul>""")
798
 
        self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
799
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
800
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
801
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
802
 
</ul>""")
803
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
804
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
805
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
806
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
807
 
</ul>""")
808
 
 
809
 
        # The 'choices' argument can be any iterable:
810
 
        def get_choices():
811
 
            for i in range(5):
812
 
                yield (i, i)
813
 
        self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """<ul>
814
 
<li><label><input type="checkbox" name="nums" value="0" /> 0</label></li>
815
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
816
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
817
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
818
 
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
819
 
</ul>""")
820
 
 
821
 
        # You can also pass 'choices' to the constructor:
822
 
        w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
823
 
        self.assertHTMLEqual(w.render('nums', [2]), """<ul>
824
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
825
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
826
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
827
 
</ul>""")
828
 
 
829
 
        # If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
830
 
        self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """<ul>
831
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
832
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
833
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
834
 
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
835
 
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
836
 
</ul>""")
837
 
 
838
 
        # Choices are escaped correctly
839
 
        self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me')))), """<ul>
840
 
<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
841
 
<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
842
 
<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
843
 
<li><label><input type="checkbox" name="escape" value="bad" /> you &amp; me</label></li>
844
 
<li><label><input type="checkbox" name="escape" value="good" /> you &gt; me</label></li>
845
 
</ul>""")
846
 
 
847
 
        # Test the usage of _has_changed
848
 
        self.assertFalse(w._has_changed(None, None))
849
 
        self.assertFalse(w._has_changed([], None))
850
 
        self.assertTrue(w._has_changed(None, ['1']))
851
 
        self.assertFalse(w._has_changed([1, 2], ['1', '2']))
852
 
        self.assertTrue(w._has_changed([1, 2], ['1']))
853
 
        self.assertTrue(w._has_changed([1, 2], ['1', '3']))
854
 
        self.assertFalse(w._has_changed([2, 1], ['1', '2']))
855
 
 
856
 
        # Unicode choices are correctly rendered as HTML
857
 
        self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>')
858
 
 
859
 
        # Each input gets a separate ID
860
 
        self.assertHTMLEqual(CheckboxSelectMultiple().render('letters', list('ac'), choices=zip(list('abc'), list('ABC')), attrs={'id': 'abc'}), """<ul>
861
 
<li><label for="abc_0"><input checked="checked" type="checkbox" name="letters" value="a" id="abc_0" /> A</label></li>
862
 
<li><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1" /> B</label></li>
863
 
<li><label for="abc_2"><input checked="checked" type="checkbox" name="letters" value="c" id="abc_2" /> C</label></li>
864
 
</ul>""")
865
 
 
866
 
    def test_multi(self):
867
 
        class MyMultiWidget(MultiWidget):
868
 
            def decompress(self, value):
869
 
                if value:
870
 
                    return value.split('__')
871
 
                return ['', '']
872
 
            def format_output(self, rendered_widgets):
873
 
                return '<br />'.join(rendered_widgets)
874
 
 
875
 
        w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
876
 
        self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />')
877
 
        self.assertHTMLEqual(w.render('name', 'john__lennon'), '<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />')
878
 
        self.assertHTMLEqual(w.render('name', 'john__lennon', attrs={'id':'foo'}), '<input id="foo_0" type="text" class="big" value="john" name="name_0" /><br /><input id="foo_1" type="text" class="small" value="lennon" name="name_1" />')
879
 
        w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
880
 
        self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />')
881
 
 
882
 
        w = MyMultiWidget(widgets=(TextInput(), TextInput()))
883
 
 
884
 
        # test with no initial data
885
 
        self.assertTrue(w._has_changed(None, ['john', 'lennon']))
886
 
 
887
 
        # test when the data is the same as initial
888
 
        self.assertFalse(w._has_changed('john__lennon', ['john', 'lennon']))
889
 
 
890
 
        # test when the first widget's data has changed
891
 
        self.assertTrue(w._has_changed('john__lennon', ['alfred', 'lennon']))
892
 
 
893
 
        # test when the last widget's data has changed. this ensures that it is not
894
 
        # short circuiting while testing the widgets.
895
 
        self.assertTrue(w._has_changed('john__lennon', ['john', 'denver']))
896
 
 
897
 
    def test_splitdatetime(self):
898
 
        w = SplitDateTimeWidget()
899
 
        self.assertHTMLEqual(w.render('date', ''), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
900
 
        self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
901
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />')
902
 
        self.assertHTMLEqual(w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)]), '<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />')
903
 
 
904
 
        # You can also pass 'attrs' to the constructor. In this case, the attrs will be
905
 
        w = SplitDateTimeWidget(attrs={'class': 'pretty'})
906
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />')
907
 
 
908
 
        # Use 'date_format' and 'time_format' to change the way a value is displayed.
909
 
        w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M')
910
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" name="date_0" value="10/01/2006" /><input type="text" name="date_1" value="07:30" />')
911
 
 
912
 
        self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['2008-05-06', '12:40:00']))
913
 
        self.assertFalse(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['06/05/2008', '12:40']))
914
 
        self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['06/05/2008', '12:41']))
915
 
 
916
 
    def test_datetimeinput(self):
917
 
        w = DateTimeInput()
918
 
        self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date" />')
919
 
        d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
920
 
        self.assertEqual(str(d), '2007-09-17 12:51:34.482548')
921
 
 
922
 
        # The microseconds are trimmed on display, by default.
923
 
        self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="2007-09-17 12:51:34" />')
924
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '<input type="text" name="date" value="2007-09-17 12:51:34" />')
925
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="text" name="date" value="2007-09-17 12:51:00" />')
926
 
 
927
 
        # Use 'format' to change the way a value is displayed.
928
 
        w = DateTimeInput(format='%d/%m/%Y %H:%M', attrs={'type': 'datetime'})
929
 
        self.assertHTMLEqual(w.render('date', d), '<input type="datetime" name="date" value="17/09/2007 12:51" />')
930
 
        self.assertFalse(w._has_changed(d, '17/09/2007 12:51'))
931
 
 
932
 
        # Make sure a custom format works with _has_changed. The hidden input will use
933
 
        data = datetime.datetime(2010, 3, 6, 12, 0, 0)
934
 
        custom_format = '%d.%m.%Y %H:%M'
935
 
        w = DateTimeInput(format=custom_format)
936
 
        self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format)))
937
 
 
938
 
    def test_dateinput(self):
939
 
        w = DateInput()
940
 
        self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date" />')
941
 
        d = datetime.date(2007, 9, 17)
942
 
        self.assertEqual(str(d), '2007-09-17')
943
 
 
944
 
        self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="2007-09-17" />')
945
 
        self.assertHTMLEqual(w.render('date', datetime.date(2007, 9, 17)), '<input type="text" name="date" value="2007-09-17" />')
946
 
 
947
 
        # We should be able to initialize from a unicode value.
948
 
        self.assertHTMLEqual(w.render('date', '2007-09-17'), '<input type="text" name="date" value="2007-09-17" />')
949
 
 
950
 
        # Use 'format' to change the way a value is displayed.
951
 
        w = DateInput(format='%d/%m/%Y', attrs={'type': 'date'})
952
 
        self.assertHTMLEqual(w.render('date', d), '<input type="date" name="date" value="17/09/2007" />')
953
 
        self.assertFalse(w._has_changed(d, '17/09/2007'))
954
 
 
955
 
        # Make sure a custom format works with _has_changed. The hidden input will use
956
 
        data = datetime.date(2010, 3, 6)
957
 
        custom_format = '%d.%m.%Y'
958
 
        w = DateInput(format=custom_format)
959
 
        self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format)))
960
 
 
961
 
    def test_timeinput(self):
962
 
        w = TimeInput()
963
 
        self.assertHTMLEqual(w.render('time', None), '<input type="text" name="time" />')
964
 
        t = datetime.time(12, 51, 34, 482548)
965
 
        self.assertEqual(str(t), '12:51:34.482548')
966
 
 
967
 
        # The microseconds are trimmed on display, by default.
968
 
        self.assertHTMLEqual(w.render('time', t), '<input type="text" name="time" value="12:51:34" />')
969
 
        self.assertHTMLEqual(w.render('time', datetime.time(12, 51, 34)), '<input type="text" name="time" value="12:51:34" />')
970
 
        self.assertHTMLEqual(w.render('time', datetime.time(12, 51)), '<input type="text" name="time" value="12:51:00" />')
971
 
 
972
 
        # We should be able to initialize from a unicode value.
973
 
        self.assertHTMLEqual(w.render('time', '13:12:11'), '<input type="text" name="time" value="13:12:11" />')
974
 
 
975
 
        # Use 'format' to change the way a value is displayed.
976
 
        w = TimeInput(format='%H:%M', attrs={'type': 'time'})
977
 
        self.assertHTMLEqual(w.render('time', t), '<input type="time" name="time" value="12:51" />')
978
 
        self.assertFalse(w._has_changed(t, '12:51'))
979
 
 
980
 
        # Make sure a custom format works with _has_changed. The hidden input will use
981
 
        data = datetime.time(13, 0)
982
 
        custom_format = '%I:%M %p'
983
 
        w = TimeInput(format=custom_format)
984
 
        self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format)))
985
 
 
986
 
    def test_splithiddendatetime(self):
987
 
        from django.forms.widgets import SplitHiddenDateTimeWidget
988
 
 
989
 
        w = SplitHiddenDateTimeWidget()
990
 
        self.assertHTMLEqual(w.render('date', ''), '<input type="hidden" name="date_0" /><input type="hidden" name="date_1" />')
991
 
        d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
992
 
        self.assertHTMLEqual(str(d), '2007-09-17 12:51:34.482548')
993
 
        self.assertHTMLEqual(w.render('date', d), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />')
994
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />')
995
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />')
996
 
 
997
 
 
998
 
class NullBooleanSelectLazyForm(Form):
999
 
    """Form to test for lazy evaluation. Refs #17190"""
1000
 
    bool = BooleanField(widget=NullBooleanSelect())
1001
 
 
1002
 
@override_settings(USE_L10N=True)
1003
 
class FormsI18NWidgetsTestCase(TestCase):
1004
 
    def setUp(self):
1005
 
        super(FormsI18NWidgetsTestCase, self).setUp()
1006
 
        activate('de-at')
1007
 
 
1008
 
    def tearDown(self):
1009
 
        deactivate()
1010
 
        super(FormsI18NWidgetsTestCase, self).tearDown()
1011
 
 
1012
 
    def test_splitdatetime(self):
1013
 
        w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M')
1014
 
        self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), ['06.05.2008', '12:41']))
1015
 
 
1016
 
    def test_datetimeinput(self):
1017
 
        w = DateTimeInput()
1018
 
        d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
1019
 
        w.is_localized = True
1020
 
        self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="17.09.2007 12:51:34" />')
1021
 
 
1022
 
    def test_dateinput(self):
1023
 
        w = DateInput()
1024
 
        d = datetime.date(2007, 9, 17)
1025
 
        w.is_localized = True
1026
 
        self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="17.09.2007" />')
1027
 
 
1028
 
    def test_timeinput(self):
1029
 
        w = TimeInput()
1030
 
        t = datetime.time(12, 51, 34, 482548)
1031
 
        w.is_localized = True
1032
 
        self.assertHTMLEqual(w.render('time', t), '<input type="text" name="time" value="12:51:34" />')
1033
 
 
1034
 
    def test_splithiddendatetime(self):
1035
 
        from django.forms.widgets import SplitHiddenDateTimeWidget
1036
 
 
1037
 
        w = SplitHiddenDateTimeWidget()
1038
 
        w.is_localized = True
1039
 
        self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="hidden" name="date_0" value="17.09.2007" /><input type="hidden" name="date_1" value="12:51:00" />')
1040
 
 
1041
 
    def test_nullbooleanselect(self):
1042
 
        """
1043
 
        Ensure that the NullBooleanSelect widget's options are lazily
1044
 
        localized.
1045
 
        Refs #17190
1046
 
        """
1047
 
        f = NullBooleanSelectLazyForm()
1048
 
        self.assertHTMLEqual(f.fields['bool'].widget.render('id_bool', True), '<select name="id_bool">\n<option value="1">Unbekannt</option>\n<option value="2" selected="selected">Ja</option>\n<option value="3">Nein</option>\n</select>')
1049
 
 
1050
 
 
1051
 
class SelectAndTextWidget(MultiWidget):
1052
 
    """
1053
 
    MultiWidget subclass
1054
 
    """
1055
 
    def __init__(self, choices=[]):
1056
 
        widgets = [
1057
 
            RadioSelect(choices=choices),
1058
 
            TextInput
1059
 
        ]
1060
 
        super(SelectAndTextWidget, self).__init__(widgets)
1061
 
 
1062
 
    def _set_choices(self, choices):
1063
 
        """
1064
 
        When choices are set for this widget, we want to pass those along to the Select widget
1065
 
        """
1066
 
        self.widgets[0].choices = choices
1067
 
    def _get_choices(self):
1068
 
        """
1069
 
        The choices for this widget are the Select widget's choices
1070
 
        """
1071
 
        return self.widgets[0].choices
1072
 
    choices = property(_get_choices, _set_choices)
1073
 
 
1074
 
 
1075
 
class WidgetTests(TestCase):
1076
 
    def test_12048(self):
1077
 
        # See ticket #12048.
1078
 
        w1 = SelectAndTextWidget(choices=[1,2,3])
1079
 
        w2 = copy.deepcopy(w1)
1080
 
        w2.choices = [4,5,6]
1081
 
        # w2 ought to be independent of w1, since MultiWidget ought
1082
 
        # to make a copy of its sub-widgets when it is copied.
1083
 
        self.assertEqual(w1.choices, [1,2,3])
1084
 
 
1085
 
    def test_13390(self):
1086
 
        # See ticket #13390
1087
 
        class SplitDateForm(Form):
1088
 
            field = DateTimeField(widget=SplitDateTimeWidget, required=False)
1089
 
 
1090
 
        form = SplitDateForm({'field': ''})
1091
 
        self.assertTrue(form.is_valid())
1092
 
        form = SplitDateForm({'field': ['', '']})
1093
 
        self.assertTrue(form.is_valid())
1094
 
 
1095
 
        class SplitDateRequiredForm(Form):
1096
 
            field = DateTimeField(widget=SplitDateTimeWidget, required=True)
1097
 
 
1098
 
        form = SplitDateRequiredForm({'field': ''})
1099
 
        self.assertFalse(form.is_valid())
1100
 
        form = SplitDateRequiredForm({'field': ['', '']})
1101
 
        self.assertFalse(form.is_valid())
1102
 
 
1103
 
 
1104
 
class LiveWidgetTests(AdminSeleniumWebDriverTestCase):
1105
 
    urls = 'regressiontests.forms.urls'
1106
 
 
1107
 
    def test_textarea_trailing_newlines(self):
1108
 
        """
1109
 
        Test that a roundtrip on a ModelForm doesn't alter the TextField value
1110
 
        """
1111
 
        article = Article.objects.create(content="\nTst\n")
1112
 
        self.selenium.get('%s%s' % (self.live_server_url,
1113
 
            reverse('article_form', args=[article.pk])))
1114
 
        self.selenium.find_element_by_id('submit').submit()
1115
 
        article = Article.objects.get(pk=article.pk)
1116
 
        # Should be "\nTst\n" after #19251 is fixed
1117
 
        self.assertEqual(article.content, "\r\nTst\r\n")
1118
 
 
1119
 
 
1120
 
@python_2_unicode_compatible
1121
 
class FakeFieldFile(object):
1122
 
    """
1123
 
    Quacks like a FieldFile (has a .url and unicode representation), but
1124
 
    doesn't require us to care about storages etc.
1125
 
 
1126
 
    """
1127
 
    url = 'something'
1128
 
 
1129
 
    def __str__(self):
1130
 
        return self.url
1131
 
 
1132
 
class ClearableFileInputTests(TestCase):
1133
 
    def test_clear_input_renders(self):
1134
 
        """
1135
 
        A ClearableFileInput with is_required False and rendered with
1136
 
        an initial value that is a file renders a clear checkbox.
1137
 
 
1138
 
        """
1139
 
        widget = ClearableFileInput()
1140
 
        widget.is_required = False
1141
 
        self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()),
1142
 
                         'Currently: <a href="something">something</a> <input type="checkbox" name="myfile-clear" id="myfile-clear_id" /> <label for="myfile-clear_id">Clear</label><br />Change: <input type="file" name="myfile" />')
1143
 
 
1144
 
    def test_html_escaped(self):
1145
 
        """
1146
 
        A ClearableFileInput should escape name, filename and URL when
1147
 
        rendering HTML. Refs #15182.
1148
 
        """
1149
 
 
1150
 
        @python_2_unicode_compatible
1151
 
        class StrangeFieldFile(object):
1152
 
            url = "something?chapter=1&sect=2&copy=3&lang=en"
1153
 
 
1154
 
            def __str__(self):
1155
 
                return '''something<div onclick="alert('oops')">.jpg'''
1156
 
 
1157
 
        widget = ClearableFileInput()
1158
 
        field = StrangeFieldFile()
1159
 
        output = widget.render('my<div>file', field)
1160
 
        self.assertFalse(field.url in output)
1161
 
        self.assertTrue('href="something?chapter=1&amp;sect=2&amp;copy=3&amp;lang=en"' in output)
1162
 
        self.assertFalse(six.text_type(field) in output)
1163
 
        self.assertTrue('something&lt;div onclick=&quot;alert(&#39;oops&#39;)&quot;&gt;.jpg' in output)
1164
 
        self.assertTrue('my&lt;div&gt;file' in output)
1165
 
        self.assertFalse('my<div>file' in output)
1166
 
 
1167
 
    def test_clear_input_renders_only_if_not_required(self):
1168
 
        """
1169
 
        A ClearableFileInput with is_required=False does not render a clear
1170
 
        checkbox.
1171
 
 
1172
 
        """
1173
 
        widget = ClearableFileInput()
1174
 
        widget.is_required = True
1175
 
        self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()),
1176
 
                         'Currently: <a href="something">something</a> <br />Change: <input type="file" name="myfile" />')
1177
 
 
1178
 
    def test_clear_input_renders_only_if_initial(self):
1179
 
        """
1180
 
        A ClearableFileInput instantiated with no initial value does not render
1181
 
        a clear checkbox.
1182
 
 
1183
 
        """
1184
 
        widget = ClearableFileInput()
1185
 
        widget.is_required = False
1186
 
        self.assertHTMLEqual(widget.render('myfile', None),
1187
 
                         '<input type="file" name="myfile" />')
1188
 
 
1189
 
    def test_clear_input_checked_returns_false(self):
1190
 
        """
1191
 
        ClearableFileInput.value_from_datadict returns False if the clear
1192
 
        checkbox is checked, if not required.
1193
 
 
1194
 
        """
1195
 
        widget = ClearableFileInput()
1196
 
        widget.is_required = False
1197
 
        self.assertEqual(widget.value_from_datadict(
1198
 
                data={'myfile-clear': True},
1199
 
                files={},
1200
 
                name='myfile'), False)
1201
 
 
1202
 
    def test_clear_input_checked_returns_false_only_if_not_required(self):
1203
 
        """
1204
 
        ClearableFileInput.value_from_datadict never returns False if the field
1205
 
        is required.
1206
 
 
1207
 
        """
1208
 
        widget = ClearableFileInput()
1209
 
        widget.is_required = True
1210
 
        f = SimpleUploadedFile('something.txt', b'content')
1211
 
        self.assertEqual(widget.value_from_datadict(
1212
 
                data={'myfile-clear': True},
1213
 
                files={'myfile': f},
1214
 
                name='myfile'), f)