# -*- coding: utf-8 -*- import datetime from decimal import Decimal import re import time from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.forms import * from django.forms.widgets import RadioFieldRenderer from django.utils import copycompat as copy from django.utils import formats from django.utils.safestring import mark_safe from django.utils.translation import activate, deactivate from django.utils.unittest import TestCase class FormsWidgetTestCase(TestCase): # Each Widget class corresponds to an HTML form widget. A Widget knows how to # render itself, given a field name and some data. Widgets don't perform # validation. def test_textinput(self): w = TextInput() self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', 'test@example.com'), u'') self.assertEqual(w.render('email', 'some "quoted" & ampersanded value'), u'') self.assertEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), u'') # Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii # characters in output, so we're displaying the repr() here. self.assertEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), u'') # You can also pass 'attrs' to the constructor: w = TextInput(attrs={'class': 'fun'}) self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', 'foo@example.com'), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = TextInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('email', '', attrs={'class': 'special'}), u'') # 'attrs' can be safe-strings if needed) w = TextInput(attrs={'onBlur': mark_safe("function('foo')")}) self.assertEqual(w.render('email', ''), u'') def test_passwordinput(self): w = PasswordInput() self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', 'secret'), u'') # The render_value argument lets you specify whether the widget should render # its value. For security reasons, this is off by default. w = PasswordInput(render_value=True) self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', 'test@example.com'), u'') self.assertEqual(w.render('email', 'some "quoted" & ampersanded value'), u'') self.assertEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), u'') # You can also pass 'attrs' to the constructor: w = PasswordInput(attrs={'class': 'fun'}, render_value=True) self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', 'foo@example.com'), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = PasswordInput(attrs={'class': 'pretty'}, render_value=True) self.assertEqual(w.render('email', '', attrs={'class': 'special'}), u'') self.assertEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), u'') def test_hiddeninput(self): w = HiddenInput() self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', 'test@example.com'), u'') self.assertEqual(w.render('email', 'some "quoted" & ampersanded value'), u'') self.assertEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), u'') # You can also pass 'attrs' to the constructor: w = HiddenInput(attrs={'class': 'fun'}) self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', 'foo@example.com'), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = HiddenInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('email', '', attrs={'class': 'special'}), u'') self.assertEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = HiddenInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('email', '', attrs={'class': 'special'}), u'') # Boolean values are rendered to their string forms ("True" and "False"). w = HiddenInput() self.assertEqual(w.render('get_spam', False), u'') self.assertEqual(w.render('get_spam', True), u'') def test_multiplehiddeninput(self): w = MultipleHiddenInput() self.assertEqual(w.render('email', []), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', ['test@example.com']), u'') self.assertEqual(w.render('email', ['some "quoted" & ampersanded value']), u'') self.assertEqual(w.render('email', ['test@example.com', 'foo@example.com']), u'\n') self.assertEqual(w.render('email', ['test@example.com'], attrs={'class': 'fun'}), u'') self.assertEqual(w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}), u'\n') # You can also pass 'attrs' to the constructor: w = MultipleHiddenInput(attrs={'class': 'fun'}) self.assertEqual(w.render('email', []), u'') self.assertEqual(w.render('email', ['foo@example.com']), u'') self.assertEqual(w.render('email', ['foo@example.com', 'test@example.com']), u'\n') # 'attrs' passed to render() get precedence over those passed to the constructor: w = MultipleHiddenInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), u'') self.assertEqual(w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = MultipleHiddenInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), u'') # Each input gets a separate ID. w = MultipleHiddenInput() self.assertEqual(w.render('letters', list('abc'), attrs={'id': 'hideme'}), u'\n\n') def test_fileinput(self): # FileInput widgets don't ever show the value, because the old value is of no use # if you are updating the form or if the provided file generated an error. w = FileInput() self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', None), u'') self.assertEqual(w.render('email', 'test@example.com'), u'') self.assertEqual(w.render('email', 'some "quoted" & ampersanded value'), u'') self.assertEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), u'') # You can also pass 'attrs' to the constructor: w = FileInput(attrs={'class': 'fun'}) self.assertEqual(w.render('email', ''), u'') self.assertEqual(w.render('email', 'foo@example.com'), u'') self.assertEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), u'') # Test for the behavior of _has_changed for FileInput. The value of data will # more than likely come from request.FILES. The value of initial data will # likely be a filename stored in the database. Since its value is of no use to # a FileInput it is ignored. w = FileInput() # No file was uploaded and no initial data. self.assertFalse(w._has_changed(u'', None)) # A file was uploaded and no initial data. self.assertTrue(w._has_changed(u'', {'filename': 'resume.txt', 'content': 'My resume'})) # A file was not uploaded, but there is initial data self.assertFalse(w._has_changed(u'resume.txt', None)) # A file was uploaded and there is initial data (file identity is not dealt # with here) self.assertTrue(w._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'})) def test_textarea(self): w = Textarea() self.assertEqual(w.render('msg', ''), u'') self.assertEqual(w.render('msg', None), u'') self.assertEqual(w.render('msg', 'value'), u'') self.assertEqual(w.render('msg', 'some "quoted" & ampersanded value'), u'') self.assertEqual(w.render('msg', mark_safe('pre "quoted" value')), u'') self.assertEqual(w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}), u'') # You can also pass 'attrs' to the constructor: w = Textarea(attrs={'class': 'pretty'}) self.assertEqual(w.render('msg', ''), u'') self.assertEqual(w.render('msg', 'example'), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = Textarea(attrs={'class': 'pretty'}) self.assertEqual(w.render('msg', '', attrs={'class': 'special'}), u'') self.assertEqual(w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), u'') def test_checkboxinput(self): w = CheckboxInput() self.assertEqual(w.render('is_cool', ''), u'') self.assertEqual(w.render('is_cool', None), u'') self.assertEqual(w.render('is_cool', False), u'') self.assertEqual(w.render('is_cool', True), u'') # Using any value that's not in ('', None, False, True) will check the checkbox # and set the 'value' attribute. self.assertEqual(w.render('is_cool', 'foo'), u'') self.assertEqual(w.render('is_cool', False, attrs={'class': 'pretty'}), u'') # You can also pass 'attrs' to the constructor: w = CheckboxInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('is_cool', ''), u'') # 'attrs' passed to render() get precedence over those passed to the constructor: w = CheckboxInput(attrs={'class': 'pretty'}) self.assertEqual(w.render('is_cool', '', attrs={'class': 'special'}), u'') # You can pass 'check_test' to the constructor. This is a callable that takes the # value and returns True if the box should be checked. w = CheckboxInput(check_test=lambda value: value.startswith('hello')) self.assertEqual(w.render('greeting', ''), u'') self.assertEqual(w.render('greeting', 'hello'), u'') self.assertEqual(w.render('greeting', 'hello there'), u'') self.assertEqual(w.render('greeting', 'hello & goodbye'), u'') # A subtlety: If the 'check_test' argument cannot handle a value and raises any # exception during its __call__, then the exception will be swallowed and the box # will not be checked. In this example, the 'check_test' assumes the value has a # startswith() method, which fails for the values True, False and None. self.assertEqual(w.render('greeting', True), u'') self.assertEqual(w.render('greeting', False), u'') self.assertEqual(w.render('greeting', None), u'') # The CheckboxInput widget will return False if the key is not found in the data # dictionary (because HTML form submission doesn't send any result for unchecked # checkboxes). self.assertFalse(w.value_from_datadict({}, {}, 'testing')) self.assertFalse(w._has_changed(None, None)) self.assertFalse(w._has_changed(None, u'')) self.assertFalse(w._has_changed(u'', None)) self.assertFalse(w._has_changed(u'', u'')) self.assertTrue(w._has_changed(False, u'on')) self.assertFalse(w._has_changed(True, u'on')) self.assertTrue(w._has_changed(True, u'')) def test_select(self): w = Select() self.assertEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: from itertools import chain def get_choices(): for i in range(5): yield (i, i) self.assertEqual(w.render('num', 2, choices=get_choices()), """""") things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'}) class SomeForm(Form): somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things])) f = SomeForm() self.assertEqual(f.as_table(), u'') self.assertEqual(f.as_table(), u'') f = SomeForm({'somechoice': 2}) self.assertEqual(f.as_table(), u'') # You can also pass 'choices' to the constructor: w = Select(choices=[(1, 1), (2, 2), (3, 3)]) self.assertEqual(w.render('num', 2), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML self.assertEqual(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), u'') # If choices is passed to the constructor and is a generator, it can be iterated # over multiple times without getting consumed: w = Select(choices=get_choices()) self.assertEqual(w.render('num', 2), """""") self.assertEqual(w.render('num', 3), """""") # Choices can be nested one level in order to create HTML optgroups: w.choices=(('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))) self.assertEqual(w.render('nestchoice', None), """""") self.assertEqual(w.render('nestchoice', 'outer1'), """""") self.assertEqual(w.render('nestchoice', 'inner1'), """""") def test_nullbooleanselect(self): w = NullBooleanSelect() self.assertTrue(w.render('is_cool', True), """""") self.assertEqual(w.render('is_cool', False), """""") self.assertEqual(w.render('is_cool', None), """""") self.assertEqual(w.render('is_cool', '2'), """""") self.assertEqual(w.render('is_cool', '3'), """""") self.assertTrue(w._has_changed(False, None)) self.assertTrue(w._has_changed(None, False)) self.assertFalse(w._has_changed(None, None)) self.assertFalse(w._has_changed(False, False)) self.assertTrue(w._has_changed(True, False)) self.assertTrue(w._has_changed(True, None)) self.assertTrue(w._has_changed(True, False)) def test_selectmultiple(self): w = SelectMultiple() self.assertEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If multiple values are given, but some of them are not valid, the valid ones are selected: self.assertEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertEqual(w.render('nums', [2], choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) self.assertEqual(w.render('nums', [2]), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML self.assertEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), u'') # Test the usage of _has_changed self.assertFalse(w._has_changed(None, None)) self.assertFalse(w._has_changed([], None)) self.assertTrue(w._has_changed(None, [u'1'])) self.assertFalse(w._has_changed([1, 2], [u'1', u'2'])) self.assertTrue(w._has_changed([1, 2], [u'1'])) self.assertTrue(w._has_changed([1, 2], [u'1', u'3'])) # Choices can be nested one level in order to create HTML optgroups: w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))) self.assertEqual(w.render('nestchoice', None), """""") self.assertEqual(w.render('nestchoice', ['outer1']), """""") self.assertEqual(w.render('nestchoice', ['inner1']), """""") self.assertEqual(w.render('nestchoice', ['outer1', 'inner2']), """""") def test_radioselect(self): w = RadioSelect() self.assertEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are checked: self.assertEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are checked: self.assertEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertEqual(w.render('num', 2, choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)]) self.assertEqual(w.render('num', 2), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """""") # RadioSelect uses a RadioFieldRenderer to render the individual radio inputs. # You can manipulate that object directly to customize the way the RadioSelect # is rendered. w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) inp_set1 = [] inp_set2 = [] inp_set3 = [] inp_set4 = [] for inp in r: inp_set1.append(str(inp)) inp_set2.append('%s
' % inp) inp_set3.append('

