source: main/waeup.sirp/branches/ulif-fasttables/src/waeup/sirp/jambtables/tests/test_dictwidget.py @ 5274

Last change on this file since 5274 was 5274, checked in by uli, 14 years ago

Add a dict widget. This is not in a very usable state, as it does not preserve order of fields and can't, because dicts have no order.

File size: 18.9 KB
Line 
1##
2## test_dictwidget.py
3## Login : <uli@pu.smp.net>
4## Started on  Sun Jul 18 15:47:58 2010 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2010 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""Dict Field Widget tests.
23"""
24import unittest
25from zope.interface import Interface, implements
26from zope.schema import Tuple, List, TextLine, Dict
27from zope.schema.interfaces import ITextLine
28from zope.component import provideAdapter
29from zope.publisher.browser import TestRequest
30from zope.publisher.interfaces.browser import IDefaultBrowserLayer
31import doctest
32
33from zope.formlib.widgets import TextWidget, ObjectWidget, DisplayWidget
34from zope.formlib.widgets import TupleSequenceWidget, ListSequenceWidget
35from zope.formlib.widgets import SequenceDisplayWidget
36from zope.formlib.widgets import SequenceWidget
37from zope.formlib.interfaces import IDisplayWidget
38from zope.formlib.interfaces import IInputWidget, MissingInputError
39from zope.formlib.interfaces import IWidgetInputError, WidgetInputError
40from zope.formlib.interfaces import IWidgetInputErrorView
41from zope.formlib.widget import CustomWidgetFactory
42from zope.formlib.exception import WidgetInputErrorView
43
44from zope.formlib.tests.support import VerifyResults
45from zope.formlib.tests.test_browserwidget import BrowserWidgetTest
46
47from zope.traversing.testing import setUp as traversingSetUp
48from zope.testing.cleanup import tearDown as traversingTearDown
49
50from waeup.sirp.jambtables.dictwidget import DictWidget, DictDisplayWidget
51
52class DictWidgetTestHelper(object):
53
54    def setUpContent(self, desc=u'', title=u'Foo Title'):
55        class ITestContent(Interface):
56            foo = self._FieldFactory(
57                    title=title,
58                    description=desc,
59                    )
60        class TestObject(object):
61            implements(ITestContent)
62
63        self.content = TestObject()
64        self.field = ITestContent['foo'].bind(self.content)
65        self.request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl')
66        self.request.form['field.foo'] = u'Foo Value'
67        self._widget = self._WidgetFactory(
68            self.field, self.request)
69
70    def setUp(self):
71        traversingSetUp()
72        self.setUpContent()
73
74    def tearDown(self):
75        traversingTearDown()
76       
77    def _FieldFactory(self, **kw):
78        kw.update({
79            '__name__': u'foo',
80            'key_type': TextLine(__name__=u'bar',title=u'bar'),
81            'value_type': TextLine(__name__=u'baz',title=u'baz')})
82        return Dict(**kw)
83
84
85class DictWidgetTest(DictWidgetTestHelper, BrowserWidgetTest):
86    """Documents and tests the dict widget.
87
88        >>> from zope.interface.verify import verifyClass
89        >>> verifyClass(IInputWidget, DictWidget)
90        True
91    """
92
93    _WidgetFactory = DictWidget
94
95    def testRender(self):
96        pass
97
98    def setUp(self):
99        super(DictWidgetTest, self).setUp()
100        provideAdapter(TextWidget,
101                       (ITextLine, IDefaultBrowserLayer),
102                       IInputWidget, '')
103        provideAdapter(WidgetInputErrorView,
104                       (IWidgetInputError, IDefaultBrowserLayer),
105                       IWidgetInputErrorView, '')
106
107    def test_haveNoData(self):
108        self.failIf(self._widget.hasInput())
109
110    def test_hasInput(self):
111        self._widget.request.form['field.foo.count'] = u'0'
112        self.failUnless(self._widget.hasInput())
113
114    def test_customWidgetFactory(self):
115        """Verify that the widget can be constructed via the CustomWidgetFactory
116        (Issue #293)
117        """
118        key_type = TextLine(__name__=u'bar')
119        value_type = TextLine(__name__=u'baz')
120        self.field = Dict( __name__=u'foo',
121                           value_type=value_type,
122                           key_type=key_type)
123        request = TestRequest()
124
125        # set up the custom widget factory and verify that it works
126        sw = CustomWidgetFactory(DictWidget)
127        widget = sw(self.field, request)
128        assert widget.subwidget is None
129        assert widget.context.value_type is value_type
130
131        # set up a variant that specifies the subwidget to use and verify it
132        class PollOption(object) : pass
133        ow = CustomWidgetFactory(ObjectWidget, PollOption)
134        sw = CustomWidgetFactory(DictWidget, subwidget=ow)
135        widget = sw(self.field, request)
136        assert widget.subwidget is ow
137        assert widget.context.value_type is value_type
138        assert widget.context.key_type is key_type
139
140    def test_subwidget(self):
141        """This test verifies that the specified subwidget is not ignored.
142        (Issue #293)
143        """
144        self.field = Dict(__name__=u'foo',
145                          key_type=TextLine(__name__=u'bar'),
146                          value_type=TextLine(__name__=u'baz'),
147                          )
148        request = TestRequest()
149
150        class PollOption(object) : pass
151        ow = CustomWidgetFactory(ObjectWidget, PollOption)
152        widget = DictWidget(
153            self.field, request, subwidget=ow)
154        assert widget.subwidget is ow
155
156    def test_dict(self):
157        self.field = Dict(
158            __name__=u'foo',
159            key_type=TextLine(__name__=u'bar'),
160            value_type=TextLine(__name__=u'baz'),
161            )
162        request = TestRequest()
163        widget = DictWidget(
164            self.field, request)
165        self.failIf(widget.hasInput())
166        self.assertRaises(MissingInputError, widget.getInputValue)
167
168        request = TestRequest(form={'field.foo.add': u'Add bar',
169                                    'field.foo.count': u'0'})
170        widget = DictWidget(
171            self.field, request)
172        self.assert_(widget.hasInput())
173        self.assertRaises(WidgetInputError, widget.getInputValue)
174
175        request = TestRequest(form={'field.foo.key.0.bar': u'Hello',
176                                    'field.foo.value.0.baz': u'world!',
177                                    'field.foo.count': u'1'})
178        widget = DictWidget(
179            self.field, request)
180        self.assert_(widget.hasInput())
181        self.assertEquals(widget.getInputValue(), {u'Hello': u'world!'})
182
183    def test_new(self):
184        request = TestRequest()
185        widget = TupleSequenceWidget(
186            self.field, self.field.value_type, request)
187        self.failIf(widget.hasInput())
188        self.assertRaises(MissingInputError, widget.getInputValue)
189        check_list = ('input', 'name="field.foo.add"')
190        self.verifyResult(widget(), check_list)
191
192    def test_add(self):
193        request = TestRequest(form={'field.foo.add': u'Add bar',
194                                    'field.foo.count': u'0'})
195        widget = DictWidget(
196            self.field, request)
197        self.assert_(widget.hasInput())
198        self.assertRaises(WidgetInputError, widget.getInputValue)
199        check_list = (
200            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
201            'submit', 'submit', 'field.foo.add'
202        )
203        self.verifyResult(widget(), check_list, inorder=True)
204
205    def test_request(self):
206        request = TestRequest(form={'field.foo.key.0.bar': u'Hello',
207                                    'field.foo.value.0.baz': u'world!',
208                                    'field.foo.count': u'1'})
209        #widget = DictWidget(
210        #    self.field, self.field.value_type, request)
211        widget = DictWidget(
212            self.field, request)
213        self.assert_(widget.hasInput())
214        self.assertEquals(widget.getInputValue(), {u'Hello': 'world!'})
215
216    def test_existing(self):
217        request = TestRequest()
218        widget = DictWidget(
219            self.field, request)
220        widget.setRenderedValue({'existing':'value'})
221        self.failIf(widget.hasInput())
222        self.assertRaises(MissingInputError, widget.getInputValue)
223        check_list = (
224            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
225                'existing',
226            'submit', 'submit', 'field.foo.add',
227            'field.foo.count" value="1"',
228        )
229        self.verifyResult(widget(), check_list, inorder=True)
230        widget.setRenderedValue({u'existing':u'entry',
231                                 u'second':u'value'})
232        self.failIf(widget.hasInput())
233        self.assertRaises(MissingInputError, widget.getInputValue)
234        check_list = (
235            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
236                'second',
237            'checkbox', 'field.foo.remove_1', 'input', 'field.foo.key.1.bar',
238                'existing',
239            'submit', 'submit', 'field.foo.add',
240            'field.foo.count" value="2"',
241        )
242        self.verifyResult(widget(), check_list, inorder=True)
243
244    def test_remove(self):
245        request = TestRequest(form={
246            'field.foo.remove_0': u'1',
247            'field.foo.0.bar': u'existing',
248            'field.foo.1.bar': u'second',
249            'field.foo.remove': u'Remove selected items',
250            'field.foo.count': u'2'})
251        request = TestRequest(form={
252            'field.foo.remove_0': u'1',
253            'field.foo.key.0.bar': u'first',
254            'field.foo.value.0.baz': u'entry',
255            'field.foo.key.1.bar': u'second',
256            'field.foo.value.1.baz': u'entry',
257            'field.foo.remove': u'Remove selected items',
258            'field.foo.count': u'2'})
259        #widget = TupleSequenceWidget(
260        #    self.field, self.field.value_type, request)
261        widget = DictWidget(
262            self.field, request)
263        #widget.setRenderedValue(((u'existing', u'one'), (u'second', u'entry')))
264        #widget.setRenderedValue({u'existing': u'one', u'other': u'entry'})
265        widget.setRenderedValue({u'other': u'entry', u'existing': u'one'})
266        #a = widget.getInputValue()
267        #print "AAAAAAAAAAAAAAAA: ", a
268        self.assertEquals(widget.getInputValue(), {u'second': u'entry'})
269        #self.assertEquals(a, {u'second': u'entry'})
270        output = widget()
271        #print "WIDGET_OUTPUT: ", output
272        check_list = (
273            'checkbox', 'field.foo.remove_0',
274            'input', 'field.foo.key.0.bar', 'other',
275            'input', 'field.foo.value.0.baz', 'entry',
276            'checkbox', 'field.foo.remove_1',
277            'input', 'field.foo.key.1.bar', 'existing',
278            'input', 'field.foo.value.1.baz', 'one',
279            'submit', 'submit', 'field.foo.add',
280            'field.foo.count" value="2"',
281        )
282        #self.verifyResult(widget(), check_list, inorder=True)
283        self.verifyResult(output, check_list, inorder=True)
284
285    def test_min(self):
286        request = TestRequest()
287        self.field.min_length = 2
288        #widget = TupleSequenceWidget(
289        #    self.field, self.field.value_type, request)
290        widget = DictWidget(
291            self.field, request)
292        widget.setRenderedValue({u'existing': u'value', None:None})
293        self.assertRaises(MissingInputError, widget.getInputValue)
294        check_list = (
295            'input', 'field.foo.key.0.bar', 'value=""',
296            'input', 'field.foo.key.1.bar', 'existing',
297            'submit', 'field.foo.add'
298        )
299        s = widget()
300        #print "S: "
301        #print s
302        self.verifyResult(s, check_list, inorder=True)
303        self.assertEquals(s.find('checkbox'), -1)
304
305    def test_max(self):
306        request = TestRequest()
307        self.field.max_length = 1
308        widget = DictWidget(
309            self.field, request)
310        widget.setRenderedValue({u'existing':u'value'})
311        self.assertRaises(MissingInputError, widget.getInputValue)
312        s = widget()
313        self.assertEquals(s.find('field.foo.add'), -1)
314
315    def test_anonymousfield(self):
316        self.field = Dict(__name__=u'foo',
317                          value_type=TextLine(),
318                          key_type=TextLine())
319        request = TestRequest()
320        widget = DictWidget(
321            self.field, request)
322        widget.setRenderedValue({u'existing':u'value'})
323        s = widget()
324        check_list = (
325            'input', '"field.foo.key.0."', 'existing',
326            'submit', 'submit', 'field.foo.add'
327        )
328        s = widget()
329        self.verifyResult(s, check_list, inorder=True)
330
331    def test_usererror(self):
332        self.field = Dict(__name__=u'foo',
333                          key_type=TextLine(__name__='bar'),
334                          value_type=TextLine(__name__='baz'),
335                          )
336        request = TestRequest(form={
337            'field.foo.key.0.bar': u'',
338            'field.foo.value.0.baz': u'value',
339            'field.foo.key.1.bar': u'nonempty',
340            'field.foo.value.1.baz': u'entry',
341            'field.foo.count': u'2'})
342        widget = DictWidget(
343            self.field, request)
344        # Rendering a widget should not raise errors!
345        widget()
346
347        data = widget._generateSequence()
348        self.assertEquals(data, [(None, u'value'),
349                                 (u'nonempty', u'entry')])
350
351    def doctest_widgeterrors(self):
352        """Test that errors on subwidgets appear
353
354            >>> #field = Tuple(__name__=u'foo',
355            >>> #              value_type=TextLine(__name__='bar'))
356            >>> field = Dict(__name__=u'foo',
357            ...              key_type=TextLine(__name__='bar',title=u'bar'),
358            ...              value_type=TextLine(__name__='baz',title=u'baz'))
359            >>> request = TestRequest(form={
360            ...     'field.foo.key.0.bar': u'',
361            ...     'field.foo.value.0.baz': u'some',
362            ...     'field.foo.key.1.bar': u'nonempty',
363            ...     'field.foo.value.1.baz': u'entry',
364            ...     'field.foo.count': u'2'})
365            >>> #widget = TupleSequenceWidget(field, field.value_type, request)
366            >>> widget = DictWidget(field, request)
367
368         If we render the widget, we see no errors:
369
370            >>> print widget()
371            <BLANKLINE>
372            ...
373            <tr>
374              <td>
375                 <input class="editcheck" type="checkbox"
376                        name="field.foo.remove_0" />
377              </td>
378              <td>
379                 <input class="textType" id="field.foo.key.0.bar"
380                        name="field.foo.key.0.bar"
381                        size="20" type="text" value=""  />
382              </td>
383              ...
384            </tr>
385            ...
386
387         However, if we call getInputValue or hasValidInput, the
388         errors on the widgets are preserved and displayed:
389
390            >>> widget.hasValidInput()
391            False
392
393            >>> print widget()
394            <BLANKLINE>
395            ...
396            <tr>
397              <td>
398                 <input class="editcheck" type="checkbox"
399                        name="field.foo.remove_0" />
400              </td>
401              <td>
402                 <span class="error">Required input is missing.</span>
403                 <input class="textType" id="field.foo.key.0.bar"
404                        name="field.foo.key.0.bar"
405                        size="20" type="text" value=""  />
406              </td>
407              ...
408            </tr>
409            ...
410        """
411
412
413
414class SequenceDisplayWidgetTest(
415    VerifyResults, DictWidgetTestHelper, unittest.TestCase):
416
417    def _WidgetFactory(self, *args, **kw):
418        #w = SequenceDisplayWidget(*args, **kw)
419        w = DictDisplayWidget(*args, **kw)
420        w.cssClass = "testwidget"
421        return w
422
423    def setUp(self):
424        self.setUpContent()
425        self.request = TestRequest()
426        #self.widget = self._WidgetFactory(
427        #    self.field, self.field.value_type, self.request)
428        self.widget = self._WidgetFactory(
429            self.field, self.request)
430        provideAdapter(DisplayWidget, (ITextLine, IDefaultBrowserLayer),
431                       IDisplayWidget)
432       
433    def test_render_empty(self):
434        self.content.foo = ()
435        self.assertEquals(self.widget(), '(no values)')
436
437    def test_render_missing(self):
438        self.content.foo = self.field.missing_value
439        self.assertEquals(self.widget(), '(no value available)')
440
441    def test_render_single(self):
442        self.content.foo = {u'one':u'value'}
443        check_list = ['<ol', 'class=', 'testwidget',
444                      '<li', 'one: value', '</li', '</ol']
445        self.verifyResult(self.widget(), check_list, inorder=True)
446
447    def test_render_multiple(self):
448        self.content.foo = {u'one': u'entry',
449                            u'entry': u'two',
450                            u'three': u'a value',
451                            u'fourth': u'entry'}
452        check_list = ['<ol', 'class=', 'testwidget',
453                      '<li', 'entry: two', '</li',
454                      '<li', 'three: a value', '</li',
455                      '<li', 'fourth: entry', '</li',
456                      '<li', 'one: entry', '</li',
457                      '</ol']
458        self.verifyResult(self.widget(), check_list, inorder=True)
459
460    def test_render_alternate_cssClass(self):
461        #self.content.foo = (u'one value',)
462        self.content.foo = {u'one': u'value'}
463        check_list = ['<ol', 'class=', 'altclass',
464                      '<li', 'one: value', '</li', '</ol']
465        self.widget.cssClass = 'altclass'
466        self.verifyResult(self.widget(), check_list, inorder=True)
467
468    def test_honors_subwidget(self):
469        self.widget = self._WidgetFactory(
470            self.field, self.request,
471            subwidget=UppercaseDisplayWidget)
472        self.content.foo = {u'first value': u'second value'}
473        check_list = ['<ol', 'class=', 'testwidget',
474                      '<li', 'FIRST VALUE: SECOND VALUE', '</li',
475                      '</ol']
476        self.verifyResult(self.widget(), check_list, inorder=True)
477
478
479class UppercaseDisplayWidget(DisplayWidget):
480
481    def __call__(self):
482        return super(UppercaseDisplayWidget, self).__call__().upper()
483
484
485def setUp(test):
486    traversingSetUp()
487    provideAdapter(TextWidget,
488                   (ITextLine, IDefaultBrowserLayer),
489                   IInputWidget)
490    provideAdapter(WidgetInputErrorView,
491                   (IWidgetInputError, IDefaultBrowserLayer),
492                   IWidgetInputErrorView)
493
494def tearDown(test):
495    traversingTearDown()
496
497
498def test_suite():
499    return unittest.TestSuite((
500        unittest.makeSuite(DictWidgetTest),
501        doctest.DocTestSuite(setUp=setUp, tearDown=tearDown,
502                             optionflags=doctest.ELLIPSIS
503                             |doctest.NORMALIZE_WHITESPACE
504                             |doctest.REPORT_NDIFF),
505        unittest.makeSuite(SequenceDisplayWidgetTest),
506        ))
507
508if __name__=='__main__':
509    unittest.main(defaultTest='test_suite')
Note: See TracBrowser for help on using the repository browser.