Index: main/waeup.widgets.core/trunk/src/waeup/widgets/core/tests/test_dictwidget.py
===================================================================
--- main/waeup.widgets.core/trunk/src/waeup/widgets/core/tests/test_dictwidget.py	(revision 5291)
+++ main/waeup.widgets.core/trunk/src/waeup/widgets/core/tests/test_dictwidget.py	(revision 5291)
@@ -0,0 +1,509 @@
+##
+## test_dictwidget.py
+## Login : <uli@pu.smp.net>
+## Started on  Sun Jul 18 15:47:58 2010 Uli Fouquet
+## $Id$
+## 
+## Copyright (C) 2010 Uli Fouquet
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Dict Field Widget tests.
+"""
+import unittest
+from zope.interface import Interface, implements
+from zope.schema import Tuple, List, TextLine, Dict
+from zope.schema.interfaces import ITextLine
+from zope.component import provideAdapter
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+import doctest
+
+from zope.formlib.widgets import TextWidget, ObjectWidget, DisplayWidget
+from zope.formlib.widgets import TupleSequenceWidget, ListSequenceWidget
+from zope.formlib.widgets import SequenceDisplayWidget
+from zope.formlib.widgets import SequenceWidget
+from zope.formlib.interfaces import IDisplayWidget
+from zope.formlib.interfaces import IInputWidget, MissingInputError
+from zope.formlib.interfaces import IWidgetInputError, WidgetInputError
+from zope.formlib.interfaces import IWidgetInputErrorView
+from zope.formlib.widget import CustomWidgetFactory
+from zope.formlib.exception import WidgetInputErrorView
+
+from zope.formlib.tests.support import VerifyResults
+from zope.formlib.tests.test_browserwidget import BrowserWidgetTest
+
+from zope.traversing.testing import setUp as traversingSetUp
+from zope.testing.cleanup import tearDown as traversingTearDown
+
+from waeup.sirp.jambtables.dictwidget import DictWidget, DictDisplayWidget
+
+class DictWidgetTestHelper(object):
+
+    def setUpContent(self, desc=u'', title=u'Foo Title'):
+        class ITestContent(Interface):
+            foo = self._FieldFactory(
+                    title=title,
+                    description=desc,
+                    )
+        class TestObject(object):
+            implements(ITestContent)
+
+        self.content = TestObject()
+        self.field = ITestContent['foo'].bind(self.content)
+        self.request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl')
+        self.request.form['field.foo'] = u'Foo Value'
+        self._widget = self._WidgetFactory(
+            self.field, self.request)
+
+    def setUp(self):
+        traversingSetUp()
+        self.setUpContent()
+
+    def tearDown(self):
+        traversingTearDown()
+        
+    def _FieldFactory(self, **kw):
+        kw.update({
+            '__name__': u'foo', 
+            'key_type': TextLine(__name__=u'bar',title=u'bar'),
+            'value_type': TextLine(__name__=u'baz',title=u'baz')})
+        return Dict(**kw)
+
+
+class DictWidgetTest(DictWidgetTestHelper, BrowserWidgetTest):
+    """Documents and tests the dict widget.
+
+        >>> from zope.interface.verify import verifyClass
+        >>> verifyClass(IInputWidget, DictWidget)
+        True
+    """
+
+    _WidgetFactory = DictWidget
+
+    def testRender(self):
+        pass
+
+    def setUp(self):
+        super(DictWidgetTest, self).setUp()
+        provideAdapter(TextWidget,
+                       (ITextLine, IDefaultBrowserLayer),
+                       IInputWidget, '')
+        provideAdapter(WidgetInputErrorView,
+                       (IWidgetInputError, IDefaultBrowserLayer),
+                       IWidgetInputErrorView, '')
+
+    def test_haveNoData(self):
+        self.failIf(self._widget.hasInput())
+
+    def test_hasInput(self):
+        self._widget.request.form['field.foo.count'] = u'0'
+        self.failUnless(self._widget.hasInput())
+
+    def test_customWidgetFactory(self):
+        """Verify that the widget can be constructed via the CustomWidgetFactory
+        (Issue #293)
+        """
+        key_type = TextLine(__name__=u'bar')
+        value_type = TextLine(__name__=u'baz')
+        self.field = Dict( __name__=u'foo',
+                           value_type=value_type,
+                           key_type=key_type)
+        request = TestRequest()
+
+        # set up the custom widget factory and verify that it works
+        sw = CustomWidgetFactory(DictWidget)
+        widget = sw(self.field, request)
+        assert widget.subwidget is None
+        assert widget.context.value_type is value_type
+
+        # set up a variant that specifies the subwidget to use and verify it
+        class PollOption(object) : pass
+        ow = CustomWidgetFactory(ObjectWidget, PollOption)
+        sw = CustomWidgetFactory(DictWidget, subwidget=ow)
+        widget = sw(self.field, request)
+        assert widget.subwidget is ow
+        assert widget.context.value_type is value_type
+        assert widget.context.key_type is key_type
+
+    def test_subwidget(self):
+        """This test verifies that the specified subwidget is not ignored.
+        (Issue #293)
+        """
+        self.field = Dict(__name__=u'foo',
+                          key_type=TextLine(__name__=u'bar'),
+                          value_type=TextLine(__name__=u'baz'),
+                          )
+        request = TestRequest()
+
+        class PollOption(object) : pass
+        ow = CustomWidgetFactory(ObjectWidget, PollOption)
+        widget = DictWidget(
+            self.field, request, subwidget=ow)
+        assert widget.subwidget is ow
+
+    def test_dict(self):
+        self.field = Dict(
+            __name__=u'foo',
+            key_type=TextLine(__name__=u'bar'),
+            value_type=TextLine(__name__=u'baz'),
+            )
+        request = TestRequest()
+        widget = DictWidget(
+            self.field, request)
+        self.failIf(widget.hasInput())
+        self.assertRaises(MissingInputError, widget.getInputValue)
+
+        request = TestRequest(form={'field.foo.add': u'Add bar',
+                                    'field.foo.count': u'0'})
+        widget = DictWidget(
+            self.field, request)
+        self.assert_(widget.hasInput())
+        self.assertRaises(WidgetInputError, widget.getInputValue)
+
+        request = TestRequest(form={'field.foo.key.0.bar': u'Hello',
+                                    'field.foo.value.0.baz': u'world!',
+                                    'field.foo.count': u'1'})
+        widget = DictWidget(
+            self.field, request)
+        self.assert_(widget.hasInput())
+        self.assertEquals(widget.getInputValue(), {u'Hello': u'world!'})
+
+    def test_new(self):
+        request = TestRequest()
+        widget = TupleSequenceWidget(
+            self.field, self.field.value_type, request)
+        self.failIf(widget.hasInput())
+        self.assertRaises(MissingInputError, widget.getInputValue)
+        check_list = ('input', 'name="field.foo.add"')
+        self.verifyResult(widget(), check_list)
+
+    def test_add(self):
+        request = TestRequest(form={'field.foo.add': u'Add bar',
+                                    'field.foo.count': u'0'})
+        widget = DictWidget(
+            self.field, request)
+        self.assert_(widget.hasInput())
+        self.assertRaises(WidgetInputError, widget.getInputValue)
+        check_list = (
+            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
+            'submit', 'submit', 'field.foo.add'
+        )
+        self.verifyResult(widget(), check_list, inorder=True)
+
+    def test_request(self):
+        request = TestRequest(form={'field.foo.key.0.bar': u'Hello',
+                                    'field.foo.value.0.baz': u'world!',
+                                    'field.foo.count': u'1'})
+        #widget = DictWidget(
+        #    self.field, self.field.value_type, request)
+        widget = DictWidget(
+            self.field, request)
+        self.assert_(widget.hasInput())
+        self.assertEquals(widget.getInputValue(), {u'Hello': 'world!'})
+
+    def test_existing(self):
+        request = TestRequest()
+        widget = DictWidget(
+            self.field, request)
+        widget.setRenderedValue({'existing':'value'})
+        self.failIf(widget.hasInput())
+        self.assertRaises(MissingInputError, widget.getInputValue)
+        check_list = (
+            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
+                'existing',
+            'submit', 'submit', 'field.foo.add',
+            'field.foo.count" value="1"',
+        )
+        self.verifyResult(widget(), check_list, inorder=True)
+        widget.setRenderedValue({u'existing':u'entry',
+                                 u'second':u'value'})
+        self.failIf(widget.hasInput())
+        self.assertRaises(MissingInputError, widget.getInputValue)
+        check_list = (
+            'checkbox', 'field.foo.remove_0', 'input', 'field.foo.key.0.bar',
+                'second',
+            'checkbox', 'field.foo.remove_1', 'input', 'field.foo.key.1.bar',
+                'existing',
+            'submit', 'submit', 'field.foo.add',
+            'field.foo.count" value="2"',
+        )
+        self.verifyResult(widget(), check_list, inorder=True)
+
+    def test_remove(self):
+        request = TestRequest(form={
+            'field.foo.remove_0': u'1',
+            'field.foo.0.bar': u'existing',
+            'field.foo.1.bar': u'second',
+            'field.foo.remove': u'Remove selected items',
+            'field.foo.count': u'2'})
+        request = TestRequest(form={
+            'field.foo.remove_0': u'1',
+            'field.foo.key.0.bar': u'first',
+            'field.foo.value.0.baz': u'entry',
+            'field.foo.key.1.bar': u'second',
+            'field.foo.value.1.baz': u'entry',
+            'field.foo.remove': u'Remove selected items',
+            'field.foo.count': u'2'})
+        #widget = TupleSequenceWidget(
+        #    self.field, self.field.value_type, request)
+        widget = DictWidget(
+            self.field, request)
+        #widget.setRenderedValue(((u'existing', u'one'), (u'second', u'entry')))
+        #widget.setRenderedValue({u'existing': u'one', u'other': u'entry'})
+        widget.setRenderedValue({u'other': u'entry', u'existing': u'one'})
+        #a = widget.getInputValue()
+        #print "AAAAAAAAAAAAAAAA: ", a
+        self.assertEquals(widget.getInputValue(), {u'second': u'entry'})
+        #self.assertEquals(a, {u'second': u'entry'})
+        output = widget()
+        #print "WIDGET_OUTPUT: ", output
+        check_list = (
+            'checkbox', 'field.foo.remove_0',
+            'input', 'field.foo.key.0.bar', 'other',
+            'input', 'field.foo.value.0.baz', 'entry',
+            'checkbox', 'field.foo.remove_1',
+            'input', 'field.foo.key.1.bar', 'existing',
+            'input', 'field.foo.value.1.baz', 'one',
+            'submit', 'submit', 'field.foo.add',
+            'field.foo.count" value="2"',
+        )
+        #self.verifyResult(widget(), check_list, inorder=True)
+        self.verifyResult(output, check_list, inorder=True)
+
+    def test_min(self):
+        request = TestRequest()
+        self.field.min_length = 2
+        #widget = TupleSequenceWidget(
+        #    self.field, self.field.value_type, request)
+        widget = DictWidget(
+            self.field, request)
+        widget.setRenderedValue({u'existing': u'value', None:None})
+        self.assertRaises(MissingInputError, widget.getInputValue)
+        check_list = (
+            'input', 'field.foo.key.0.bar', 'value=""',
+            'input', 'field.foo.key.1.bar', 'existing',
+            'submit', 'field.foo.add'
+        )
+        s = widget()
+        #print "S: "
+        #print s
+        self.verifyResult(s, check_list, inorder=True)
+        self.assertEquals(s.find('checkbox'), -1)
+
+    def test_max(self):
+        request = TestRequest()
+        self.field.max_length = 1
+        widget = DictWidget(
+            self.field, request)
+        widget.setRenderedValue({u'existing':u'value'})
+        self.assertRaises(MissingInputError, widget.getInputValue)
+        s = widget()
+        self.assertEquals(s.find('field.foo.add'), -1)
+
+    def test_anonymousfield(self):
+        self.field = Dict(__name__=u'foo',
+                          value_type=TextLine(),
+                          key_type=TextLine())
+        request = TestRequest()
+        widget = DictWidget(
+            self.field, request)
+        widget.setRenderedValue({u'existing':u'value'})
+        s = widget()
+        check_list = (
+            'input', '"field.foo.key.0."', 'existing',
+            'submit', 'submit', 'field.foo.add'
+        )
+        s = widget()
+        self.verifyResult(s, check_list, inorder=True)
+
+    def test_usererror(self):
+        self.field = Dict(__name__=u'foo',
+                          key_type=TextLine(__name__='bar'),
+                          value_type=TextLine(__name__='baz'),
+                          )
+        request = TestRequest(form={
+            'field.foo.key.0.bar': u'',
+            'field.foo.value.0.baz': u'value',
+            'field.foo.key.1.bar': u'nonempty',
+            'field.foo.value.1.baz': u'entry',
+            'field.foo.count': u'2'})
+        widget = DictWidget(
+            self.field, request)
+        # Rendering a widget should not raise errors!
+        widget()
+
+        data = widget._generateSequence()
+        self.assertEquals(data, [(None, u'value'),
+                                 (u'nonempty', u'entry')])
+
+    def doctest_widgeterrors(self):
+        """Test that errors on subwidgets appear
+
+            >>> #field = Tuple(__name__=u'foo',
+            >>> #              value_type=TextLine(__name__='bar'))
+            >>> field = Dict(__name__=u'foo',
+            ...              key_type=TextLine(__name__='bar',title=u'bar'),
+            ...              value_type=TextLine(__name__='baz',title=u'baz'))
+            >>> request = TestRequest(form={
+            ...     'field.foo.key.0.bar': u'',
+            ...     'field.foo.value.0.baz': u'some',
+            ...     'field.foo.key.1.bar': u'nonempty',
+            ...     'field.foo.value.1.baz': u'entry',
+            ...     'field.foo.count': u'2'})
+            >>> #widget = TupleSequenceWidget(field, field.value_type, request)
+            >>> widget = DictWidget(field, request)
+
+         If we render the widget, we see no errors:
+
+            >>> print widget()
+            <BLANKLINE>
+            ...
+            <tr>
+              <td>
+                 <input class="editcheck" type="checkbox"
+                        name="field.foo.remove_0" />
+              </td>
+              <td>
+                 <input class="textType" id="field.foo.key.0.bar"
+                        name="field.foo.key.0.bar"
+                        size="20" type="text" value=""  />
+              </td>
+              ...
+            </tr>
+            ...
+
+         However, if we call getInputValue or hasValidInput, the
+         errors on the widgets are preserved and displayed:
+
+            >>> widget.hasValidInput()
+            False
+
+            >>> print widget()
+            <BLANKLINE>
+            ...
+            <tr>
+              <td>
+                 <input class="editcheck" type="checkbox"
+                        name="field.foo.remove_0" />
+              </td>
+              <td>
+                 <span class="error">Required input is missing.</span>
+                 <input class="textType" id="field.foo.key.0.bar"
+                        name="field.foo.key.0.bar"
+                        size="20" type="text" value=""  />
+              </td>
+              ...
+            </tr>
+            ...
+        """
+
+
+
+class SequenceDisplayWidgetTest(
+    VerifyResults, DictWidgetTestHelper, unittest.TestCase):
+
+    def _WidgetFactory(self, *args, **kw):
+        #w = SequenceDisplayWidget(*args, **kw)
+        w = DictDisplayWidget(*args, **kw)
+        w.cssClass = "testwidget"
+        return w
+
+    def setUp(self):
+        self.setUpContent()
+        self.request = TestRequest()
+        #self.widget = self._WidgetFactory(
+        #    self.field, self.field.value_type, self.request)
+        self.widget = self._WidgetFactory(
+            self.field, self.request)
+        provideAdapter(DisplayWidget, (ITextLine, IDefaultBrowserLayer),
+                       IDisplayWidget)
+        
+    def test_render_empty(self):
+        self.content.foo = ()
+        self.assertEquals(self.widget(), '(no values)')
+
+    def test_render_missing(self):
+        self.content.foo = self.field.missing_value
+        self.assertEquals(self.widget(), '(no value available)')
+
+    def test_render_single(self):
+        self.content.foo = {u'one':u'value'}
+        check_list = ['<ol', 'class=', 'testwidget',
+                      '<li', 'one: value', '</li', '</ol']
+        self.verifyResult(self.widget(), check_list, inorder=True)
+
+    def test_render_multiple(self):
+        self.content.foo = {u'one': u'entry',
+                            u'entry': u'two',
+                            u'three': u'a value',
+                            u'fourth': u'entry'}
+        check_list = ['<ol', 'class=', 'testwidget',
+                      '<li', 'entry: two', '</li',
+                      '<li', 'three: a value', '</li',
+                      '<li', 'fourth: entry', '</li',
+                      '<li', 'one: entry', '</li',
+                      '</ol']
+        self.verifyResult(self.widget(), check_list, inorder=True)
+
+    def test_render_alternate_cssClass(self):
+        #self.content.foo = (u'one value',)
+        self.content.foo = {u'one': u'value'}
+        check_list = ['<ol', 'class=', 'altclass',
+                      '<li', 'one: value', '</li', '</ol']
+        self.widget.cssClass = 'altclass'
+        self.verifyResult(self.widget(), check_list, inorder=True)
+
+    def test_honors_subwidget(self):
+        self.widget = self._WidgetFactory(
+            self.field, self.request,
+            subwidget=UppercaseDisplayWidget)
+        self.content.foo = {u'first value': u'second value'}
+        check_list = ['<ol', 'class=', 'testwidget',
+                      '<li', 'FIRST VALUE: SECOND VALUE', '</li',
+                      '</ol']
+        self.verifyResult(self.widget(), check_list, inorder=True)
+
+
+class UppercaseDisplayWidget(DisplayWidget):
+
+    def __call__(self):
+        return super(UppercaseDisplayWidget, self).__call__().upper()
+
+
+def setUp(test):
+    traversingSetUp()
+    provideAdapter(TextWidget,
+                   (ITextLine, IDefaultBrowserLayer),
+                   IInputWidget)
+    provideAdapter(WidgetInputErrorView,
+                   (IWidgetInputError, IDefaultBrowserLayer),
+                   IWidgetInputErrorView)
+
+def tearDown(test):
+    traversingTearDown()
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(DictWidgetTest),
+        doctest.DocTestSuite(setUp=setUp, tearDown=tearDown,
+                             optionflags=doctest.ELLIPSIS
+                             |doctest.NORMALIZE_WHITESPACE
+                             |doctest.REPORT_NDIFF),
+        unittest.makeSuite(SequenceDisplayWidgetTest),
+        ))
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