%s %s

' % (inp.tag(), inp.choice_label)) inp_set4.append('%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())) self.assertEqual('\n'.join(inp_set1), """ """) self.assertEqual('\n'.join(inp_set2), """



""") self.assertEqual('\n'.join(inp_set3), """

John

Paul

George

Ringo

""") self.assertEqual('\n'.join(inp_set4), """beatle J J John True beatle J P Paul False beatle J G George False beatle J R Ringo False""") # You can create your own custom renderers for RadioSelect to use. class MyRenderer(RadioFieldRenderer): def render(self): return u'
\n'.join([unicode(choice) for choice in self]) w = RadioSelect(renderer=MyRenderer) self.assertEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""") # Or you can use custom RadioSelect fields that use your custom renderer. class CustomRadioSelect(RadioSelect): renderer = MyRenderer w = CustomRadioSelect() self.assertEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """


""") # A RadioFieldRenderer object also allows index access to individual RadioInput w = RadioSelect() r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) self.assertEqual(str(r[1]), '') self.assertEqual(str(r[0]), '') self.assertTrue(r[0].is_checked()) self.assertFalse(r[1].is_checked()) self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', u'J', u'P', u'Paul')) try: r[10] self.fail("This offset should not exist.") except IndexError: pass # Choices are escaped correctly w = RadioSelect() self.assertEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Unicode choices are correctly rendered as HTML w = RadioSelect() self.assertEqual(unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), u'') # Attributes provided at instantiation are passed to the constituent inputs w = RadioSelect(attrs={'id':'foo'}) self.assertEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # Attributes provided at render-time are passed to the constituent inputs w = RadioSelect() self.assertEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """""") def test_checkboxselectmultiple(self): w = CheckboxSelectMultiple() self.assertEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") self.assertEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value is None, none of the options are selected: self.assertEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If the value corresponds to a label (but not to an option value), none of the options are selected: self.assertEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # If multiple values are given, but some of them are not valid, the valid ones are selected: self.assertEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """""") # The value is compared to its str(): self.assertEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """""") self.assertEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """""") self.assertEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """""") # The 'choices' argument can be any iterable: def get_choices(): for i in range(5): yield (i, i) self.assertEqual(w.render('nums', [2], choices=get_choices()), """""") # You can also pass 'choices' to the constructor: w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) self.assertEqual(w.render('nums', [2]), """""") # If 'choices' is passed to both the constructor and render(), then they'll both be in the output: self.assertEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """""") # Choices are escaped correctly self.assertEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """""") # Test the usage of _has_changed self.assertFalse(w._has_changed(None, None)) self.assertFalse(w._has_changed([], None)) self.assertTrue(w._has_changed(None, [u'1'])) self.assertFalse(w._has_changed([1, 2], [u'1', u'2'])) self.assertTrue(w._has_changed([1, 2], [u'1'])) self.assertTrue(w._has_changed([1, 2], [u'1', u'3'])) self.assertFalse(w._has_changed([2, 1], [u'1', u'2'])) # Unicode choices are correctly rendered as HTML self.assertEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), u'') # Each input gets a separate ID self.assertEqual(CheckboxSelectMultiple().render('letters', list('ac'), choices=zip(list('abc'), list('ABC')), attrs={'id': 'abc'}), """""") def test_multi(self): class MyMultiWidget(MultiWidget): def decompress(self, value): if value: return value.split('__') return ['', ''] def format_output(self, rendered_widgets): return u'
'.join(rendered_widgets) w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'}))) self.assertEqual(w.render('name', ['john', 'lennon']), u'
') self.assertEqual(w.render('name', 'john__lennon'), u'
') self.assertEqual(w.render('name', 'john__lennon', attrs={'id':'foo'}), u'
') w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'}) self.assertEqual(w.render('name', ['john', 'lennon']), u'
') w = MyMultiWidget(widgets=(TextInput(), TextInput())) # test with no initial data self.assertTrue(w._has_changed(None, [u'john', u'lennon'])) # test when the data is the same as initial self.assertFalse(w._has_changed(u'john__lennon', [u'john', u'lennon'])) # test when the first widget's data has changed self.assertTrue(w._has_changed(u'john__lennon', [u'alfred', u'lennon'])) # test when the last widget's data has changed. this ensures that it is not # short circuiting while testing the widgets. self.assertTrue(w._has_changed(u'john__lennon', [u'john', u'denver'])) def test_splitdatetime(self): w = SplitDateTimeWidget() self.assertEqual(w.render('date', ''), u'') self.assertEqual(w.render('date', None), u'') self.assertEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), u'') self.assertEqual(w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)]), u'') # You can also pass 'attrs' to the constructor. In this case, the attrs will be w = SplitDateTimeWidget(attrs={'class': 'pretty'}) self.assertEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), u'') # Use 'date_format' and 'time_format' to change the way a value is displayed. w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M') self.assertEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), u'') self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'2008-05-06', u'12:40:00'])) self.assertFalse(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06/05/2008', u'12:40'])) self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06/05/2008', u'12:41'])) def test_datetimeinput(self): w = DateTimeInput() self.assertEqual(w.render('date', None), u'') d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) self.assertEqual(str(d), '2007-09-17 12:51:34.482548') # The microseconds are trimmed on display, by default. self.assertEqual(w.render('date', d), u'') self.assertEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), u'') self.assertEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), u'') # Use 'format' to change the way a value is displayed. w = DateTimeInput(format='%d/%m/%Y %H:%M') self.assertEqual(w.render('date', d), u'') self.assertFalse(w._has_changed(d, '17/09/2007 12:51')) # Make sure a custom format works with _has_changed. The hidden input will use data = datetime.datetime(2010, 3, 6, 12, 0, 0) custom_format = '%d.%m.%Y %H:%M' w = DateTimeInput(format=custom_format) self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format))) def test_dateinput(self): w = DateInput() self.assertEqual(w.render('date', None), u'') d = datetime.date(2007, 9, 17) self.assertEqual(str(d), '2007-09-17') self.assertEqual(w.render('date', d), u'') self.assertEqual(w.render('date', datetime.date(2007, 9, 17)), u'') # We should be able to initialize from a unicode value. self.assertEqual(w.render('date', u'2007-09-17'), u'') # Use 'format' to change the way a value is displayed. w = DateInput(format='%d/%m/%Y') self.assertEqual(w.render('date', d), u'') self.assertFalse(w._has_changed(d, '17/09/2007')) # Make sure a custom format works with _has_changed. The hidden input will use data = datetime.date(2010, 3, 6) custom_format = '%d.%m.%Y' w = DateInput(format=custom_format) self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format))) def test_timeinput(self): w = TimeInput() self.assertEqual(w.render('time', None), u'') t = datetime.time(12, 51, 34, 482548) self.assertEqual(str(t), '12:51:34.482548') # The microseconds are trimmed on display, by default. self.assertEqual(w.render('time', t), u'') self.assertEqual(w.render('time', datetime.time(12, 51, 34)), u'') self.assertEqual(w.render('time', datetime.time(12, 51)), u'') # We should be able to initialize from a unicode value. self.assertEqual(w.render('time', u'13:12:11'), u'') # Use 'format' to change the way a value is displayed. w = TimeInput(format='%H:%M') self.assertEqual(w.render('time', t), u'') self.assertFalse(w._has_changed(t, '12:51')) # Make sure a custom format works with _has_changed. The hidden input will use data = datetime.time(13, 0) custom_format = '%I:%M %p' w = TimeInput(format=custom_format) self.assertFalse(w._has_changed(formats.localize_input(data), data.strftime(custom_format))) def test_splithiddendatetime(self): from django.forms.widgets import SplitHiddenDateTimeWidget w = SplitHiddenDateTimeWidget() self.assertEqual(w.render('date', ''), u'') d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) self.assertEqual(str(d), '2007-09-17 12:51:34.482548') self.assertEqual(w.render('date', d), u'') self.assertEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), u'') self.assertEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), u'') class FormsI18NWidgetsTestCase(TestCase): def setUp(self): super(FormsI18NWidgetsTestCase, self).setUp() self.old_use_l10n = getattr(settings, 'USE_L10N', False) settings.USE_L10N = True activate('de-at') def tearDown(self): deactivate() settings.USE_L10N = self.old_use_l10n super(FormsI18NWidgetsTestCase, self).tearDown() def test_splitdatetime(self): w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M') self.assertTrue(w._has_changed(datetime.datetime(2008, 5, 6, 12, 40, 00), [u'06.05.2008', u'12:41'])) def test_datetimeinput(self): w = DateTimeInput() d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548) w.is_localized = True self.assertEqual(w.render('date', d), u'') def test_dateinput(self): w = DateInput() d = datetime.date(2007, 9, 17) w.is_localized = True self.assertEqual(w.render('date', d), u'') def test_timeinput(self): w = TimeInput() t = datetime.time(12, 51, 34, 482548) w.is_localized = True self.assertEqual(w.render('time', t), u'') def test_splithiddendatetime(self): from django.forms.widgets import SplitHiddenDateTimeWidget w = SplitHiddenDateTimeWidget() w.is_localized = True self.assertEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), u'') class SelectAndTextWidget(MultiWidget): """ MultiWidget subclass """ def __init__(self, choices=[]): widgets = [ RadioSelect(choices=choices), TextInput ] super(SelectAndTextWidget, self).__init__(widgets) def _set_choices(self, choices): """ When choices are set for this widget, we want to pass those along to the Select widget """ self.widgets[0].choices = choices def _get_choices(self): """ The choices for this widget are the Select widget's choices """ return self.widgets[0].choices choices = property(_get_choices, _set_choices) class WidgetTests(TestCase): def test_12048(self): # See ticket #12048. w1 = SelectAndTextWidget(choices=[1,2,3]) w2 = copy.deepcopy(w1) w2.choices = [4,5,6] # w2 ought to be independent of w1, since MultiWidget ought # to make a copy of its sub-widgets when it is copied. self.assertEqual(w1.choices, [1,2,3]) def test_13390(self): # See ticket #13390 class SplitDateForm(Form): field = DateTimeField(widget=SplitDateTimeWidget, required=False) form = SplitDateForm({'field': ''}) self.assertTrue(form.is_valid()) form = SplitDateForm({'field': ['', '']}) self.assertTrue(form.is_valid()) class SplitDateRequiredForm(Form): field = DateTimeField(widget=SplitDateTimeWidget, required=True) form = SplitDateRequiredForm({'field': ''}) self.assertFalse(form.is_valid()) form = SplitDateRequiredForm({'field': ['', '']}) self.assertFalse(form.is_valid()) class FakeFieldFile(object): """ Quacks like a FieldFile (has a .url and unicode representation), but doesn't require us to care about storages etc. """ url = 'something' def __unicode__(self): return self.url class ClearableFileInputTests(TestCase): def test_clear_input_renders(self): """ A ClearableFileInput with is_required False and rendered with an initial value that is a file renders a clear checkbox. """ widget = ClearableFileInput() widget.is_required = False self.assertEqual(widget.render('myfile', FakeFieldFile()), u'Currently: something
Change: ') def test_clear_input_renders_only_if_not_required(self): """ A ClearableFileInput with is_required=False does not render a clear checkbox. """ widget = ClearableFileInput() widget.is_required = True self.assertEqual(widget.render('myfile', FakeFieldFile()), u'Currently: something
Change: ') def test_clear_input_renders_only_if_initial(self): """ A ClearableFileInput instantiated with no initial value does not render a clear checkbox. """ widget = ClearableFileInput() widget.is_required = False self.assertEqual(widget.render('myfile', None), u'') def test_clear_input_checked_returns_false(self): """ ClearableFileInput.value_from_datadict returns False if the clear checkbox is checked, if not required. """ widget = ClearableFileInput() widget.is_required = False self.assertEqual(widget.value_from_datadict( data={'myfile-clear': True}, files={}, name='myfile'), False) def test_clear_input_checked_returns_false_only_if_not_required(self): """ ClearableFileInput.value_from_datadict never returns False if the field is required. """ widget = ClearableFileInput() widget.is_required = True f = SimpleUploadedFile('something.txt', 'content') self.assertEqual(widget.value_from_datadict( data={'myfile-clear': True}, files={'myfile': f}, name='myfile'), f)