[Zope3-checkins] SVN: zope.formlib/branches/faassen-zaf/src/zope/formlib/ Move over a lot more widget tests from zope.app.form.
Martijn Faassen
faassen at startifact.com
Wed Dec 30 17:26:16 EST 2009
Log message for revision 107397:
Move over a lot more widget tests from zope.app.form.
Changed:
U zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/objectwidget.txt
A zope.formlib/branches/faassen-zaf/src/zope/formlib/source.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/source.txt
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicecollections.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicewidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datetimewidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datewidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_decimalwidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_displaywidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_intwidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_itemswidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_multicheckboxwidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_objectwidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_passwordwidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_radiowidget.py
A zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_source.py
-=-
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py 2009-12-30 21:54:52 UTC (rev 107396)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -310,6 +310,26 @@
"""Convert a widget input error to an html snippet."""
+class ISourceQueryView(Interface):
+ """View support for querying non-iterable sources
+ """
+
+ def render(name):
+ """Return a rendering of the search form elements
+
+ The query view should use `name` as the prefix for its widgets.
+ """
+
+ def results(name):
+ """Return the results of the query
+
+ The query view should use `name` as the prefix for its widgets.
+
+ The value returned is an iterable.
+
+ None may be returned to indicate that there are no results.
+ """
+
class ISubPage(Interface):
"""A component that computes part of a page
"""
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/objectwidget.txt (from rev 107371, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.txt)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/objectwidget.txt (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/objectwidget.txt 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,152 @@
+=============
+Object Widget
+=============
+
+The following example shows a Family with Mother and Father.
+First define the interface for a person:
+
+ >>> from zope.interface import Interface, implements
+ >>> from zope.schema import TextLine
+
+ >>> class IPerson(Interface):
+ ... """Interface for Persons."""
+ ...
+ ... name = TextLine(title=u'Name', description=u'The first name')
+
+Let's define the class:
+
+ >>> class Person(object):
+ ...
+ ... implements(IPerson)
+ ...
+ ... def __init__(self, name=''):
+ ... self.name = name
+
+Let's define the interface family:
+
+ >>> from zope.schema import Object
+
+ >>> class IFamily(Interface):
+ ... """The familiy interface."""
+ ...
+ ... mother = Object(title=u'Mother',
+ ... required=False,
+ ... schema=IPerson)
+ ...
+ ... father = Object(title=u'Father',
+ ... required=False,
+ ... schema=IPerson)
+
+Let's define the class family with FieldProperty's mother and father
+FieldProperty validate the values if they get added:
+
+ >>> from zope.schema.fieldproperty import FieldProperty
+
+ >>> class Family(object):
+ ... """The familiy interface."""
+ ...
+ ... implements(IFamily)
+ ...
+ ... mother = FieldProperty(IFamily['mother'])
+ ... father = FieldProperty(IFamily['father'])
+ ...
+ ... def __init__(self, mother=None, father=None):
+ ... self.mother = mother
+ ... self.father = father
+
+Let's make a instance of Family with None attributes:
+
+ >>> family = Family()
+ >>> bool(family.mother == None)
+ True
+
+ >>> bool(family.father == None)
+ True
+
+Let's make a instance of Family with None attributes:
+
+ >>> mother = Person(u'Margrith')
+ >>> father = Person(u'Joe')
+ >>> family = Family(mother, father)
+ >>> IPerson.providedBy(family.mother)
+ True
+
+ >>> IPerson.providedBy(family.father)
+ True
+
+Let's define a dummy class which doesn't implements IPerson:
+
+ >>> class Dummy(object):
+ ... """Dummy class."""
+ ... def __init__(self, name=''):
+ ... self.name = name
+
+Raise a SchemaNotProvided exception if we add a Dummy instance to a Family
+object:
+
+ >>> foo = Dummy('foo')
+ >>> bar = Dummy('bar')
+ >>> family = Family(foo, bar)
+ Traceback (most recent call last):
+ ...
+ SchemaNotProvided
+
+Now let's setup a enviroment for use the widget like in a real application:
+
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.schema.interfaces import ITextLine
+ >>> from zope.schema import TextLine
+ >>> from zope.app.form.browser import TextWidget
+ >>> from zope.app.form.browser import ObjectWidget
+ >>> from zope.formlib.interfaces import IInputWidget
+
+Register the TextLine widget used in the IPerson interface for the field 'name'.
+
+ >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+ >>> from zope.component import provideAdapter
+ >>> provideAdapter(TextWidget, (ITextLine, IDefaultBrowserLayer),
+ ... IInputWidget)
+
+Let's define a request and provide input value for the mothers name used
+in the family object:
+
+ >>> request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl')
+ >>> request.form['field.mother.name'] = u'Margrith Ineichen'
+
+Before we update the object let's check the value name of the mother
+instance on the family object:
+
+ >>> family.mother.name
+ u'Margrith'
+
+Now let's initialize a ObjectWidget with the right attributes:
+
+ >>> mother_field = IFamily['mother']
+ >>> factory = Person
+ >>> widget = ObjectWidget(mother_field, request, factory)
+
+Now comes the magic. Apply changes means we force the ObjectWidget to read
+the request, extract the value and save it on the content. The ObjectWidget
+instance uses a real Person class (factory) for add the value. The value is
+temporary stored in this factory class. The ObjectWidget reads the value from
+this factory and set it to the attribute 'name' of the instance mother
+(The object mother is allready there). If we don't have a instance mother
+allready store in the family object, the factory instance will be stored
+directly to the family attribute mother. For more information see the method
+'applyChanges()' in the interface
+zope.app.form.browser.objectwidget.ObjectWidget.
+
+ >>> widget.applyChanges(family)
+ True
+
+Test the updated mother's name value on the object family:
+
+ >>> family.mother.name
+ u'Margrith Ineichen'
+
+ >>> IPerson.providedBy(family.mother)
+ True
+
+So, now you know my mothers and fathers name. I hope it's also clear how to
+use the Object field and the ObjectWidget.
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/source.py (from rev 107373, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/source.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/source.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/source.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,610 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Source widgets support
+
+$Id$
+"""
+
+from itertools import imap
+
+import xml.sax.saxutils
+
+from zope.component import adapts, getMultiAdapter
+from zope.interface import implements
+import zope.browser.interfaces
+import zope.schema.interfaces
+from zope.schema.interfaces import \
+ ISourceQueriables, ValidationError, IVocabularyTokenized, IIterableSource
+
+import zope.formlib.interfaces
+import zope.formlib.widget
+from zope.formlib.interfaces import (
+ WidgetInputError,
+ MissingInputError,
+ ISourceQueryView,
+ IWidgetInputErrorView,
+ IDisplayWidget,
+ IInputWidget)
+
+from zope.formlib.i18n import _
+from zope.formlib.widgets import (
+ SelectWidget, RadioWidget, MultiSelectWidget, OrderedMultiSelectWidget,
+ MultiCheckBoxWidget, MultiSelectSetWidget, MultiSelectFrozenSetWidget)
+from zope.formlib.widget import InputWidget
+import zope.formlib.itemswidgets
+from zope.formlib.widget import DisplayWidget
+
+class SourceDisplayWidget(DisplayWidget):
+
+ implements(IDisplayWidget)
+
+ def __init__(self, field, source, request):
+ super(SourceDisplayWidget, self).__init__(field, request)
+ self.source = source
+
+ required = False
+
+ def hidden(self):
+ return ''
+
+ def error(self):
+ return ''
+
+ def __call__(self):
+ """Render the current value
+ """
+
+ if self._renderedValueSet():
+ value = self._data
+ else:
+ value = self.context.default
+
+ if value == self.context.missing_value:
+ value = self._translate(_("SourceDisplayWidget-missing",
+ default="Nothing"))
+ else:
+ terms = getMultiAdapter((self.source, self.request),
+ zope.browser.interfaces.ITerms)
+
+ try:
+ term = terms.getTerm(value)
+ except LookupError:
+ value = self._translate(_("SourceDisplayWidget-invalid",
+ default="Invalid value"))
+ else:
+ value = self.renderTermForDisplay(term)
+
+ return value
+
+ def renderTermForDisplay(self, term):
+ # Provide a rendering of `term` for display; this is not for
+ # use when generating a select list.
+ return xml.sax.saxutils.escape(self._translate(term.title))
+
+
+class SourceSequenceDisplayWidget(SourceDisplayWidget):
+
+ def __call__(self):
+
+ if self._renderedValueSet():
+ seq = self._data
+ else:
+ seq = self.context.default
+
+ terms = getMultiAdapter((self.source, self.request),
+ zope.browser.interfaces.ITerms)
+ result = []
+ for value in seq:
+ try:
+ term = terms.getTerm(value)
+ except LookupError:
+ value = self._translate(_("SourceDisplayWidget-invalid",
+ default="Invalid value"))
+ else:
+ value = self.renderTermForDisplay(term)
+
+ result.append(value)
+
+ return '<br />\n'.join(result)
+
+
+class SourceInputWidget(InputWidget):
+
+ _error = None
+
+ implements(IInputWidget)
+
+ def __init__(self, field, source, request):
+ super(SourceInputWidget, self).__init__(field, request)
+ self.source = source
+ self.terms = getMultiAdapter((source, self.request),
+ zope.browser.interfaces.ITerms)
+
+ def queryviews(self):
+ queriables = ISourceQueriables(self.source, None)
+ if queriables is None:
+ # treat the source itself as a queriable
+ queriables = ((self.name + '.query', self.source), )
+ else:
+ queriables = [
+ (self.name + '.' +
+ unicode(i).encode('base64').strip().replace('=', '_'), s)
+ for (i, s) in queriables.getQueriables()]
+
+ return [
+ (name, getMultiAdapter(
+ (source, self.request),
+ ISourceQueryView,
+ )
+ ) for (name, source) in queriables]
+
+ queryviews = property(queryviews)
+
+ def _value(self):
+ if self._renderedValueSet():
+ value = self._data
+ else:
+ for name, queryview in self.queryviews:
+ if name+'.apply' in self.request:
+ token = self.request.form.get(name+'.selection')
+ if token is not None:
+ break
+ else:
+ token = self.request.form.get(self.name)
+
+ if token is not None:
+ try:
+ value = self.terms.getValue(str(token))
+ except LookupError:
+ value = self.context.missing_value
+ else:
+ value = self.context.missing_value
+
+ return value
+
+ def hidden(self):
+ value = self._value()
+ if value == self.context.missing_value:
+ return '' # Nothing to hide ;)
+
+ try:
+ term = self.terms.getTerm(value)
+ except LookupError:
+ # A value was set, but it's not valid. Treat
+ # it as if it was missing and return nothing.
+ return ''
+
+ return ('<input type="hidden" name="%s" value=%s />'
+ % (self.name, xml.sax.saxutils.quoteattr(term.token))
+ )
+
+ def error(self):
+ if self._error:
+ # TODO This code path is untested.
+ return getMultiAdapter((self._error, self.request),
+ IWidgetInputErrorView).snippet()
+ return ""
+
+ def __call__(self):
+ result = ['<div class="value">']
+ value = self._value()
+ field = self.context
+
+ term = None
+ if value == field.missing_value:
+ result.append(' <div class="row">')
+ result.append(' <div class="label">')
+ result.append(u' ' +
+ self._translate(_("SourceDisplayWidget-label",
+ default="Selected"))
+ )
+ result.append(' </div>')
+ result.append(' <div class="field">')
+ result.append(u' ' +
+ self._translate(_("SourceDisplayWidget-missing",
+ default="Nothing"))
+ )
+ result.append(' </div>')
+ result.append(' </div>')
+ else:
+ try:
+ term = self.terms.getTerm(value)
+ except LookupError:
+ result.append(u' ' +
+ self._translate(_("SourceDisplayWidget-missing",
+ default="Nothing Valid"))
+ )
+ else:
+ result.append(' <div class="row">')
+ result.append(' <div class="label">')
+ result.append(u' ' +
+ self._translate(_("SourceDisplayWidget-label",
+ default="Selected"))
+ )
+ result.append(' </div>')
+ result.append(' <div class="field">')
+ result.append(u' ' + self.renderTermForDisplay(term))
+ result.append(' </div>')
+ result.append(' </div>')
+ result.append(
+ ' <input type="hidden" name="%s" value=%s />'
+ % (self.name, xml.sax.saxutils.quoteattr(term.token)))
+
+ result.append(' <input type="hidden" name="%s.displayed" value="y" />'
+ % self.name)
+
+ result.append(' <div class="queries">')
+ for name, queryview in self.queryviews:
+ result.append(' <div class="query">')
+ result.append(' <div class="queryinput">')
+ result.append(queryview.render(name))
+ result.append(' </div> <!-- queryinput -->')
+
+ qresults = queryview.results(name)
+ if qresults:
+ result.append(' <div class="queryresults">\n%s' %
+ self._renderResults(qresults, name))
+ result.append(' </div> <!-- queryresults -->')
+ result.append(' </div> <!-- query -->')
+ result.append(' </div> <!-- queries -->')
+ result.append('</div> <!-- value -->')
+ return '\n'.join(result)
+
+ def _renderResults(self, results, name):
+ terms = []
+ for value in results:
+ term = self.terms.getTerm(value)
+ terms.append((self._translate(term.title), term.token))
+ terms.sort()
+
+ apply = self._translate(_("SourceInputWidget-apply", default="Apply"))
+ return (
+ '<select name="%s.selection">\n'
+ '%s\n'
+ '</select>\n'
+ '<input type="submit" name="%s.apply" value="%s" />'
+ % (name,
+ '\n'.join(
+ [('<option value="%s">%s</option>'
+ % (token, title))
+ for (title, token) in terms]),
+ name,
+ apply)
+ )
+
+ def renderTermForDisplay(self, term):
+ # Provide a rendering of `term` for display; this is not for
+ # use when generating a select list.
+ return xml.sax.saxutils.escape(self._translate(term.title))
+
+ required = property(lambda self: self.context.required)
+
+ def getInputValue(self):
+ for name, queryview in self.queryviews:
+ if name+'.apply' in self.request:
+ token = self.request.form.get(name+'.selection')
+ if token is not None:
+ break
+ else:
+ token = self.request.get(self.name)
+
+ field = self.context
+
+ if token is None:
+ if field.required:
+ # TODO This code path is untested.
+ raise MissingInputError(
+ field.__name__, self.label,
+ )
+ return field.missing_value
+
+ try:
+ value = self.terms.getValue(str(token))
+ except LookupError:
+ # TODO This code path is untested.
+ err = zope.schema.interfaces.ValidationError(
+ "Invalid value id", token)
+ raise WidgetInputError(field.__name__, self.label, err)
+
+ # Remaining code copied from SimpleInputWidget
+
+ # value must be valid per the field constraints
+ try:
+ field.validate(value)
+ except ValidationError, err:
+ # TODO This code path is untested.
+ self._error = WidgetInputError(field.__name__, self.label, err)
+ raise self._error
+
+ return value
+
+ def hasInput(self):
+ if self.name in self.request or self.name+'.displayed' in self.request:
+ return True
+
+ for name, queryview in self.queryviews:
+ if name+'.apply' in self.request:
+ token = self.request.form.get(name+'.selection')
+ if token is not None:
+ return True
+
+ return False
+
+class SourceListInputWidget(SourceInputWidget):
+
+ def _input_value(self):
+ tokens = self.request.form.get(self.name)
+ for name, queryview in self.queryviews:
+ if name+'.apply' in self.request:
+ newtokens = self.request.form.get(name+'.selection')
+ if newtokens:
+ if tokens:
+ tokens = tokens + newtokens
+ else:
+ tokens = newtokens
+
+ if tokens:
+ remove = self.request.form.get(self.name+'.checked')
+ if remove and (self.name+'.remove' in self.request):
+ tokens = [token
+ for token in tokens
+ if token not in remove
+ ]
+ value = []
+ for token in tokens:
+ try:
+ v = self.terms.getValue(str(token))
+ except LookupError:
+ pass # skip invalid tokens (shrug)
+ else:
+ value.append(v)
+ else:
+ if self.name+'.displayed' in self.request:
+ value = []
+ else:
+ value = self.context.missing_value
+
+ if value:
+ r = []
+ seen = {}
+ for s in value:
+ if s not in seen:
+ r.append(s)
+ seen[s] = 1
+ value = r
+
+ return value
+
+ def _value(self):
+ if self._renderedValueSet():
+ value = self._data
+ else:
+ value = self._input_value()
+
+ return value
+
+ def hidden(self):
+ value = self._value()
+ if value == self.context.missing_value:
+ return '' # Nothing to hide ;)
+
+ result = []
+ for v in value:
+ try:
+ term = self.terms.getTerm(value)
+ except LookupError:
+ # A value was set, but it's not valid. Treat
+ # it as if it was missing and skip
+ continue
+ else:
+ result.append(
+ '<input type="hidden" name="%s:list" value=%s />'
+ % (self.name, xml.sax.saxutils.quoteattr(term.token))
+ )
+
+ def __call__(self):
+ result = ['<div class="value">']
+ value = self._value()
+ field = self.context
+
+ if value:
+ for v in value:
+ try:
+ term = self.terms.getTerm(v)
+ except LookupError:
+ continue # skip
+ else:
+ result.append(
+ ' <input type="checkbox" name="%s.checked:list"'
+ ' value=%s />'
+ % (self.name, xml.sax.saxutils.quoteattr(term.token))
+ )
+ result.append(' ' + self.renderTermForDisplay(term))
+ result.append(
+ ' <input type="hidden" name="%s:list" value=%s />'
+ % (self.name, xml.sax.saxutils.quoteattr(term.token)))
+ result.append(' <br />')
+
+ result.append(
+ ' <input type="submit" name="%s.remove" value="%s" />'
+ % (self.name,
+ self._translate(_("MultipleSourceInputWidget-remove",
+ default="Remove")))
+ )
+ result.append(' <br />')
+
+ result.append(' <input type="hidden" name="%s.displayed" value="y" />'
+ % self.name)
+
+ result.append(' <div class="queries">')
+
+ for name, queryview in self.queryviews:
+ result.append(' <div class="query">')
+ result.append(' <div class="queryinput">')
+ result.append(queryview.render(name))
+ result.append(' </div> <!-- queryinput -->')
+
+ qresults = queryview.results(name)
+ if qresults:
+ result.append(' <div class="queryresults">\n%s' %
+ self._renderResults(qresults, name))
+ result.append(' </div> <!-- queryresults -->')
+ result.append(' </div> <!-- query -->')
+
+ result.append(' </div> <!-- queries -->')
+ result.append('</div> <!-- value -->')
+ return '\n'.join(result)
+
+ def _renderResults(self, results, name):
+ terms = []
+ apply = self._translate(_("SourceListInputWidget-apply",
+ default="Apply"))
+ for value in results:
+ term = self.terms.getTerm(value)
+ terms.append((self._translate(term.title), term.token))
+ terms.sort()
+ return (
+ '<select name="%s.selection:list" multiple>\n'
+ '%s\n'
+ '</select>\n'
+ '<input type="submit" name="%s.apply" value="%s" />'
+ % (name,
+ '\n'.join([('<option value="%s">%s</option>' % (token, title))
+ for (title, token) in terms]),
+ name,
+ apply)
+ )
+
+ def getInputValue(self):
+ value = self._input_value()
+
+ # Remaining code copied from SimpleInputWidget
+
+ # value must be valid per the field constraints
+ field = self.context
+ try:
+ field.validate(value)
+ except ValidationError, err:
+ # TODO This code path is untested.
+ self._error = WidgetInputError(field.__name__, self.label, err)
+ raise self._error
+
+ return value
+
+ def hasInput(self):
+ return self.name+'.displayed' in self.request.form
+
+
+# Input widgets for IIterableSource:
+
+# These widgets reuse the old-style vocabulary widgets via the class
+# IterableSourceVocabulary that adapts a source (and its ITerms object)
+# into a vocabulary. When/if vocabularies go away, these classes
+# should be updated into full implementations.
+
+
+class IterableSourceVocabulary(object):
+
+ """Adapts an iterable source into a legacy vocabulary.
+
+ This can be used to wrap sources to make them usable with widgets that
+ expect vocabularies. Note that there must be an ITerms implementation
+ registered to obtain the terms.
+ """
+
+ implements(IVocabularyTokenized)
+ adapts(IIterableSource);
+
+ def __init__(self, source, request):
+ self.source = source
+ self.terms = getMultiAdapter((source, request),
+ zope.browser.interfaces.ITerms)
+
+ def getTerm(self, value):
+ return self.terms.getTerm(value)
+
+ def getTermByToken(self, token):
+ value = self.terms.getValue(token)
+ return self.getTerm(value)
+
+ def __iter__(self):
+ return imap(
+ lambda value: self.getTerm(value), self.source.__iter__())
+
+ def __len__(self):
+ return self.source.__len__()
+
+ def __contains__(self, value):
+ return self.source.__contains__(value)
+
+
+class SourceSelectWidget(SelectWidget):
+ """Provide a selection list for the item."""
+
+ def __init__(self, field, source, request):
+ super(SourceSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+ # BBB
+ if not zope.formlib.itemswidgets.EXPLICIT_EMPTY_SELECTION:
+ # Even if the field is required, no input is needed, so don't
+ # worry the user about it:
+ self.required = False
+
+class SourceDropdownWidget(SourceSelectWidget):
+ """Variation of the SourceSelectWidget that uses a drop-down list."""
+
+ size = 1
+ explicit_empty_selection = True
+
+class SourceRadioWidget(RadioWidget):
+ """Radio widget for single item choices."""
+
+ def __init__(self, field, source, request):
+ super(SourceRadioWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiSelectWidget(MultiSelectWidget):
+ """A multi-selection widget with ordering support."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceOrderedMultiSelectWidget(OrderedMultiSelectWidget):
+ """A multi-selection widget with ordering support."""
+
+ def __init__(self, field, source, request):
+ super(SourceOrderedMultiSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiSelectSetWidget(MultiSelectSetWidget):
+ """Provide a selection list for the set to be selected."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiSelectSetWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiSelectFrozenSetWidget(MultiSelectFrozenSetWidget):
+ """Provide a selection list for the frozenset to be selected."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiSelectFrozenSetWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiCheckBoxWidget(MultiCheckBoxWidget):
+ """Provide a list of checkboxes that provide the choice for the list."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiCheckBoxWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/source.txt (from rev 107371, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/source.txt)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/source.txt (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/source.txt 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,1113 @@
+==============
+Source Widgets
+==============
+
+Sources are objects that represent sets of values from which one might choose
+and are used with Choice schema fields. Source widgets currently fall into two
+categories:
+
+- widgets for iterable sources
+
+- widgets for queryable sources
+
+Sources (combined with the available adapters) may support both approaches, but
+no widgets currently support both.
+
+In both cases, the widgets need views that can be used to get tokens to
+represent source values in forms, as well as textual representations of values.
+We use the `zope.browser.interfaces.ITerms` views for that.
+
+All of our examples will be using the component architecture::
+
+ >>> import zope.interface
+ >>> import zope.component
+ >>> import zope.schema
+
+This `ITerms` implementation can be used for the sources involved in
+our tests::
+
+ >>> from zope.browser.interfaces import ITerms
+ >>> import zope.publisher.interfaces.browser
+ >>> import zope.app.form.browser.interfaces
+ >>> from zope.schema.vocabulary import SimpleTerm
+ >>> class ListTerms:
+ ...
+ ... zope.interface.implements(ITerms)
+ ...
+ ... def __init__(self, source, request):
+ ... pass # We don't actually need the source or the request :)
+ ...
+ ... def getTerm(self, value):
+ ... title = unicode(value)
+ ... try:
+ ... token = title.encode('base64').strip()
+ ... except binascii.Error:
+ ... raise LookupError(token)
+ ... return SimpleTerm(value, token=token, title=title)
+ ...
+ ... def getValue(self, token):
+ ... return token.decode('base64')
+
+This view just uses the unicode representations of values as titles and the
+base-64 encoding of the titles as tokens. This is a very simple strategy
+that's only approriate when the values have short and unique unicode
+representations.
+
+All of the source widgets are in a single module::
+
+ >>> import zope.app.form.browser.source
+
+We'll also need request objects::
+
+ >>> from zope.publisher.browser import TestRequest
+
+
+Iterable Source Widgets
+=======================
+
+Iterable sources are expected to be simpler than queriable sources, so they
+represent a good place to start. The most important aspect of iterable sources
+for widgets is that it's actually possible to enumerate all the values from the
+source. This allows each possible value to be listed in a <select> form field.
+
+Let's start with a simple example. We have a very trivial source,
+which is basically a list::
+
+ >>> class SourceList(list):
+ ... zope.interface.implements(zope.schema.interfaces.IIterableSource)
+
+We need to register our `ITerms` view::
+
+ >>> zope.component.provideAdapter(
+ ... ListTerms,
+ ... (SourceList, zope.publisher.interfaces.browser.IBrowserRequest))
+
+Let's define a choice field using our iterable source::
+
+ >>> dog = zope.schema.Choice(
+ ... __name__ = 'dog',
+ ... title=u"Dogs",
+ ... source=SourceList(['spot', 'bowser', 'prince', 'duchess', 'lassie']),
+ ... )
+
+ >>> dog = dog.bind(object())
+
+When we get a choice input widget for a choice field, the default widget
+factory gets a view on the field and the field's source. We'll just create the
+view directly::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceSelectWidget(
+ ... dog, dog.source, request)
+
+ >>> print widget()
+ <div>
+ <div class="value">
+ <select id="field.dog" name="field.dog" size="5" >
+ <option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option>
+ </select>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+Since the field is required, an empty selection is not valid:
+
+ >>> widget.getInputValue()
+ Traceback (most recent call last):
+ MissingInputError: ('field.dog', u'Dogs', None)
+
+Also, the widget is required in this case:
+
+ >>> widget.required
+ True
+
+If the request contains a value, it is marked as selected::
+
+ >>> request.form["field.dog-empty-marker"] = "1"
+ >>> request.form["field.dog"] = "Ym93c2Vy"
+
+ >>> print widget()
+ <div>
+ <div class="value">
+ <select id="field.dog" name="field.dog" size="5" >
+ <option value="c3BvdA==">spot</option>
+ <option selected="selected" value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option>
+ </select>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+If we set the displayed value for the widget, that value is marked as
+selected::
+
+ >>> widget.setRenderedValue("duchess")
+ >>> print widget()
+ <div>
+ <div class="value">
+ <select id="field.dog" name="field.dog" size="5" >
+ <option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option selected="selected" value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option>
+ </select>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+Dropdown widgets are achieved with SourceDropdownWidget, which simply
+generates a selection list of size 1::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceDropdownWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +ELLIPSIS
+ <div>
+ <div class="value">
+ <select id="field.dog" name="field.dog" size="1" >
+ <option selected="selected" value="">(no value)</option>...
+
+An alternative to SourceSelectWidget for small numbers of items is
+SourceRadioWidget that provides a radio button group for the items::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceRadioWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label for="field.dog.0"><input class="radioType" id="field.dog.0"
+ name="field.dog" type="radio" value="c3BvdA==" /> spot</label><br
+ /><label for="field.dog.1"><input class="radioType" id="field.dog.1"
+ name="field.dog" type="radio" value="Ym93c2Vy" /> bowser</label><br
+ /><label for="field.dog.2"><input class="radioType" id="field.dog.2"
+ name="field.dog" type="radio" value="cHJpbmNl" /> prince</label><br
+ /><label for="field.dog.3"><input class="radioType" id="field.dog.3"
+ name="field.dog" type="radio" value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label for="field.dog.4"><input class="radioType" id="field.dog.4"
+ name="field.dog" type="radio" value="bGFzc2ll" /> lassie</label>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+We'll select an item by setting the appropriate fields in the request::
+
+ >>> request.form['field.dog-empty-marker'] = '1'
+ >>> request.form['field.dog'] = 'bGFzc2ll'
+ >>>
+ >>> widget = zope.app.form.browser.source.SourceRadioWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label for="field.dog.0"><input class="radioType" id="field.dog.0"
+ name="field.dog" type="radio" value="c3BvdA==" /> spot</label><br
+ /><label for="field.dog.1"><input class="radioType" id="field.dog.1"
+ name="field.dog" type="radio" value="Ym93c2Vy" /> bowser</label><br
+ /><label for="field.dog.2"><input class="radioType" id="field.dog.2"
+ name="field.dog" type="radio" value="cHJpbmNl" /> prince</label><br
+ /><label for="field.dog.3"><input class="radioType" id="field.dog.3"
+ name="field.dog" type="radio" value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label for="field.dog.4"><input class="radioType" checked="checked"
+ id="field.dog.4" name="field.dog" type="radio" value="bGFzc2ll"
+ /> lassie</label>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+For list-valued fields with items chosen from iterable sources, there are the
+SourceMultiSelectWidget and SourceOrderedMultiSelectWidget widgets. The latter
+widget includes support for re-ording the list items.
+SourceOrderedMultiSelectWidget is configured as the default widget for lists of
+choices.
+
+If you don't need ordering support through the web UI, then you can use
+the simpler SourceMultiSelectWidget::
+
+ >>> dogSource = SourceList([
+ ... u'spot', u'bowser', u'prince', u'duchess', u'lassie'])
+ >>> dogs = zope.schema.List(
+ ... __name__ = 'dogs',
+ ... title=u"Dogs",
+ ... value_type=zope.schema.Choice(
+ ... source=dogSource,
+ ... )
+ ... )
+ >>> dogs = dogs.bind(object()) # give the field a context
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiSelectWidget(
+ ... dogs, dogSource, request)
+
+Let's look at the rendered widget::
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogs" multiple="multiple" name="field.dogs:list"
+ size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+We have no input yet::
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.formlib.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+Select an item::
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ ['lassie']
+
+and another::
+
+ >>> request.form['field.dogs'] = ['cHJpbmNl', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ ['prince', 'lassie']
+
+Finally, what does the widget look like now::
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogs" multiple="multiple" name="field.dogs:list"
+ size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option selected="selected" value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option selected="selected" value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+An alternative for small numbers of items is to use SourceMultiCheckBoxWidget::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiCheckBoxWidget(
+ ... dogs, dogSource, request)
+
+The rendered widget::
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label for="field.dogs.0"><input class="checkboxType" id="field.dogs.0"
+ name="field.dogs" type="checkbox" value="c3BvdA==" /> spot</label><br
+ /><label for="field.dogs.1"><input class="checkboxType" id="field.dogs.1"
+ name="field.dogs" type="checkbox" value="Ym93c2Vy"
+ /> bowser</label><br
+ /><label for="field.dogs.2"><input class="checkboxType" id="field.dogs.2"
+ name="field.dogs" type="checkbox" value="cHJpbmNl"
+ /> prince</label><br
+ /><label for="field.dogs.3"><input class="checkboxType" id="field.dogs.3"
+ name="field.dogs" type="checkbox"
+ value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label for="field.dogs.4"><input class="checkboxType" id="field.dogs.4"
+ name="field.dogs" type="checkbox" value="bGFzc2ll"
+ /> lassie</label>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+We have no input yet::
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.formlib.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+Select an item::
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ ['lassie']
+
+and another::
+
+ >>> request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ ['spot', 'lassie']
+
+Finally, what does the widget look like now::
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label for="field.dogs.0"><input class="checkboxType" checked="checked"
+ id="field.dogs.0" name="field.dogs" type="checkbox" value="c3BvdA=="
+ /> spot</label><br
+ /><label for="field.dogs.1"><input class="checkboxType" id="field.dogs.1"
+ name="field.dogs" type="checkbox" value="Ym93c2Vy"
+ /> bowser</label><br
+ /><label for="field.dogs.2"><input class="checkboxType" id="field.dogs.2"
+ name="field.dogs" type="checkbox" value="cHJpbmNl"
+ /> prince</label><br
+ /><label for="field.dogs.3"><input class="checkboxType" id="field.dogs.3"
+ name="field.dogs" type="checkbox"
+ value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label for="field.dogs.4"><input class="checkboxType" checked="checked"
+ id="field.dogs.4" name="field.dogs" type="checkbox" value="bGFzc2ll"
+ /> lassie</label>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+For list ordering support, use SourceOrderedMultiSelectWidget::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceOrderedMultiSelectWidget(
+ ... dogs, dogSource, request)
+
+The widget is too complicated to show in complete rendered form here.
+Insted, we'll inspect the properties of the widget::
+
+ >>> from zope.formlib.interfaces import MissingInputError
+ >>> try:
+ ... widget.getInputValue()
+ ... except MissingInputError:
+ ... print 'no input'
+ no input
+
+ >>> widget.choices() == [
+ ... {'text': u'spot', 'value': 'c3BvdA=='},
+ ... {'text': u'bowser', 'value': 'Ym93c2Vy'},
+ ... {'text': u'prince', 'value': 'cHJpbmNl'},
+ ... {'text': u'duchess', 'value': 'ZHVjaGVzcw=='},
+ ... {'text': u'lassie', 'value': 'bGFzc2ll'}
+ ... ]
+ True
+
+ >>> widget.selected()
+ []
+
+Let's try out selecting items. Select one item::
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.selected() # doctest: +NORMALIZE_WHITESPACE
+ [{'text': u'lassie', 'value': 'bGFzc2ll'}]
+
+ >>> widget.getInputValue()
+ ['lassie']
+
+Select two items::
+
+ >>> request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.selected() # doctest: +NORMALIZE_WHITESPACE
+ [{'text': u'spot', 'value': 'c3BvdA=='},
+ {'text': u'lassie', 'value': 'bGFzc2ll'}]
+
+ >>> widget.getInputValue()
+ ['spot', 'lassie']
+
+
+For set-valued fields, use SourceMultiSelectSetWidget::
+
+ >>> dogSet = zope.schema.Set(
+ ... __name__ = 'dogSet',
+ ... title=u"Dogs",
+ ... value_type=zope.schema.Choice(
+ ... source=dogSource,
+ ... )
+ ... )
+ >>> dogSet = dogSet.bind(object()) # give the field a context
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiSelectSetWidget(
+ ... dogSet, dogSource, request)
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.formlib.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogSet" multiple="multiple"
+ name="field.dogSet:list" size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogSet-empty-marker" type="hidden" value="1" />
+ </div>
+
+Let's try out selecting items. Select one item::
+
+ >>> request.form['field.dogSet-empty-marker'] = '1'
+ >>> request.form['field.dogSet'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ set(['lassie'])
+
+Select two items::
+
+ >>> request.form['field.dogSet'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ set(['spot', 'lassie'])
+
+The rendered widget (still with the two items selected) looks like this::
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogSet" multiple="multiple"
+ name="field.dogSet:list" size="5" ><option selected="selected"
+ value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option selected="selected" value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogSet-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+
+Source Widget Query Framework
+=============================
+
+An important aspect of sources is that they may have too many values to
+enumerate. Rather than listing all of the values, we, instead, provide
+interfaces for querying values and selecting values from query results.
+Matters are further complicated by the fact that different sources may have
+very different interfaces for querying them.
+
+To make matters more interesting, a source may be an aggregation of several
+collections, each with their own querying facilities. An example of such a
+source is a principal source, where principals might come from a number of
+places, such as an LDAP database and ZCML-based principal definitions.
+
+The default widgets for selecting values from sources use the
+following approach:
+
+- One or more query objects are obtained from the source by adapting the source
+ to `zope.schema.ISourceQueriables`. If no adapter is obtained, then the
+ source itself is assumed to be queriable.
+
+- For each queriable found, a
+ `zope.app.form.browser.interfaces.ISourceQueryView` view is looked up. This
+ view is used to obtain the HTML for displaying a query form. The view is also
+ used to obtain search results.
+
+Let's start with a simple example. We have a very trivial source,
+which is basically a list:
+
+ >>> class SourceList(list):
+ ... zope.interface.implements(zope.schema.interfaces.ISource)
+
+We need to register our `ITerms` view::
+
+ >>> zope.component.provideAdapter(
+ ... ListTerms,
+ ... (SourceList, zope.publisher.interfaces.browser.IBrowserRequest))
+
+We aren't going to provide an adapter to `ISourceQueriables`, so the source
+itself will be used as it's own queriable. We need to provide a query view
+for the source::
+
+ >>> class ListQueryView:
+ ...
+ ... zope.interface.implements(
+ ... zope.app.form.browser.interfaces.ISourceQueryView)
+ ... zope.component.adapts(
+ ... SourceList,
+ ... zope.publisher.interfaces.browser.IBrowserRequest,
+ ... )
+ ...
+ ... def __init__(self, source, request):
+ ... self.source = source
+ ... self.request = request
+ ...
+ ... def render(self, name):
+ ... return (
+ ... '<input name="%s.string">\n'
+ ... '<input type="submit" name="%s" value="Search">'
+ ... % (name, name)
+ ... )
+ ...
+ ... def results(self, name):
+ ... if name in self.request:
+ ... search_string = self.request.get(name+'.string')
+ ... if search_string is not None:
+ ... return [value
+ ... for value in self.source
+ ... if search_string in value
+ ... ]
+ ... return None
+
+ >>> zope.component.provideAdapter(ListQueryView)
+
+Now, we can define a choice field::
+
+ >>> dog = zope.schema.Choice(
+ ... __name__ = 'dog',
+ ... title=u"Dogs",
+ ... source=SourceList(['spot', 'bowser', 'prince', 'duchess', 'lassie']),
+ ... )
+
+As before, we'll just create the view directly::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceInputWidget(
+ ... dog, dog.source, request)
+
+Now if we render the widget, we'll see the input value (initially nothing) and
+a form elements for seaching for values::
+
+ >>> print widget()
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ Nothing
+ </div>
+ </div>
+ <input type="hidden" name="field.dog.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.dog.query.string">
+ <input type="submit" name="field.dog.query" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+This shows that we haven't selected a dog. We get a search box that we can type
+seach strings into. Let's supply a search string. We do this by providing data
+in the form and by "selecting" the submit button::
+
+ >>> request.form['field.dog.displayed'] = u'y'
+ >>> request.form['field.dog.query.string'] = u'o'
+ >>> request.form['field.dog.query'] = u'Search'
+
+Because the field is required, a non-selection is not valid. Thus, while the
+widget still hasInput, it will raise an error when you getInputValue::
+
+ >>> widget.hasInput()
+ True
+ >>> widget.getInputValue()
+ Traceback (most recent call last):
+ ...
+ MissingInputError: ('dog', u'Dogs', None)
+
+If the field is not required::
+
+ >>> dog.required = False
+
+then as long as the field is displayed, the widget still has input but returns
+the field's missing value::
+
+ >>> widget.hasInput()
+ True
+ >>> widget.getInputValue() # None
+
+Now if we render the widget, we'll see the search results::
+
+ >>> dog.required = True
+ >>> print widget()
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ Nothing
+ </div>
+ </div>
+ <input type="hidden" name="field.dog.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.dog.query.string">
+ <input type="submit" name="field.dog.query" value="Search">
+ </div> <!-- queryinput -->
+ <div class="queryresults">
+ <select name="field.dog.query.selection">
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="c3BvdA==">spot</option>
+ </select>
+ <input type="submit" name="field.dog.query.apply" value="Apply" />
+ </div> <!-- queryresults -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+If we select an item::
+
+ >>> request.form['field.dog.displayed'] = u'y'
+ >>> del request.form['field.dog.query.string']
+ >>> del request.form['field.dog.query']
+ >>> request.form['field.dog.query.selection'] = u'c3BvdA=='
+ >>> request.form['field.dog.query.apply'] = u'Apply'
+
+Then we'll show the newly selected value::
+
+ >>> print widget()
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ spot
+ </div>
+ </div>
+ <input type="hidden" name="field.dog" value="c3BvdA==" />
+ <input type="hidden" name="field.dog.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.dog.query.string">
+ <input type="submit" name="field.dog.query" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+Note that we should have an input value now, since pressing the 'Apply' button
+provides us with input::
+
+ >>> widget.hasInput()
+ True
+
+We should also be able to get the input value::
+
+ >>> widget.getInputValue()
+ 'spot'
+
+Now, let's look at a more complicated example. We'll define a source that
+combines multiple sources::
+
+ >>> class MultiSource:
+ ...
+ ... zope.interface.implements(
+ ... zope.schema.interfaces.ISource,
+ ... zope.schema.interfaces.ISourceQueriables,
+ ... )
+ ...
+ ... def __init__(self, *sources):
+ ... self.sources = [(unicode(i), s) for (i, s) in enumerate(sources)]
+ ...
+ ... def __contains__(self, value):
+ ... for i, s in self.sources:
+ ... if value in s:
+ ... return True
+ ... return False
+ ...
+ ... def getQueriables(self):
+ ... return self.sources
+
+This multi-source implements `ISourceQueriables`. It assumes that the sources
+it's given are queriable and just returns the sources as the queryable objects.
+
+We can reuse our terms view::
+
+ >>> zope.component.provideAdapter(
+ ... ListTerms,
+ ... (MultiSource, zope.publisher.interfaces.browser.IBrowserRequest))
+
+Now, we'll create a pet choice that combines dogs and cats::
+
+ >>> pet = zope.schema.Choice(
+ ... __name__ = 'pet',
+ ... title=u"Dogs and Cats",
+ ... source=MultiSource(
+ ... dog.source,
+ ... SourceList(['boots', 'puss', 'tabby', 'tom', 'tiger']),
+ ... ),
+ ... )
+
+and a widget::
+
+ >>> widget = zope.app.form.browser.source.SourceInputWidget(
+ ... pet, pet.source, request)
+
+Now if we display the widget, we'll see search inputs for both dogs
+and cats::
+
+ >>> print widget()
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ Nothing
+ </div>
+ </div>
+ <input type="hidden" name="field.pet.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MA__.string">
+ <input type="submit" name="field.pet.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MQ__.string">
+ <input type="submit" name="field.pet.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+As before, we can perform a search::
+
+ >>> request.form['field.pet.displayed'] = u'y'
+ >>> request.form['field.pet.MQ__.string'] = u't'
+ >>> request.form['field.pet.MQ__'] = u'Search'
+
+In which case, we'll get some results::
+
+ >>> print widget() # doctest:
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ Nothing
+ </div>
+ </div>
+ <input type="hidden" name="field.pet.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MA__.string">
+ <input type="submit" name="field.pet.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MQ__.string">
+ <input type="submit" name="field.pet.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ <div class="queryresults">
+ <select name="field.pet.MQ__.selection">
+ <option value="Ym9vdHM=">boots</option>
+ <option value="dGFiYnk=">tabby</option>
+ <option value="dGlnZXI=">tiger</option>
+ <option value="dG9t">tom</option>
+ </select>
+ <input type="submit" name="field.pet.MQ__.apply" value="Apply" />
+ </div> <!-- queryresults -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+from which we can choose::
+
+ >>> request.form['field.pet.displayed'] = u'y'
+ >>> del request.form['field.pet.MQ__.string']
+ >>> del request.form['field.pet.MQ__']
+ >>> request.form['field.pet.MQ__.selection'] = u'dGFiYnk='
+ >>> request.form['field.pet.MQ__.apply'] = u'Apply'
+
+and get a selection::
+
+ >>> print widget()
+ <div class="value">
+ <div class="row">
+ <div class="label">
+ Selected
+ </div>
+ <div class="field">
+ tabby
+ </div>
+ </div>
+ <input type="hidden" name="field.pet" value="dGFiYnk=" />
+ <input type="hidden" name="field.pet.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MA__.string">
+ <input type="submit" name="field.pet.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pet.MQ__.string">
+ <input type="submit" name="field.pet.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+Note that we should have an input value now, since pressing the 'Apply' button
+provides us with input::
+
+ >>> widget.hasInput()
+ True
+
+and we can get the input value::
+
+ >>> widget.getInputValue()
+ 'tabby'
+
+There's a display widget, which doesn't use queriables, since it doesn't assign
+values::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceDisplayWidget(
+ ... pet, pet.source, request)
+ >>> print widget()
+ Nothing
+ >>> from zope.app.form.browser.interfaces import IBrowserWidget
+ >>> IBrowserWidget.providedBy(widget)
+ True
+
+ >>> widget.setRenderedValue('tabby')
+ >>> print widget()
+ tabby
+
+Like any good display widget, input is not required::
+
+ >>> widget.required
+ False
+
+If we specify a list of choices::
+
+ >>> pets = zope.schema.List(__name__ = 'pets', title=u"Pets",
+ ... value_type=pet)
+
+when a widget is computed for the field, a view will be looked up for the field
+and the source, where, in this case, the field is a list field. We'll just call
+the widget factory directly::
+
+ >>> widget = zope.app.form.browser.source.SourceListInputWidget(
+ ... pets, pets.value_type.source, request)
+
+If we render the widget::
+
+ >>> print widget()
+ <div class="value">
+ <input type="hidden" name="field.pets.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MA__.string">
+ <input type="submit" name="field.pets.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MQ__.string">
+ <input type="submit" name="field.pets.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+Here the output looks very similar to the simple choice case. We get a search
+input for each source. In this case, we don't show any inputs
+(TODO we probably should make it clearer that there are no selected values.)
+
+As before, we can search one of the sources::
+
+ >>> request.form['field.pets.displayed'] = u'y'
+ >>> request.form['field.pets.MQ__.string'] = u't'
+ >>> request.form['field.pets.MQ__'] = u'Search'
+
+In which case, we'll get some results::
+
+ >>> print widget()
+ <div class="value">
+ <input type="hidden" name="field.pets.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MA__.string">
+ <input type="submit" name="field.pets.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MQ__.string">
+ <input type="submit" name="field.pets.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ <div class="queryresults">
+ <select name="field.pets.MQ__.selection:list" multiple>
+ <option value="Ym9vdHM=">boots</option>
+ <option value="dGFiYnk=">tabby</option>
+ <option value="dGlnZXI=">tiger</option>
+ <option value="dG9t">tom</option>
+ </select>
+ <input type="submit" name="field.pets.MQ__.apply" value="Apply" />
+ </div> <!-- queryresults -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+from which we can select some values::
+
+ >>> request.form['field.pets.displayed'] = u'y'
+ >>> del request.form['field.pets.MQ__.string']
+ >>> del request.form['field.pets.MQ__']
+ >>> request.form['field.pets.MQ__.selection'] = [
+ ... u'dGFiYnk=', u'dGlnZXI=', u'dG9t']
+ >>> request.form['field.pets.MQ__.apply'] = u'Apply'
+
+Which then leads to the selections appearing as widget selections::
+
+ >>> print widget()
+ <div class="value">
+ <input type="checkbox" name="field.pets.checked:list" value="dGFiYnk=" />
+ tabby
+ <input type="hidden" name="field.pets:list" value="dGFiYnk=" />
+ <br />
+ <input type="checkbox" name="field.pets.checked:list" value="dGlnZXI=" />
+ tiger
+ <input type="hidden" name="field.pets:list" value="dGlnZXI=" />
+ <br />
+ <input type="checkbox" name="field.pets.checked:list" value="dG9t" />
+ tom
+ <input type="hidden" name="field.pets:list" value="dG9t" />
+ <br />
+ <input type="submit" name="field.pets.remove" value="Remove" />
+ <br />
+ <input type="hidden" name="field.pets.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MA__.string">
+ <input type="submit" name="field.pets.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MQ__.string">
+ <input type="submit" name="field.pets.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+We can get the selected values::
+
+ >>> widget.getInputValue()
+ ['tabby', 'tiger', 'tom']
+
+We now see the values we selected. We also have checkboxes and buttons that
+allow us to remove selections::
+
+ >>> request.form['field.pets.displayed'] = u'y'
+ >>> request.form['field.pets'] = [u'dGFiYnk=', u'dGlnZXI=', u'dG9t']
+ >>> del request.form['field.pets.MQ__.selection']
+ >>> del request.form['field.pets.MQ__.apply']
+ >>> request.form['field.pets.checked'] = [u'dGFiYnk=', u'dG9t']
+ >>> request.form['field.pets.remove'] = u'Remove'
+
+ >>> print widget()
+ <div class="value">
+ <input type="checkbox" name="field.pets.checked:list" value="dGlnZXI=" />
+ tiger
+ <input type="hidden" name="field.pets:list" value="dGlnZXI=" />
+ <br />
+ <input type="submit" name="field.pets.remove" value="Remove" />
+ <br />
+ <input type="hidden" name="field.pets.displayed" value="y" />
+ <div class="queries">
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MA__.string">
+ <input type="submit" name="field.pets.MA__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ <div class="query">
+ <div class="queryinput">
+ <input name="field.pets.MQ__.string">
+ <input type="submit" name="field.pets.MQ__" value="Search">
+ </div> <!-- queryinput -->
+ </div> <!-- query -->
+ </div> <!-- queries -->
+ </div> <!-- value -->
+
+
+Using vocabulary-dependent widgets with sources
+===============================================
+
+if you have a widget that uses old-style vocabularies but don't have the time
+to rewrite it for sources, all is not lost! The wrapper
+IterableSourceVocabulary can be used to make sources and ITerms look like a
+vocabulary. This allows us to use vocabulary-based widgets with sources
+instead of vocabularies.
+
+Usage::
+
+ >>> from zope.schema.vocabulary import SimpleTerm
+
+ >>> values = [u'a', u'b', u'c']
+ >>> tokens = [ '0', '1', '2']
+ >>> titles = [u'A', u'B', u'C']
+
+ >>> terms = [SimpleTerm(values[i], token=tokens[i], title=titles[i]) \
+ ... for i in range(0,len(values))]
+
+ >>> class TestSource(list):
+ ... zope.interface.implements(zope.schema.interfaces.IIterableSource)
+ >>> source = TestSource(values)
+
+ >>> class TestTerms(object):
+ ... zope.interface.implements(ITerms)
+ ... def __init__(self, source, request):
+ ... pass
+ ... def getTerm(self, value):
+ ... index = values.index(value)
+ ... return terms[index]
+ ... def getValue(self, token):
+ ... index = tokens.index(token)
+ ... return values[index]
+
+ >>> zope.component.provideAdapter(
+ ... TestTerms,
+ ... (TestSource, zope.publisher.interfaces.browser.IBrowserRequest))
+
+ >>> from zope.app.form.browser.source import IterableSourceVocabulary
+ >>> request = TestRequest()
+ >>> vocab = IterableSourceVocabulary(source, request)
+ >>> from zope.interface.verify import verifyClass, verifyObject
+ >>> verifyClass(zope.schema.interfaces.IVocabularyTokenized, \
+ ... IterableSourceVocabulary)
+ True
+ >>> verifyObject(zope.schema.interfaces.IVocabularyTokenized, vocab)
+ True
+
+ >>> len(vocab)
+ 3
+ >>> (u'a' in vocab) and (u'b' in vocab) and (u'c' in vocab)
+ True
+ >>> [value for value in vocab] == terms
+ True
+ >>> term = vocab.getTerm(u'b')
+ >>> (term.value, term.token, term.title)
+ (u'b', '1', u'B')
+ >>> term = vocab.getTermByToken('2')
+ >>> (term.value, term.token, term.title)
+ (u'c', '2', u'C')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicecollections.py (from rev 107371, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_choicecollections.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicecollections.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicecollections.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,73 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the choice collections widgets (function).
+
+$Id$
+"""
+import unittest
+from zope.component.testing import PlacelessSetup
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.browser import TestRequest
+from zope.schema.interfaces import IList, IChoice, IIterableVocabulary
+from zope.schema import Choice, List
+
+from zope.component import provideAdapter
+
+from zope.formlib.interfaces import IInputWidget, IDisplayWidget
+from zope.formlib.widgets import CollectionDisplayWidget
+from zope.formlib.widgets import CollectionInputWidget
+from zope.formlib.widgets import ChoiceCollectionDisplayWidget
+from zope.formlib.widgets import ChoiceCollectionInputWidget
+from zope.formlib.widgets import ItemsMultiDisplayWidget, SelectWidget
+
+class ListOfChoicesWidgetTest(PlacelessSetup, unittest.TestCase):
+
+ def test_ListOfChoicesDisplayWidget(self):
+ provideAdapter(ChoiceCollectionDisplayWidget,
+ (IList, IChoice, IBrowserRequest),
+ IDisplayWidget)
+ provideAdapter(ItemsMultiDisplayWidget,
+ (IList, IIterableVocabulary, IBrowserRequest),
+ IDisplayWidget)
+ field = List(value_type=Choice(values=[1, 2, 3]))
+ bound = field.bind(object())
+ widget = CollectionDisplayWidget(bound, TestRequest())
+ self.assert_(isinstance(widget, ItemsMultiDisplayWidget))
+ self.assertEqual(widget.context, bound)
+ self.assertEqual(widget.vocabulary, bound.value_type.vocabulary)
+
+
+ def test_ChoiceSequenceEditWidget(self):
+ provideAdapter(ChoiceCollectionInputWidget,
+ (IList, IChoice, IBrowserRequest),
+ IInputWidget)
+ provideAdapter(SelectWidget,
+ (IList, IIterableVocabulary, IBrowserRequest),
+ IInputWidget)
+ field = List(value_type=Choice(values=[1, 2, 3]))
+ bound = field.bind(object())
+ widget = CollectionInputWidget(bound, TestRequest())
+ self.assert_(isinstance(widget, SelectWidget))
+ self.assertEqual(widget.context, bound)
+ self.assertEqual(widget.vocabulary, bound.value_type.vocabulary)
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(ListOfChoicesWidgetTest),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicewidget.py (from rev 107371, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_choicewidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicewidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_choicewidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the Choice display and edit widget (function).
+
+$Id$
+"""
+import unittest
+from zope.component.testing import PlacelessSetup
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.browser import TestRequest
+from zope.schema.interfaces import IChoice, IIterableVocabulary
+from zope.schema import Choice
+
+from zope.component import provideAdapter
+from zope.formlib.interfaces import IInputWidget, IDisplayWidget
+from zope.formlib.widgets import ChoiceDisplayWidget, ChoiceInputWidget
+from zope.formlib.widgets import ItemDisplayWidget, DropdownWidget
+
+
+class ChoiceWidgetTest(PlacelessSetup, unittest.TestCase):
+
+ def test_ChoiceDisplayWidget(self):
+ provideAdapter(ItemDisplayWidget,
+ (IChoice, IIterableVocabulary, IBrowserRequest),
+ IDisplayWidget)
+ field = Choice(values=[1, 2, 3])
+ bound = field.bind(object())
+ widget = ChoiceDisplayWidget(bound, TestRequest())
+ self.assert_(isinstance(widget, ItemDisplayWidget))
+ self.assertEqual(widget.context, bound)
+ self.assertEqual(widget.vocabulary, bound.vocabulary)
+
+ def test_ChoiceInputWidget(self):
+ provideAdapter(DropdownWidget,
+ (IChoice, IIterableVocabulary, IBrowserRequest),
+ IInputWidget)
+ field = Choice(values=[1, 2, 3])
+ bound = field.bind(object())
+ widget = ChoiceInputWidget(bound, TestRequest())
+ self.assert_(isinstance(widget, DropdownWidget))
+ self.assertEqual(widget.context, bound)
+ self.assertEqual(widget.vocabulary, bound.vocabulary)
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(ChoiceWidgetTest),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datetimewidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_datetimewidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datetimewidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datetimewidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,177 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Datetime Widget Tests
+
+$Id$
+"""
+import datetime
+import unittest
+from zope.testing import doctest
+
+from zope.schema import Datetime
+from zope.datetime import parseDatetimetz, tzinfo
+from zope.interface.verify import verifyClass
+
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import DatetimeWidget
+from zope.formlib.widgets import DatetimeI18nWidget
+from zope.formlib.interfaces import ConversionError, WidgetInputError
+
+
+class DatetimeWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the datetime widget.
+
+ >>> verifyClass(IInputWidget, DatetimeWidget)
+ True
+ """
+
+ _FieldFactory = Datetime
+ _WidgetFactory = DatetimeWidget
+
+ def testRender(self):
+ super(DatetimeWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="2004-03-26 12:58:59"'))
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ # widget has input, even if input is an empty string
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'2003-03-26 12:00:00'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getInputValue(self,
+ value=u'2004-03-26 12:58:59',
+ check_value=parseDatetimetz('2004-03-26 12:58:59')):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = value
+ self.assertEquals(self._widget.getInputValue(), check_value)
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+class DatetimeI18nWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the i18n datetime widget.
+
+ >>> verifyClass(IInputWidget, DatetimeI18nWidget)
+ True
+ """
+
+ _FieldFactory = Datetime
+ _WidgetFactory = DatetimeI18nWidget
+
+ def testDefaultDisplayStyle(self):
+ self.failIf(self._widget.displayStyle)
+
+ def testRender(self):
+ super(DatetimeI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.2004 12:58:59"'))
+
+ def testRenderShort(self):
+ self._widget.displayStyle = "short"
+ super(DatetimeI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.04 12:58"'))
+
+ def testRenderMedium(self):
+ self._widget.displayStyle = "medium"
+ super(DatetimeI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.2004 12:58:59"'))
+
+ def testRenderLong(self):
+ self._widget.displayStyle = "long"
+ super(DatetimeI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ u'value="26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ u' 12:58:59 +000"'))
+
+ def testRenderFull(self):
+ self._widget.displayStyle = "full"
+ super(DatetimeI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ u'value="26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ u' 12:58:59 +000"'))
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ # widget has input, even if input is an empty string
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'26.03.2003 12:00:00'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getDefaultInputValue(self,
+ value=u'26.03.2004 12:58:59',
+ check_value=datetime.datetime(2004, 3, 26, 12, 58, 59)):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = value
+ self.assertEquals(self._widget.getInputValue(), check_value)
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+ def test_getShortInputValue(self):
+ self._widget.displayStyle = "short"
+ self.test_getDefaultInputValue(
+ value=u'26.03.04 12:58',
+ check_value=datetime.datetime(2004, 3, 26, 12, 58)
+ )
+
+ def test_getMediumInputValue(self):
+ self._widget.displayStyle = "medium"
+ self.test_getDefaultInputValue(
+ value=u'26.03.2004 12:58:59',
+ check_value=datetime.datetime(2004, 3, 26, 12, 58, 59)
+ )
+
+ def test_getLongInputValue(self):
+ self._widget.displayStyle = "long"
+ self.test_getDefaultInputValue(
+ value=(u'26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ u' 12:58:59 +030'),
+ check_value=datetime.datetime(2004, 3, 26, 12, 58, 59,
+ tzinfo=tzinfo(30))
+ )
+
+ def test_getFullInputValue(self):
+ self._widget.displayStyle = "full"
+ self.test_getDefaultInputValue(
+ value=(u'26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ u' 12:58:59 +030'),
+ check_value=datetime.datetime(2004, 3, 26, 12, 58, 59,
+ tzinfo=tzinfo(30))
+ )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(DatetimeWidgetTest),
+ unittest.makeSuite(DatetimeI18nWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datewidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_datewidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datewidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_datewidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,160 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Date Widget tests
+
+$Id$
+"""
+import datetime
+import unittest
+from zope.testing import doctest
+from zope.datetime import parseDatetimetz
+from zope.schema import Date
+from zope.interface.verify import verifyClass
+
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import DateWidget
+from zope.formlib.widgets import DateI18nWidget
+from zope.formlib.interfaces import ConversionError, WidgetInputError
+
+
+class DateWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the date widget.
+
+ >>> verifyClass(IInputWidget, DateWidget)
+ True
+ """
+
+ _FieldFactory = Date
+ _WidgetFactory = DateWidget
+
+ def testRender(self):
+ super(DateWidgetTest, self).testRender(
+ datetime.date(2003, 3, 26),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="2003-03-26"'))
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'2003-03-26'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getInputValue(self,
+ value=u'2004-03-26',
+ check_value=datetime.date(2004, 3, 26)):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = value
+ self.assertEquals(self._widget.getInputValue(), check_value)
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+class DateI18nWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the i18n date widget.
+
+ >>> verifyClass(IInputWidget, DateI18nWidget)
+ True
+ """
+
+ _FieldFactory = Date
+ _WidgetFactory = DateI18nWidget
+
+ def testDefaultDisplayStyle(self):
+ self.failIf(self._widget.displayStyle)
+
+ def testRender(self):
+ super(DateI18nWidgetTest, self).testRender(
+ datetime.date(2003, 3, 26),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.2003"'))
+
+ def testRenderShort(self):
+ self._widget.displayStyle = "short"
+ super(DateI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.04"'))
+
+ def testRenderMedium(self):
+ self._widget.displayStyle = "medium"
+ super(DateI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ 'value="26.03.2004"'))
+
+ def testRenderLong(self):
+ self._widget.displayStyle = "long"
+ super(DateI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ u'value="26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433."'))
+
+ def testRenderFull(self):
+ self._widget.displayStyle = "full"
+ super(DateI18nWidgetTest, self).testRender(
+ datetime.datetime(2004, 3, 26, 12, 58, 59),
+ ('type="text"', 'id="field.foo"', 'name="field.foo"',
+ u'value="26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433."'))
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'26.03.2003'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getDefaultInputValue(self,
+ value=u'26.03.2004',
+ check_value=datetime.date(2004, 3, 26)):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = value
+ self.assertEquals(self._widget.getInputValue(), check_value)
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+ def test_getShortInputValue(self):
+ self._widget.displayStyle = "short"
+ self.test_getDefaultInputValue(u'26.03.04')
+
+ def test_getMediumInputValue(self):
+ self._widget.displayStyle = "medium"
+ self.test_getDefaultInputValue(u'26.03.2004')
+
+ def test_getLongInputValue(self):
+ self._widget.displayStyle = "long"
+ self.test_getDefaultInputValue(
+ u'26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ )
+
+ def test_getFullInputValue(self):
+ self._widget.displayStyle = "full"
+ self.test_getDefaultInputValue(
+ u'26 \u043c\u0430\u0440\u0442\u0430 2004 \u0433.'
+ )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(DateWidgetTest),
+ unittest.makeSuite(DateI18nWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_decimalwidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_decimalwidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_decimalwidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_decimalwidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decimal Widget tests
+
+$Id$
+"""
+import unittest
+import decimal
+from zope.testing import doctest
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import DecimalWidget
+from zope.formlib.interfaces import ConversionError, WidgetInputError
+from zope.interface.verify import verifyClass
+
+from zope.schema import Decimal
+
+
+class DecimalWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the float widget.
+
+ >>> verifyClass(IInputWidget, DecimalWidget)
+ True
+ """
+
+ _FieldFactory = Decimal
+ _WidgetFactory = DecimalWidget
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ # widget has input, even if input is an empty string
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'123'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getInputValue(self):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = u'123.45'
+ self.assertEquals(self._widget.getInputValue(),
+ decimal.Decimal("123.45"))
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(DecimalWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_displaywidget.py (from rev 107373, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_displaywidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_displaywidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_displaywidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Generic Text Widgets tests
+
+$Id$
+"""
+import unittest
+from zope.interface.verify import verifyClass
+from zope.interface.exceptions import DoesNotImplement
+from zope.publisher.browser import TestRequest
+from zope.schema import TextLine
+from zope.testing.doctest import DocTestSuite
+
+from zope.formlib.widget import DisplayWidget, UnicodeDisplayWidget
+
+
+def test_implemented_interfaces():
+ """Make sure that the display widget implements the correct interfaces.
+
+ Like all browser-used widgets, DisplayWidget must implement
+ `IBrowserWidget`.
+
+ >>> from zope.app.form.browser.interfaces import IBrowserWidget
+ >>> verifyClass(IBrowserWidget, DisplayWidget)
+ True
+
+ But unlike most other widgets in this package, the display widget is *not*
+ an `IInputWidget`.
+
+ >>> from zope.formlib.interfaces import IInputWidget
+ >>> try:
+ ... verifyClass(IInputWidget, DisplayWidget)
+ ... except DoesNotImplement:
+ ... 'not implemented'
+ 'not implemented'
+ """
+
+def test_not_required():
+ """Make sure that display widgets are not required
+
+ >>> field = TextLine(title = u'Title',
+ ... __name__ = u'title',
+ ... default = u'<My Title>')
+ >>> widget = DisplayWidget(field, TestRequest())
+ >>> widget.required
+ False
+
+ """
+
+def test_value_escaping():
+ """Make sure that the returned values are correctly escaped.
+
+ First we need to create a field that is the context of the display widget.
+ >>> field = TextLine(title = u'Title',
+ ... __name__ = u'title',
+ ... default = u'<My Title>')
+
+ >>> field = field.bind(None)
+
+ Now we are ready to instantiate our widget.
+
+ >>> widget = DisplayWidget(field, TestRequest())
+
+ If no data was specified in the widget, the field's default value will be
+ chosen.
+
+ >>> widget()
+ u'<My Title>'
+
+ Now let's set a value and make sure that, when output, it is also
+ correctly escaped.
+
+ >>> widget.setRenderedValue(u'<Another Title>')
+ >>> widget()
+ u'<Another Title>'
+
+ When the value is the missing_value, the empty string should be
+ displayed::
+
+ >>> field = TextLine(title = u'Title',
+ ... __name__ = u'title',
+ ... required = False)
+
+ >>> field = field.bind(None)
+ >>> widget = DisplayWidget(field, TestRequest())
+ >>> widget.setRenderedValue(field.missing_value)
+
+ >>> widget()
+ ''
+
+ If there's no default for the field and the value is missing on
+ the bound object, the empty string should still be displayed::
+
+ >>> field = TextLine(title=u'Title',
+ ... __name__=u'title',
+ ... required=False)
+
+ >>> class Thing:
+ ... title = field.missing_value
+
+ >>> field = field.bind(Thing())
+ >>> widget = DisplayWidget(field, TestRequest())
+
+ >>> widget()
+ ''
+
+ """
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(DocTestSuite())
+ suite.addTest(DocTestSuite(
+ extraglobs={"DisplayWidget": UnicodeDisplayWidget}))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_intwidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_intwidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_intwidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_intwidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,65 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Integer Widget Tests
+
+$Id$
+"""
+import unittest
+from zope.testing import doctest
+from unittest import main, makeSuite
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import IntWidget
+from zope.formlib.interfaces import ConversionError, WidgetInputError
+from zope.interface.verify import verifyClass
+
+from zope.schema import Int
+
+
+class IntWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the int widget.
+
+ >>> verifyClass(IInputWidget, IntWidget)
+ True
+ """
+
+ _FieldFactory = Int
+ _WidgetFactory = IntWidget
+
+ def test_hasInput(self):
+ del self._widget.request.form['field.foo']
+ self.failIf(self._widget.hasInput())
+ # widget has input, even if input is an empty string
+ self._widget.request.form['field.foo'] = u''
+ self.failUnless(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'123'
+ self.failUnless(self._widget.hasInput())
+
+ def test_getInputValue(self):
+ self._widget.request.form['field.foo'] = u''
+ self.assertRaises(WidgetInputError, self._widget.getInputValue)
+ self._widget.request.form['field.foo'] = u'123'
+ self.assertEquals(self._widget.getInputValue(), 123)
+ self._widget.request.form['field.foo'] = u'abc'
+ self.assertRaises(ConversionError, self._widget.getInputValue)
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(IntWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_itemswidget.py (from rev 107377, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_itemswidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_itemswidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_itemswidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,595 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Select Widget Tests
+
+$Id$
+"""
+import unittest
+
+from zope.component.testing import PlacelessSetup
+from zope.interface import Interface, implements
+from zope.publisher.browser import TestRequest
+from zope.schema import Choice, List, Set, FrozenSet
+from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
+
+import zope.formlib.itemswidgets
+from zope.formlib.itemswidgets import ItemsWidgetBase
+from zope.formlib.itemswidgets import ItemDisplayWidget
+from zope.formlib.itemswidgets import ItemsMultiDisplayWidget
+from zope.formlib.itemswidgets import ListDisplayWidget
+from zope.formlib.itemswidgets import SetDisplayWidget
+from zope.formlib.itemswidgets import ItemsEditWidgetBase
+from zope.formlib.itemswidgets import SelectWidget, DropdownWidget
+from zope.formlib.itemswidgets import RadioWidget
+from zope.formlib.itemswidgets import ItemsMultiEditWidgetBase
+from zope.formlib.itemswidgets import MultiSelectWidget
+from zope.formlib.itemswidgets import OrderedMultiSelectWidget
+from zope.formlib.itemswidgets import MultiCheckBoxWidget
+from zope.formlib.tests.support import VerifyResults
+
+vocab = SimpleVocabulary(
+ [SimpleTerm(value, token, title) for value, token, title in (
+ ('one', 'token1', 'One'),
+ ('two', 'token2', 'Two'),
+ ('three', 'token3', 'Three'))])
+
+class ICollector(Interface):
+ choice = Choice(
+ title=u"Number",
+ description=u"The Number",
+ # we want to be able to distinguish between tokens and values
+ vocabulary=vocab,
+ required=True)
+
+ numbers = List(
+ title=u"Numbers",
+ description=u"The Numbers",
+ value_type=choice,
+ required=False)
+
+ letters = Set(
+ title=u"Letters",
+ description=u"The Letters",
+ value_type=choice,
+ required=False)
+
+ frozenLetters = FrozenSet(
+ title=u"Frozen Letters",
+ description=u"The Frozen Letters",
+ value_type=choice,
+ required=False)
+
+
+class Collector(object):
+ implements(ICollector)
+
+ def __init__(self, numbers=None):
+ self.numbers = numbers or []
+
+
+class ItemsWidgetBaseTest(VerifyResults, PlacelessSetup, unittest.TestCase):
+
+ _widget = ItemsWidgetBase
+ _field = ICollector.get('choice')
+ _vocabulary = _field.vocabulary
+
+ def _makeWidget(self, form=None, nums=None):
+ request = TestRequest(form=form or {})
+ collector = Collector(nums)
+ bound = self._field.bind(collector)
+ return self._widget(bound, self._vocabulary, request)
+
+ def test_setPrefix(self):
+ widget = self._makeWidget()
+ name = self._field.getName()
+ # Default prefix
+ self.assertEqual(widget._prefix, 'field.')
+ self.assertEqual(widget.name, 'field.%s' %name)
+ self.assertEqual(widget.empty_marker_name,
+ 'field.%s-empty-marker' %name)
+ # Declaring custom prefix
+ widget.setPrefix('foo')
+ self.assertEqual(widget._prefix, 'foo.')
+ self.assertEqual(widget.name, 'foo.%s' %name)
+ self.assertEqual(widget.empty_marker_name,
+ 'foo.%s-empty-marker' %name)
+ # Declaring empty prefix
+ widget.setPrefix('')
+ self.assertEqual(widget._prefix, '')
+ self.assertEqual(widget.name, name)
+ self.assertEqual(widget.empty_marker_name,
+ '%s-empty-marker' %name)
+
+ def test_convertTokensToValues(self):
+ widget = self._makeWidget()
+ self.assertEqual(widget.convertTokensToValues(['token1', 'token2']),
+ ['one', 'two'])
+
+
+class ItemDisplayWidgetTest(ItemsWidgetBaseTest):
+
+ _widget = ItemDisplayWidget
+
+ def test_setVocabulary(self):
+ widget = self._makeWidget()
+ self.assert_(widget.vocabulary is not None)
+ self.assertEqual(widget.vocabulary, self._field.vocabulary)
+
+ def test__call__(self):
+ widget = self._makeWidget()
+ self.assertEqual(widget(), '')
+ widget = self._makeWidget(form={'field.choice': 'token1'})
+ self.assertEqual(widget(), 'One')
+
+ def test_not_required(self):
+ self.failIf(self._makeWidget().required)
+
+
+class ItemsMultiDisplayWidgetTest(ItemsWidgetBaseTest):
+
+ _widget = ItemsMultiDisplayWidget
+ _field = ICollector.get('numbers')
+ _vocabulary = _field.value_type.vocabulary
+ _tag = 'ol'
+
+ def test__call__(self):
+ widget = self._makeWidget()
+ self.assertEqual(widget(), '')
+ widget = self._makeWidget(form={'field.numbers': ['token1', 'token2']})
+ self.assertEqual(
+ widget(),
+ '<%s id="field.numbers" >'
+ '<li>One</li>\n<li>Two</li>'
+ '</%s>' %(self._tag, self._tag))
+
+ def test_renderItems(self):
+ widget = self._makeWidget()
+ self.assertEqual(
+ widget.renderItems(['one', 'two']),
+ [u'<li>One</li>', u'<li>Two</li>'])
+ self.assertRaises(LookupError, widget.renderItems, 'one')
+ self.assertRaises(TypeError, widget.renderItems, 1)
+
+
+ def test_not_required(self):
+ numbers = List(value_type=ICollector['choice']).bind(Collector(None))
+ request = TestRequest()
+ widget = self._widget(numbers, self._vocabulary, request)
+ self.failIf(widget.required)
+
+
+class ListDisplayWidgetTest(ItemsMultiDisplayWidgetTest):
+ _widget = ListDisplayWidget
+ _tag = 'ol'
+
+
+class SetDisplayWidgetTest(ItemsMultiDisplayWidgetTest):
+ _widget = SetDisplayWidget
+ _tag = 'ul'
+
+
+class ItemsEditWidgetBaseTest(ItemsWidgetBaseTest):
+
+ _widget = ItemsEditWidgetBase
+
+ def test_div(self):
+ widget = self._makeWidget()
+ self.assertEqual(widget._div('', ''), '')
+ self.assertEqual(widget._div('foo', ''), '')
+ self.assertEqual(widget._div('', 'bar'), '<div>\nbar\n</div>')
+ self.assertEqual(widget._div('foo', 'bar'),
+ '<div class="foo">\nbar\n</div>')
+ self.assertEqual(widget._div('foo', 'bar', style='blah'),
+ '<div class="foo" style="blah">\nbar\n</div>')
+
+ def test_renderItem(self):
+ widget = self._makeWidget()
+ self.assertEqual(widget.renderItem('', 'Foo', 'foo', '', None),
+ '<option value="foo">Foo</option>')
+ self.assertEqual(widget.renderItem('', 'Foo', 'foo', '', 'klass'),
+ '<option class="klass" value="foo">Foo</option>')
+
+ def test_renderSelectedItem(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', '', None),
+ ['<option', 'value="foo"', 'selected="selected"', '>Foo</option>'])
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', '', 'klass'),
+ ['<option', 'class="klass"', 'value="foo"', 'selected="selected"',
+ '>Foo</option>'])
+
+ def test_renderItemsWithValues(self):
+ widget = self._makeWidget()
+ self.assertEqual(
+ widget.renderItemsWithValues(['one', 'two']),
+ [u'<option selected="selected" value="token1">One</option>',
+ u'<option selected="selected" value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ self.assertEqual(
+ widget.renderItemsWithValues([]),
+ [u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+
+# This test is disabled because it tests for the presense of a missfeature,
+# which has been removed. Did someone actually *want* this?
+## def test_error(self):
+## widget = self._makeWidget(form={'field.choice': 'ten'})
+## widget.setPrefix('field.')
+## widget._getFormValue()
+## self.assert_(isinstance(widget._error, ConversionError))
+
+ def test_hidden(self):
+ widget = self._makeWidget(form={'field.choice': 'token2'})
+ widget.setPrefix('field.')
+ widget.context.required = False
+ self.verifyResult(
+ widget.hidden(),
+ ['<input', 'type="hidden"', 'value="token2"', 'id="field.choice"',
+ 'name="field.choice"'])
+
+class SelectWidgetTest(ItemsEditWidgetBaseTest):
+
+ _widget = SelectWidget
+ _size = 5
+
+ def test__call__(self):
+ widget = self._makeWidget(form={'field.choice': 'token1'})
+ widget.setPrefix('field.')
+ widget.context.required = False
+ self.assertEqual(
+ widget(),
+ '<div>\n'
+ '<div class="value">\n'
+ '<select id="field.choice" name="field.choice" size="%i" >\n'
+ '<option value="">(no value)</option>\n'
+ '<option selected="selected" value="token1">One</option>\n'
+ '<option value="token2">Two</option>\n'
+ '<option value="token3">Three</option>\n'
+ '</select>\n</div>\n'
+ '<input name="field.choice-empty-marker" '
+ 'type="hidden" value="1" />\n</div>' %self._size)
+
+ def test_renderValue(self):
+ widget = self._makeWidget()
+ widget.setPrefix('field.')
+ self.assertEqual(
+ widget.renderValue('one'),
+ '<select id="field.choice" name="field.choice" size="%i" >\n'
+ '<option selected="selected" value="token1">One</option>\n'
+ '<option value="token2">Two</option>\n'
+ '<option value="token3">Three</option>\n'
+ '</select>' %self._size)
+
+ def test_renderItems(self):
+ widget = self._makeWidget()
+ widget.setPrefix('field.')
+ self.assertEqual(
+ widget.renderItems('one'),
+ [u'<option selected="selected" value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ self.assertEqual(
+ widget.renderItems('two'),
+ [u'<option value="token1">One</option>',
+ u'<option selected="selected" value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ self.assertEqual(
+ widget.renderItems(None),
+ [u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+
+ def test_renderItems_notRequired(self):
+ widget = self._makeWidget()
+ widget.setPrefix('field.')
+ widget.context.required = False
+ self.assertEqual(
+ widget.renderItems([]),
+ [u'<option value="">(no value)</option>',
+ u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+
+ def test_renderItems_firstItem(self):
+ widget = self._makeWidget()
+ widget.setPrefix('field.')
+ widget.firstItem = True
+ self.assertEqual(
+ widget.renderItems(widget._toFormValue(widget.context.missing_value)),
+ [u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+
+
+class DropdownWidgetTest(SelectWidgetTest):
+
+ _widget = DropdownWidget
+ _size = 1
+
+ def test_renderItems_firstItem(self):
+ widget = self._makeWidget()
+ widget.setPrefix('field.')
+ widget.firstItem = True
+ self.assertEqual(
+ widget.renderItems(widget._toFormValue(widget.context.missing_value)),
+ [u'<option selected="selected" value="">(no value)</option>',
+ u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ try:
+ # test BBB starting with 3.6.0
+ zope.formlib.itemswidgets.EXPLICIT_EMPTY_SELECTION = False
+ self.assertEqual(
+ widget.renderItems(widget._toFormValue(widget.context.missing_value)),
+ [u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ finally:
+ zope.formlib.itemswidgets.EXPLICIT_EMPTY_SELECTION = True
+
+
+class RadioWidgetTest(ItemsEditWidgetBaseTest):
+
+ _widget = RadioWidget
+
+ def test_renderItem(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderItem('', 'Foo', 'foo', 'bar', None),
+ ['<label', '<input', 'type="radio"', 'name="bar"', 'value="foo"',
+ 'class="radioType"', '> Foo'])
+ self.verifyResult(
+ widget.renderItem('bar', 'Foo', 'foo', 'bar', 'klass'),
+ ['<input', 'type="radio"', 'name="bar"', 'value="foo"',
+ 'class="klass radioType"', '> Foo'])
+
+ def test_renderSelectedItem(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', 'bar', 'klass'),
+ ['<label', '<input', 'type="radio"', 'name="bar"', 'value="foo"',
+ 'checked="checked"', '> Foo'])
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', 'bar', 'klass'),
+ ['<label', '<input', 'type="radio"', 'name="bar"', 'value="foo"',
+ 'class="klass radioType"', 'checked="checked"', '> Foo'])
+
+ def test_renderItemsWithValues(self):
+ widget = self._makeWidget()
+ items = widget.renderItemsWithValues(['one'])
+ values = [('token1','One'), ('token2','Two'), ('token3','Three')]
+ for index, item in enumerate(items):
+ self.verifyResult(
+ item,
+ ['<label', '<input', 'class="radioType"', 'name="field.choice"',
+ 'id="field.choice.%i' %index, 'type="radio"',
+ 'value="%s"' %values[index][0],
+ ' %s' %values[index][1]])
+ self.verifyResult(items[0], ['checked="checked"'])
+
+ def test_renderItems(self):
+ widget = self._makeWidget()
+ items = widget.renderItems('one')
+ values = [('token1','One'), ('token2','Two'), ('token3','Three')]
+ for index, item in enumerate(items):
+ self.verifyResult(
+ item,
+ ['<label', '<input', 'class="radioType"', 'name="field.choice"',
+ 'id="field.choice.%i' %index, 'type="radio"',
+ 'value="%s"' %values[index][0], ' %s' %values[index][1]])
+ self.verifyResult(items[0], ['checked="checked"'])
+
+ def test_renderItems_notRequired(self):
+ widget = self._makeWidget()
+ widget.context.required = False
+ items = widget.renderItems([])
+ values = [('', '(no value)'),
+ ('token1','One'),
+ ('token2','Two'),
+ ('token3','Three')]
+ for index, item in enumerate(items):
+ self.verifyResult(
+ item,
+ ['<label', '<input', 'class="radioType"',
+ 'name="field.choice"', 'type="radio"',
+ 'value="%s"' %values[index][0], ' %s' %values[index][1]])
+
+ def test_renderItems_firstItem(self):
+ widget = self._makeWidget()
+ items = widget.renderItems(
+ widget._toFormValue(widget.context.missing_value))
+ values = [('token1','One'), ('token2','Two'), ('token3','Three')]
+ for index, item in enumerate(items):
+ self.verifyResult(
+ item,
+ ['<label', '<input', 'class="radioType"',
+ 'name="field.choice"', 'id="field.choice.%i"' % index,
+ 'type="radio"', 'value="%s"' % values[index][0],
+ ' %s' % values[index][1]])
+
+ def test_renderValue(self):
+ widget = self._makeWidget()
+ self.verifyResult(widget.renderValue(None), ['<br /><label for='])
+ widget.orientation = 'horizontal'
+ self.verifyResult(widget.renderValue(None),
+ [' <label for='])
+
+
+class ItemsMultiEditWidgetBaseTest(ItemsEditWidgetBaseTest):
+
+ _widget = ItemsMultiEditWidgetBase
+ _field = ICollector.get('numbers')
+ _vocabulary = _field.value_type.vocabulary
+
+ def test_renderValue(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderValue(['one', 'two']),
+ ['<select', 'multiple="multiple"', 'name="field.numbers:list"',
+ 'size="5"', '><option', 'selected="selected"', 'value="token1"',
+ '>One</option>\n', 'value="token2"', '>Two</option>\n',
+ 'value="token3"', '>Three</option>', '</select>'])
+
+ def test_renderItemsWithValues(self):
+ widget = self._makeWidget()
+ self.assertEqual(
+ widget.renderItemsWithValues(['one', 'two']),
+ [u'<option selected="selected" value="token1">One</option>',
+ u'<option selected="selected" value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+ self.assertEqual(
+ widget.renderItemsWithValues([]),
+ [u'<option value="token1">One</option>',
+ u'<option value="token2">Two</option>',
+ u'<option value="token3">Three</option>'])
+
+# This test is disabled because it tests for the presense of a missfeature,
+# which has been removed. Did someone actually *want* this?
+## def test_error(self):
+## widget = self._makeWidget(form={'field.numbers': ['ten']})
+## widget.setPrefix('field.')
+## widget._getFormValue()
+## self.assert_(isinstance(widget._error, ConversionError))
+
+ def test_hidden(self):
+ widget = self._makeWidget(
+ form={'field.numbers': ['two','three']})
+ widget.setPrefix('field.')
+ widget.context.required = False
+ self.verifyResult(
+ widget.hidden(),
+ ['<input', 'type="hidden"', 'value="token2"', 'id="field.numbers"',
+ 'name="field.numbers:list"', 'value="token3"'])
+
+ def test_getInputValue(self):
+ widget = self._makeWidget(form={'field.numbers': ['token2', 'token3']})
+ widget.setPrefix('field.')
+ self.assertEqual(widget.getInputValue(), ['two', 'three'])
+
+ self._field = ICollector.get('letters')
+ widget = self._makeWidget(form={'field.letters-empty-marker': '1'})
+ widget.setPrefix('field.')
+ self.assertEqual(widget.getInputValue(), set([]))
+ widget = self._makeWidget(form={'field.letters': ['token2', 'token3']})
+ widget.setPrefix('field.')
+ self.assertEqual(widget.getInputValue(), set(['two', 'three']))
+
+ self._field = ICollector.get('frozenLetters')
+ widget = self._makeWidget(form={'field.frozenLetters-empty-marker':
+ '1'})
+ widget.setPrefix('field.')
+ field_value = widget.getInputValue()
+ self.assertEqual(field_value, frozenset())
+ widget = self._makeWidget(form={'field.frozenLetters':
+ ['token2', 'token3']})
+ widget.setPrefix('field.')
+ field_value = widget.getInputValue()
+ self.assertEqual(field_value, frozenset(['two', 'three']))
+ self.assert_(isinstance(field_value, frozenset))
+
+
+class MultiSelectWidgetTest(ItemsMultiEditWidgetBaseTest):
+
+ _widget = MultiSelectWidget
+
+
+class OrderedMultiSelectWidgetTest(ItemsMultiEditWidgetBaseTest):
+
+ _widget = OrderedMultiSelectWidget
+
+ def test_choices(self):
+ widget = self._makeWidget()
+ choices = [choice['text'] for choice in widget.choices()]
+ choices.sort()
+ self.assertEqual(choices, ['One', 'Three', 'Two'])
+
+ def test_selected(self):
+ widget = self._makeWidget(nums=['one'])
+ widget._data = ['two']
+ selected = [select['text'] for select in widget.selected()]
+ selected.sort()
+ self.assertEqual(selected, ['One', 'Two'])
+ widget._data = ['one']
+ selected = [select['text'] for select in widget.selected()]
+ selected.sort()
+ self.assertEqual(selected, ['One'])
+
+
+class MultiCheckBoxWidgetTest(ItemsMultiEditWidgetBaseTest):
+
+ _widget = MultiCheckBoxWidget
+
+ def test_renderItem(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderItem('', 'Foo', 'foo', 'bar', None),
+ ['<input', 'type="checkbox"', 'name="bar"', 'value="foo"',
+ 'class="checkboxType"', '> Foo'])
+ self.verifyResult(
+ widget.renderItem('bar', 'Foo', 'foo', 'bar', 'klass'),
+ ['<input', 'type="checkbox"', 'name="bar"', 'value="foo"',
+ 'class="klass checkboxType"', '> Foo'])
+
+ def test_renderSelectedItem(self):
+ widget = self._makeWidget()
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', 'bar', 'klass'),
+ ['<input', 'type="checkbox"', 'name="bar"', 'value="foo"',
+ 'checked="checked"', '> Foo'])
+ self.verifyResult(
+ widget.renderSelectedItem('', 'Foo', 'foo', 'bar', 'klass'),
+ ['<input', 'type="checkbox"', 'name="bar"', 'value="foo"',
+ 'class="klass checkboxType"', 'checked="checked"', '> Foo'])
+
+ def test_renderValue(self):
+ widget = self._makeWidget()
+ self.verifyResult(widget.renderValue(None), ['<br /><label for='])
+ widget.orientation='horizontal'
+ self.verifyResult(widget.renderValue(None),
+ [' <label for='])
+
+ def test_renderItemsWithValues(self):
+ widget = self._makeWidget()
+ items = widget.renderItemsWithValues(['one'])
+ values = [('token1','One'), ('token2','Two'), ('token3','Three')]
+ for index, item in enumerate(items):
+ self.verifyResult(
+ item,
+ ['<input', 'class="checkboxType',
+ 'id="field.numbers.%i"' %index, 'type="checkbox"',
+ 'value="%s"' % values[index][0],
+ '/> %s' % values[index][1]])
+
+ self.verifyResult(items[0], ['checked="checked"'])
+
+
+def test_suite():
+ suite = unittest.makeSuite(ItemDisplayWidgetTest)
+ suite.addTest(unittest.makeSuite(ItemsMultiDisplayWidgetTest))
+ suite.addTest(unittest.makeSuite(ListDisplayWidgetTest))
+ suite.addTest(unittest.makeSuite(SetDisplayWidgetTest))
+ suite.addTest(unittest.makeSuite(ItemsEditWidgetBaseTest))
+ suite.addTest(unittest.makeSuite(SelectWidgetTest))
+ suite.addTest(unittest.makeSuite(DropdownWidgetTest))
+ suite.addTest(unittest.makeSuite(RadioWidgetTest))
+ suite.addTest(unittest.makeSuite(ItemsMultiEditWidgetBaseTest))
+ suite.addTest(unittest.makeSuite(MultiSelectWidgetTest))
+ suite.addTest(unittest.makeSuite(OrderedMultiSelectWidgetTest))
+ suite.addTest(unittest.makeSuite(MultiCheckBoxWidgetTest))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest="test_suite")
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_multicheckboxwidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_multicheckboxwidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_multicheckboxwidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_multicheckboxwidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Multi-Checkbox Widget Tests
+
+$Id$
+"""
+import unittest
+from zope.testing import doctest
+from zope.interface import Interface, implements
+from zope.publisher.browser import TestRequest
+from zope.schema import Choice, List
+
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import MultiCheckBoxWidget
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.interface.verify import verifyClass
+
+class MultiCheckBoxWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the multi checkbox widget.
+
+ >>> verifyClass(IInputWidget, MultiCheckBoxWidget)
+ True
+ """
+
+ _WidgetFactory = MultiCheckBoxWidget
+ _FieldFactory = List
+
+ def setUpContent(self, desc=u'', title=u'Foo Title'):
+ class ITestContent(Interface):
+ foo = self._FieldFactory(
+ title=title,
+ description=desc,
+ value_type=Choice(values=[u'foo', u'bar'])
+ )
+ class TestObject(object):
+ implements(ITestContent)
+
+ self.content = TestObject()
+ field = ITestContent['foo']
+ field = field.bind(self.content)
+ request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl',
+ form={'field.foo': u'bar'})
+ self._widget = self._WidgetFactory(field, field.value_type.vocabulary,
+ request)
+
+ def testProperties(self):
+ self.assertEqual(self._widget.cssClass, "")
+ self.assertEqual(self._widget.extra, '')
+ self.assertEqual(self._widget.orientation, 'vertical')
+
+
+ def testRenderItem(self):
+ check_list = ('type="checkbox"', 'id="field.bar.',
+ 'name="field.bar"', 'value="foo"', 'Foo')
+ self.verifyResult(
+ self._widget.renderItem(0, 'Foo', 'foo', 'field.bar', None),
+ check_list)
+ check_list += ('checked="checked"',)
+ self.verifyResult(
+ self._widget.renderSelectedItem(
+ 0, 'Foo', 'foo', 'field.bar', None),
+ check_list)
+
+
+ def testRenderItems(self):
+ check_list = ('type="checkbox"', 'id="field.foo.',
+ 'name="field.foo"', 'value="bar"', 'bar',
+ 'value="foo"', 'foo', 'checked="checked"')
+ self.verifyResult('\n'.join(self._widget.renderItems(['bar'])),
+ check_list)
+
+
+ def testRender(self):
+ check_list = ('type="checkbox"', 'id="field.foo.',
+ 'name="field.foo"', 'value="bar"', 'bar',
+ 'value="foo"', 'foo', 'checked="checked"')
+ self.verifyResult(self._widget(), check_list)
+
+ check_list = ('type="hidden"', 'id="field.foo', 'name="field.foo:list"',
+ 'value="bar"')
+ self.verifyResult(self._widget.hidden(), check_list)
+ check_list = ('style="color: red"',) + check_list
+ self._widget.extra = 'style="color: red"'
+ self.verifyResult(self._widget.hidden(), check_list)
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(MultiCheckBoxWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_objectwidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_objectwidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_objectwidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_objectwidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,148 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Object Widget tests
+
+$Id$
+"""
+import unittest
+import sys
+from zope.component import testing
+from zope.interface import Interface, implements
+from zope.publisher.browser import TestRequest
+from zope.schema import Object, TextLine
+from zope.schema.interfaces import ITextLine
+from zope.testing import doctest
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.component import provideAdapter
+
+from zope.formlib.interfaces import IInputWidget, MissingInputError
+from zope.formlib.widgets import TextWidget, ObjectWidget
+from zope.formlib.tests.test_browserwidget import BrowserWidgetTest
+from zope.formlib.interfaces import IWidgetInputErrorView
+
+class ITestContact(Interface):
+ name = TextLine()
+ email = TextLine()
+
+class TestContact(object):
+ implements(ITestContact)
+
+class ObjectWidgetInputErrorView(object):
+ implements(IWidgetInputErrorView)
+
+ def __init__(self, error, request):
+ self.error = error
+ self.request = request
+
+ def snippet(self):
+ return repr(self.error)
+
+class ObjectWidgetTest(BrowserWidgetTest):
+ """Documents and tests the object widget.
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IInputWidget, ObjectWidget)
+ True
+ """
+
+ _FieldFactory = Object
+ def _WidgetFactory(self, context, request, **kw):
+ kw.update({'factory': TestContact})
+ return ObjectWidget(context, request, **kw)
+
+ def setUpContent(self, desc=u'', title=u'Foo Title'):
+ provideAdapter(TextWidget, (ITextLine, IDefaultBrowserLayer),
+ IInputWidget)
+
+ class ITestContent(Interface):
+ foo = self._FieldFactory(
+ ITestContact,
+ title=title,
+ description=desc
+ )
+ class TestObject(object):
+ implements(ITestContent)
+
+ self.content = TestObject()
+ self.field = ITestContent['foo']
+ 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):
+ super(ObjectWidgetTest, self).setUp()
+ self.field = Object(ITestContact, __name__=u'foo')
+ provideAdapter(TextWidget,
+ (ITextLine, IDefaultBrowserLayer),
+ IInputWidget)
+
+ def test_applyChanges(self):
+ self.request.form['field.foo.name'] = u'Foo Name'
+ self.request.form['field.foo.email'] = u'foo at foo.test'
+ widget = self._WidgetFactory(self.field, self.request)
+
+ self.assertEqual(widget.applyChanges(self.content), True)
+ self.assertEqual(hasattr(self.content, 'foo'), True)
+ self.assertEqual(isinstance(self.content.foo, TestContact), True)
+ self.assertEqual(self.content.foo.name, u'Foo Name')
+ self.assertEqual(self.content.foo.email, u'foo at foo.test')
+
+ def test_error(self):
+ provideAdapter(
+ ObjectWidgetInputErrorView,
+ (MissingInputError, TestRequest),
+ IWidgetInputErrorView)
+
+ widget = self._WidgetFactory(self.field, self.request)
+ self.assertRaises(MissingInputError, widget.getInputValue)
+ error_html = widget.error()
+ if sys.version_info < (2, 5):
+ self.failUnless("email: <zope.formlib.interfaces.Mis"
+ in error_html)
+ self.failUnless("name: <zope.formlib.interfaces.Miss"
+ in error_html)
+ else:
+ self.failUnless("email: MissingInputError(u'field.foo.email', u'', None)"
+ in error_html)
+ self.failUnless("name: MissingInputError(u'field.foo.name', u'', None)"
+ in error_html)
+
+ def test_applyChangesNoChange(self):
+ self.content.foo = TestContact()
+ self.content.foo.name = u'Foo Name'
+ self.content.foo.email = u'foo at foo.test'
+
+ self.request.form['field.foo.name'] = u'Foo Name'
+ self.request.form['field.foo.email'] = u'foo at foo.test'
+ widget = self._WidgetFactory(self.field, self.request)
+ widget.setRenderedValue(self.content.foo)
+
+ self.assertEqual(widget.applyChanges(self.content), False)
+ self.assertEqual(hasattr(self.content, 'foo'), True)
+ self.assertEqual(isinstance(self.content.foo, TestContact), True)
+ self.assertEqual(self.content.foo.name, u'Foo Name')
+ self.assertEqual(self.content.foo.email, u'foo at foo.test')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(ObjectWidgetTest),
+ doctest.DocFileSuite('../objectwidget.txt',
+ setUp=testing.setUp,
+ tearDown=testing.tearDown),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_passwordwidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_passwordwidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_passwordwidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_passwordwidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Password Widget Tests
+
+$Id$
+"""
+import unittest
+from zope.testing import doctest
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import PasswordWidget
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.interface.verify import verifyClass
+
+class PasswordWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the password widget.
+
+ >>> verifyClass(IInputWidget, PasswordWidget)
+ True
+ """
+
+ _WidgetFactory = PasswordWidget
+
+ def testProperties(self):
+ self.assertEqual(self._widget.tag, 'input')
+ self.assertEqual(self._widget.type, 'password')
+ self.assertEqual(self._widget.cssClass, '')
+ self.assertEqual(self._widget.extra, '')
+ self.assertEqual(self._widget.default, '')
+ self.assertEqual(self._widget.displayWidth, 20)
+ self.assertEqual(self._widget.displayMaxWidth, '')
+
+ def testRender(self):
+ value = 'Foo Value'
+ self._widget.setRenderedValue(value)
+ check_list = ('type="password"', 'id="field.foo"',
+ 'name="field.foo"', 'value=""', 'size="20"')
+ self.verifyResult(self._widget(), check_list)
+
+ def testHidden(self):
+ self.assertRaises(NotImplementedError, self._widget.hidden)
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(PasswordWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_radiowidget.py (from rev 107392, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_radiowidget.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_radiowidget.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_radiowidget.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,125 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Radio Widget Tests
+
+$Id$
+"""
+import unittest
+from zope.testing import doctest
+from zope.interface import Interface, implements
+from zope.interface.verify import verifyClass
+from zope.publisher.browser import TestRequest
+from zope.schema import Choice
+
+from zope.formlib.interfaces import IInputWidget
+from zope.formlib.widgets import RadioWidget
+from zope.formlib.tests.test_browserwidget import SimpleInputWidgetTest
+
+class RadioWidgetTest(SimpleInputWidgetTest):
+ """Documents and tests the radio widget.
+
+ >>> verifyClass(IInputWidget, RadioWidget)
+ True
+ """
+
+ _FieldFactory = Choice
+ _WidgetFactory = RadioWidget
+
+ def setUpContent(self, desc=u'', title=u'Foo Title'):
+ class ITestContent(Interface):
+ foo = self._FieldFactory(
+ title=title,
+ description=desc,
+ values=(u'foo', u'bar')
+ )
+ class TestObject(object):
+ implements(ITestContent)
+
+ self.content = TestObject()
+ field = ITestContent['foo']
+ field = field.bind(self.content)
+ request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl')
+ request.form['field.foo'] = u'Foo Value'
+ self._widget = self._WidgetFactory(field, field.vocabulary, request)
+
+ def testProperties(self):
+ self.assertEqual(self._widget.cssClass, "")
+ self.assertEqual(self._widget.extra, '')
+ self.assertEqual(self._widget.orientation, 'vertical')
+
+
+ def testRenderItem(self):
+ check_list = ('type="radio"', 'id="field.bar.0"',
+ 'name="field.bar"', 'value="foo"', 'Foo')
+ self.verifyResult(
+ self._widget.renderItem(0, 'Foo', 'foo', 'field.bar', None),
+ check_list)
+ check_list += ('checked="checked"',)
+ self.verifyResult(
+ self._widget.renderSelectedItem(
+ 0, 'Foo', 'foo', 'field.bar', None),
+ check_list)
+
+
+ def testRenderItems(self):
+ check_list = ('type="radio"', 'id="field.foo.0"', 'name="field.foo"',
+ 'value="bar"', 'bar', 'value="foo"', 'foo',
+ 'checked="checked"')
+ self.verifyResult('\n'.join(self._widget.renderItems('bar')),
+ check_list)
+
+
+ def testRender(self):
+ value = 'bar'
+ self._widget.setRenderedValue(value)
+ check_list = ('type="radio"', 'id="field.foo.0"',
+ 'name="field.foo"', 'value="bar"', 'bar',
+ 'value="foo"', 'foo', 'checked="checked"')
+ self.verifyResult(self._widget(), check_list)
+
+ check_list = ('type="hidden"', 'id="field.foo"',
+ 'name="field.foo"', 'value="bar"')
+ self.verifyResult(self._widget.hidden(), check_list)
+ check_list = ('style="color: red"',) + check_list
+ self._widget.extra = 'style="color: red"'
+ self.verifyResult(self._widget.hidden(), check_list)
+
+
+ def testHasInput(self):
+ self._widget.request.form.clear()
+ self.assert_(not self._widget.hasInput())
+ self._widget.request.form['field.foo-empty-marker'] = '1'
+ self.assert_(self._widget.hasInput())
+ self._widget.request.form['field.foo'] = u'Foo Value'
+ self.assert_(self._widget.hasInput())
+ del self._widget.request.form['field.foo-empty-marker']
+ self.assert_(self._widget.hasInput())
+
+
+ def testRenderEmptyMarker(self):
+ self.verifyResult(self._widget(), ('field.foo-empty-marker',))
+ self._widget.setRenderedValue(u'bar')
+ self.verifyResult(self._widget(), ('field.foo-empty-marker',))
+ self._widget.setRenderedValue(u'not a legal value')
+ self.verifyResult(self._widget(), ('field.foo-empty-marker',))
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(RadioWidgetTest),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Copied: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_source.py (from rev 107362, zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_source.py)
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_source.py (rev 0)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests/test_source.py 2009-12-30 22:26:15 UTC (rev 107397)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Source Widget Tests
+
+$Id$
+"""
+from zope.component import testing
+
+def test_suite():
+ from zope.testing import doctest
+ return doctest.DocFileSuite(
+ '../source.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown)
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='test_suite')
+
More information about the Zope3-Checkins
mailing list