[Zope3-checkins] CVS: Zope3/src/zope/app/browser/form/ftests - __init__.py:1.2 support.py:1.2 test_checkboxwidget.py:1.2 test_datetimewidget.py:1.2 test_filewidget.py:1.2 test_floatwidget.py:1.2 test_intwidget.py:1.2 test_textareawidget.py:1.2 test_textwidget.py:1.2

Garrett Smith garrett at mojave-corp.com
Wed Aug 13 18:29:09 EDT 2003


Update of /cvs-repository/Zope3/src/zope/app/browser/form/ftests
In directory cvs.zope.org:/tmp/cvs-serv9151/src/zope/app/browser/form/ftests

Added Files:
	__init__.py support.py test_checkboxwidget.py 
	test_datetimewidget.py test_filewidget.py test_floatwidget.py 
	test_intwidget.py test_textareawidget.py test_textwidget.py 
Log Message:
Made the following changes to the widget machinery:

- Renamed IWidget getData to getInputValue

getInputValue no longer accepts an 'optional' flag. If value is missing or is invalid, getInputValue will raise an error. Calls made to this method should be in a try...except block to handle such conditions.

- Renamed IWidget haveData to hasInput

- Added method hasValidInput to IWidget and widget implementations

- Renamed IWidget setData to setRenderedValue

- Added functional tests for some of the core widgets - additional ftests are needed

- Deleted the class PossibleEmptyMeansMissing - it's no longer needed

- Added deprecation tests for changes to widgets

- Some widgets were refactored to use the new framework correctly

These changes were based on the proposal:

 http://dev.zope.org/Zope3/ComponentArchitecture/WidgetsFormsSchemas

Not all the changes in the proposal are included in this commit. Specifically, getRawData/setRawData and the refactoring of the widget error classes are the two major changes not included in this commit.

=== Zope3/src/zope/app/browser/form/ftests/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:05 2003
+++ Zope3/src/zope/app/browser/form/ftests/__init__.py	Wed Aug 13 17:27:57 2003
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.


=== Zope3/src/zope/app/browser/form/ftests/support.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:05 2003
+++ Zope3/src/zope/app/browser/form/ftests/support.py	Wed Aug 13 17:27:57 2003
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import re
+from zope.configuration import xmlconfig
+
+def registerEditForm(schema):
+    xmlconfig.string("""
+        <configure xmlns="http://namespaces.zope.org/browser">
+          <include package="zope.app.browser.form" file="meta.zcml" />
+          <editform
+            name="edit.html"
+            schema="%s"
+            permission="zope.View" />
+        </configure>
+        """ % schema.__identifier__)
+
+
+def defineSecurity(class_, schema):
+    class_ = '%s.%s' % (class_.__module__, class_.__name__)
+    schema = schema.__identifier__
+    xmlconfig.string("""
+        <configure xmlns="http://namespaces.zope.org/zope">
+          <include package="zope.app.component" file="meta.zcml" />
+          <class class="%s">
+            <require 
+              permission="zope.Public" 
+              interface="%s"
+              set_schema="%s" />
+          </class>
+        </configure>
+        """ % (class_, schema, schema))
+
+
+def defineWidgetView(name, field_interface, widget_class):
+
+    field_interface = field_interface.__identifier__
+    widget_class = '%s.%s' % (widget_class.__module__, widget_class.__name__)
+    xmlconfig.string("""
+        <configure xmlns="http://namespaces.zope.org/browser">
+          <include package="zope.app.publisher.browser" file="meta.zcml" />
+          <page
+            name="%s"
+            permission="zope.Public"
+            allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
+            for="%s"
+            class="%s" />
+        </configure>
+        """ % (name, field_interface, widget_class))
+
+
+def patternExists(pattern, source, flags=0):
+
+    return re.search(pattern, source, flags) is not None
+
+
+def validationErrorExists(field, error_msg, source):
+
+    return patternExists(
+        'name="field.%s".*%s' % (field, error_msg), source)
+
+
+def missingInputErrorExists(field, source):
+
+    return validationErrorExists(field, 'Input is required', source)
+
+
+def invalidValueErrorExists(field, source):
+
+    # assumes this error is displayed for select elements
+    return patternExists(
+        'name="field.%s".*</select>.*Invalid value' % field, 
+        source, re.DOTALL)
+
+
+def updatedMsgExists(source):
+    
+    return patternExists('<p>Updated .*</p>', source)


=== Zope3/src/zope/app/browser/form/ftests/test_checkboxwidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:06 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_checkboxwidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,157 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from persistence import Persistent
+from transaction import get_transaction
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import Bool
+from zope.app.browser.form.widget import CheckBoxWidget
+
+from support import *
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class IBoolTest(Interface):
+
+    b1 = Bool(
+        required=True)
+
+    b2 = Bool(
+        required=False)
+
+
+registerEditForm(IBoolTest)
+
+
+class BoolTest(Persistent):
+
+    implements(IBoolTest)
+
+    def __init__(self):
+        self.b1 = True
+        self.b2 = False
+
+defineSecurity(BoolTest, IBoolTest)
+
+
+class Test(BrowserTestCase):
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', BoolTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # b1 and b2 should be displayed in checkbox input fields
+        self.assert_(patternExists(
+            '<input .* checked="checked".* name="field.b1".* ' \
+            'type="checkbox".* />',
+            response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.b2".* type="checkbox".* />',
+            response.getBody()))
+        # confirm that b2 is *not* checked
+        self.assert_(not patternExists(
+            '<input .* checked="checked".* name="field.b2".* ' \
+            'type="checkbox".* />',
+            response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', BoolTest())
+        get_transaction().commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.b1' : '',
+            'field.b2' : 'on' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.b1, False) 
+        self.assertEqual(object.b2, True)
+
+
+    def test_unexpected_value(self):
+        object = BoolTest()
+        object.b1 = True
+        object.b2 = True
+        self.getRootFolder().setObject('test', object)
+        get_transaction().commit()
+
+        # submit invalud type for text line
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.b1' : 'true',
+            'field.b2' : 'foo' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+
+        # values other than 'on' should be treated as False
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.b1, False) 
+        self.assertEqual(object.b2, False)
+
+
+    def test_missing_value(self):
+        # Note: checkbox widget doesn't support a missing value. This
+        # test confirms that one cannot set a Bool field to None.
+
+        self.getRootFolder().setObject('test', BoolTest())
+        get_transaction().commit()
+
+        # confirm default value of b1 is True
+        object = traverse(self.getRootFolder(), 'test')
+        self.assertEqual(object.b1, True)
+
+        # submit missing for b1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.b1' : CheckBoxWidget._missing })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # confirm b1 is not missing
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assert_(object.b1 != Bool.missing_value)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+
+


=== Zope3/src/zope/app/browser/form/ftests/test_datetimewidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:06 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_datetimewidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,244 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+import re
+from persistence import Persistent
+from transaction import get_transaction
+from datetime import datetime
+from zope.app.datetimeutils import parseDatetimetz, tzinfo
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import Datetime
+from zope.schema import EnumeratedDatetime
+
+from support import *
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class IDatetimeTest(Interface):
+
+    d1 = Datetime(
+        required=True,
+        min=datetime(2003, 1, 1, tzinfo=tzinfo(0)),
+        max=datetime(2020, 12, 31, tzinfo=tzinfo(0)))
+
+    d2 = Datetime(
+        required=False)
+
+    d3 = EnumeratedDatetime(
+        required=False,
+        allowed_values=(
+            datetime(2003, 9, 15, tzinfo=tzinfo(0)), 
+            datetime(2003, 10, 15, tzinfo=tzinfo(0))),
+        missing_value=datetime(2000, 1, 1, tzinfo=tzinfo(0)))
+
+registerEditForm(IDatetimeTest)
+
+
+class DatetimeTest(Persistent):
+
+    implements(IDatetimeTest)
+
+    def __init__(self):
+        self.d1 = datetime(2003, 4, 6, tzinfo=tzinfo(0))
+        self.d2 = datetime(2003, 8, 6, tzinfo=tzinfo(0))
+        self.d3 = None
+
+defineSecurity(DatetimeTest, IDatetimeTest)
+
+
+def getDateForField(field, source):
+    """Returns a datetime object for the specified field in source.
+    
+    Returns None if the field value cannot be converted to date.
+    """
+
+    # look in input element first
+    pattern = '<input .* name="field.%s".* value="(.*)".*>' % field
+    m = re.search(pattern, source)
+    if m is None:
+        # look in a select element
+        pattern = '<select .* name="field.%s".*>.*' \
+            '<option value="(.*)" selected>*.</select>' % field
+        m = re.search(pattern, source, re.DOTALL)
+        if m is None:
+            return None
+
+    try:
+        return parseDatetimetz(m.group(1))
+    except:
+        # ignore specifics
+        return None
+
+
+class Test(BrowserTestCase):
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+        object = traverse(self.getRootFolder(), 'test')
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm date values in form with actual values
+        self.assertEqual(getDateForField('d1', response.getBody()), object.d1)
+        self.assertEqual(getDateForField('d2', response.getBody()), object.d2)
+        self.assert_(getDateForField('d3', response.getBody()) is None)
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        d1 = datetime(2003, 2, 1, tzinfo=tzinfo(0))
+        d2 = datetime(2003, 2, 2, tzinfo=tzinfo(0))
+        d3 = datetime(2003, 10, 15, tzinfo=tzinfo(0))
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d1' : str(d1),
+            'field.d2' : str(d2),
+            'field.d3' : str(d3) })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+
+        self.assertEqual(object.d1, d1) 
+        self.assertEqual(object.d2, d2)
+        self.assertEqual(object.d3, d3)
+
+
+    def test_missing_value(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        # submit missing values for d2 and d3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d2' : '',
+            'field.d3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assert_(object.d2 is None) # default missing_value for dates
+        # 2000-1-1 is missing_value for d3
+        self.assertEqual(object.d3, datetime(2000, 1, 1, tzinfo=tzinfo(0)))
+
+
+    def test_required_validation(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        # submit missing values for required field d1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d1' : '',
+            'field.d2' : '',
+            'field.d3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('d1', response.getBody()))
+        self.assert_(not missingInputErrorExists('d2', response.getBody()))
+        self.assert_(not missingInputErrorExists('d3', response.getBody()))
+
+
+    def test_inalid_value(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        # submit a value for d3 that isn't allowed
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d3' : str(datetime(2003, 2, 1, tzinfo=tzinfo(0))) })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(invalidValueErrorExists('d3', response.getBody()))
+
+
+    def test_min_max_validation(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        # submit value for d1 that is too low
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d1' : str(datetime(2002, 12, 31, tzinfo=tzinfo(0))) })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('d1', 'Too small', 
+            response.getBody()))
+
+        # submit value for i1 that is too high
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d1' : str(datetime(2021, 1, 1, tzinfo=tzinfo(0))) })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('d1', 'Too big', 
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder().setObject('test', DatetimeTest())
+        get_transaction().commit()
+
+        # remember default values
+        object = traverse(self.getRootFolder(), 'test')
+        d1 = object.d1
+        d2 = object.d2
+        self.assert_(d2 is not None)
+        d3 = object.d3
+
+        # submit change with only d2 present -- note that required
+        # field d1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.d2' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.d1, d1)
+        self.assert_(object.d2 is None)
+        self.assertEqual(object.d3, d3)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+
+


=== Zope3/src/zope/app/browser/form/ftests/test_filewidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:06 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_filewidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,179 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from StringIO import StringIO
+from persistence import Persistent
+from transaction import get_transaction
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema.interfaces import IField, IEnumerated
+from zope.schema import Field, Enumerated
+
+from zope.app.browser.form.widget import FileWidget
+
+from support import *
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+class IFileField(IEnumerated, IField):
+    """Field for representing a file that can be edited by FileWidget."""
+
+
+class FileField(Enumerated, Field):
+
+    implements(IFileField)
+
+
+defineWidgetView('edit', IFileField, FileWidget)
+
+
+class IFileTest(Interface):
+
+    f1 = FileField()
+    f2 = FileField(required=False)
+
+registerEditForm(IFileTest)
+
+
+class FileTest(Persistent):
+
+    implements(IFileTest)
+
+    def __init__(self):
+        self.f1 = None
+        self.f2 = 'foo'
+
+defineSecurity(FileTest, IFileTest)
+
+
+class SampleTextFile(StringIO):
+
+    def __init__(self, buf, filename=''):
+        StringIO.__init__(self, buf)
+        self.filename = filename
+
+
+class Test(BrowserTestCase):
+
+    sampleText = "The quick brown fox\njumped over the lazy dog."
+    sampleTextFile = SampleTextFile(sampleText)
+
+    emptyFileName = 'empty.txt'
+    emptyFile = SampleTextFile('', emptyFileName)
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', FileTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # field should be displayed in a file input element
+        self.assert_(patternExists(
+            '<input .* name="field.f1".* type="file".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.f2".* type="file".*>', response.getBody()))
+
+
+    def test_submit_text(self):
+        self.getRootFolder().setObject('test', FileTest())
+        get_transaction().commit()
+        object = traverse(self.getRootFolder(), 'test')
+        self.assert_(object.f1 is None)
+        self.assertEqual(object.f2, 'foo')
+
+        # submit a sample text file
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : self.sampleTextFile,
+            'field.f2' : self.sampleTextFile })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.f1, self.sampleText)
+        self.assertEqual(object.f2, self.sampleText)
+
+
+    def XXX_test_invalid_value(self):
+        self.getRootFolder().setObject('test', FileTest())
+        get_transaction().commit()
+
+        # submit an invalid file value
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : 'not a file' })
+        self.assertEqual(response.getStatus(), 200)
+
+        print response.getBody()
+
+        self.assert_(validationErrorExists('f1', 
+            'Value is not a file object', response.getBody()))
+
+
+    def XXX_test_required_validation(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit missing values for required field s1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : sampleTextFile,
+            'field.f2' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('s1', response.getBody()))
+        self.assert_(not missingInputErrorExists('s2', response.getBody()))
+
+
+
+    def test_empty_file(self):
+        self.getRootFolder().setObject('test', FileTest())
+        get_transaction().commit()
+
+        # submit an empty text file
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f2' : self.emptyFile })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # new value for f1 should be field.missing_value (i.e, None)
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assert_(object.f1 is None)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+
+


=== Zope3/src/zope/app/browser/form/ftests/test_floatwidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:06 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_floatwidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,230 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from persistence import Persistent
+from transaction import get_transaction
+
+from support import *
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import Float
+from zope.schema import EnumeratedFloat
+
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class IFloatTest(Interface):
+
+    f1 = Float(
+        required=True,
+        min=1.1,
+        max=10.1)
+
+    f2 = Float(
+        required=False)
+
+    f3 = EnumeratedFloat(
+        required=False,
+        allowed_values=(0.0, 1.1, 2.1, 3.1, 5.1, 7.1, 11.1),
+        missing_value=0)
+
+registerEditForm(IFloatTest)
+
+
+class FloatTest(Persistent):
+
+    implements(IFloatTest)
+
+    def __init__(self):
+        self.f1 = None
+        self.f2 = 1.1
+        self.f3 = 2.1
+
+defineSecurity(FloatTest, IFloatTest)
+
+
+class Test(BrowserTestCase):
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # f1 and f2 should be displayed in text fields
+        self.assert_(patternExists(
+            '<input .* name="field.f1".* value="".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.f2".* value="1.1".*>', response.getBody()))
+
+        # f3 should be in a dropdown
+        self.assert_(patternExists(
+            '<select .* name="field.f3".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<option value="2.1" selected>2.1</option>', response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '1.123',
+            'field.f2' : '2.23456789012345',
+            'field.f3' : '11.1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.f1, 1.123) 
+        self.assertEqual(object.f2, 2.23456789012345)
+        self.assertEqual(object.f3, 11.1)
+
+
+    def test_missing_value(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit missing values for f2 and f3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '1.1',
+            'field.f2' : '',
+            'field.f3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.f1, 1.1) 
+        self.assertEqual(object.f2, None) # None is default missing_value
+        self.assertEqual(object.f3, 0)  # 0 is from f3.missing_value=0
+
+
+    def test_required_validation(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit missing values for required field f1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '',
+            'field.f2' : '',
+            'field.f3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('f1', response.getBody()))
+        self.assert_(not missingInputErrorExists('f2', response.getBody()))
+        self.assert_(not missingInputErrorExists('f3', response.getBody()))
+
+
+    def test_invalid_allowed_value(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit a value for f3 that isn't allowed
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f3' : '10000' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(invalidValueErrorExists('f3', response.getBody()))
+
+
+    def test_min_max_validation(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit value for f1 that is too low
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '-1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('f1', 'Too small', 
+            response.getBody()))
+
+        # submit value for f1 that is too high
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '1000.2' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('f1', 'Too big', 
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # confirm default values
+        object = traverse(self.getRootFolder(), 'test')
+        self.assert_(object.f1 is None)
+        self.assertEqual(object.f2, 1.1)
+        self.assertEqual(object.f3, 2.1)
+
+        # submit change with only f2 present -- note that required
+        # field f1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f2' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assert_(object.f1 is None) 
+        self.assert_(object.f2 is None)
+        self.assertEqual(object.f3, 2.1)
+
+
+    def test_conversion(self):
+        self.getRootFolder().setObject('test', FloatTest())
+        get_transaction().commit()
+
+        # submit value for f1 that cannot be convert to an float
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : 'foo' })
+        self.assertEqual(response.getStatus(), 200)
+        # XXX - reinstate when widget errors are cleaned up
+        # self.assert_(validationErrorExists('f1', 
+        #    'Invalid floating point data', response.getBody()))
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+


=== Zope3/src/zope/app/browser/form/ftests/test_intwidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:07 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_intwidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,285 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from persistence import Persistent
+from transaction import get_transaction
+
+from support import *
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import Int
+from zope.schema import EnumeratedInt
+
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class IIntTest(Interface):
+
+    i1 = Int(
+        required=True,
+        min=1,
+        max=10)
+
+    i2 = Int(
+        required=False)
+
+    i3 = EnumeratedInt(
+        required=False,
+        allowed_values=(0, 1, 2, 3, 5, 7, 11),
+        missing_value=0)
+
+registerEditForm(IIntTest)
+
+
+class IIntTest2(Interface):
+    """Used to test an unusual care where missing_value is -1 and
+    not in allowed_values."""
+
+    i1 = EnumeratedInt(
+        required=False,
+        missing_value=-1,
+        allowed_values=(10, 20, 30))
+
+registerEditForm(IIntTest2)
+
+
+class IntTest(Persistent):
+
+    implements(IIntTest)
+
+    def __init__(self):
+        self.i1 = None
+        self.i2 = 1
+        self.i3 = 2
+
+defineSecurity(IntTest, IIntTest)
+
+
+class IntTest2(Persistent):
+
+    implements(IIntTest2)
+
+    def __init__(self):
+        self.i1 = 10
+
+defineSecurity(IntTest2, IIntTest2)
+
+
+class Test(BrowserTestCase):
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # i1 and i2 should be displayed in text fields
+        self.assert_(patternExists(
+            '<input .* name="field.i1".* value="".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.i2".* value="1".*>', response.getBody()))
+
+        # i3 should be in a dropdown
+        self.assert_(patternExists(
+            '<select .* name="field.i3".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<option value="2" selected>2</option>', response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '1',
+            'field.i2' : '2',
+            'field.i3' : '3' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.i1, 1) 
+        self.assertEqual(object.i2, 2)
+        self.assertEqual(object.i3, 3)
+
+
+    def test_missing_value(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit missing values for i2 and i3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '1',
+            'field.i2' : '',
+            'field.i3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.i1, 1) 
+        self.assertEqual(object.i2, None) # None is default missing_value
+        self.assertEqual(object.i3, 0)  # 0 is from i3.missing_value=0
+
+
+    def test_alternative_missing_value(self):
+        """Tests the addition of an empty value at the top of the dropdown
+        that, when selected, updates the field with field.missing_value.
+        """
+    
+        self.getRootFolder().setObject('test', IntTest2()) # note alt. class
+        get_transaction().commit()
+
+        # display edit form
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm that i1 is has a blank item at top with value=""
+        self.assert_(patternExists(
+            '<select .* name="field.i1".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<option value=""></option>', response.getBody()))
+        self.assert_(patternExists(
+            '<option value="10" selected>10</option>', response.getBody()))
+
+        # submit form as if top item is selected
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '' })
+
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # confirm new value is -1 -- i1.missing_value
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.i1, -1) 
+
+
+    def test_required_validation(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit missing values for required field i1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '',
+            'field.i2' : '',
+            'field.i3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('i1', response.getBody()))
+        self.assert_(not missingInputErrorExists('i2', response.getBody()))
+        self.assert_(not missingInputErrorExists('i3', response.getBody()))
+
+
+    def test_invalid_allowed_value(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit a value for i3 that isn't allowed
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i3' : '12' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(invalidValueErrorExists('i3', response.getBody()))
+
+
+    def test_min_max_validation(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit value for i1 that is too low
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '-1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('i1', 'Too small', 
+            response.getBody()))
+
+        # submit value for i1 that is too high
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : '11' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('i1', 'Too big', 
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # confirm default values
+        object = traverse(self.getRootFolder(), 'test')
+        self.assert_(object.i1 is None)
+        self.assertEqual(object.i2, 1)
+        self.assertEqual(object.i3, 2)
+
+        # submit change with only i2 present -- note that required
+        # field i1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i2' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assert_(object.i1 is None) 
+        self.assert_(object.i2 is None)
+        self.assertEqual(object.i3, 2)
+
+
+    def test_conversion(self):
+        self.getRootFolder().setObject('test', IntTest())
+        get_transaction().commit()
+
+        # submit value for i1 that cannot be convert to an int
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.i1' : 'foo' })
+        self.assertEqual(response.getStatus(), 200)
+        # XXX reinstate when widget errors are fixed
+        # self.assert_(validationErrorExists('i1', 'Invalid integer data', 
+        #    response.getBody()))
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')


=== Zope3/src/zope/app/browser/form/ftests/test_textareawidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:07 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_textareawidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,235 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from persistence import Persistent
+from transaction import get_transaction
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import Text
+
+from support import *
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class ITextTest(Interface):
+
+    s1 = Text(
+        required=True,
+        min_length=2,
+        max_length=10)
+
+    s2 = Text(
+        required=False,
+        missing_value=u'')
+
+    s3 = Text(
+        required=False)
+
+registerEditForm(ITextTest)
+
+
+class TextTest(Persistent):
+
+    implements(ITextTest)
+
+    def __init__(self):
+        self.s1 = ''
+        self.s2 = u'foo'
+        self.s3 = None
+
+defineSecurity(TextTest, ITextTest)
+
+
+class Test(BrowserTestCase):
+
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # all fields should be displayed in text fields
+        self.assert_(patternExists(
+            '<textarea .* name="field.s1".*></textarea>', 
+            response.getBody()))
+        self.assert_(patternExists(
+            '<textarea .* name="field.s2".*>foo</textarea>', 
+            response.getBody()))
+        self.assert_(patternExists(
+            '<textarea .* name="field.s3".*></textarea>', 
+            response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'foo',
+            'field.s2' : u'bar',
+            'field.s3' : u'baz' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, u'foo') 
+        self.assertEqual(object.s2, u'bar')
+        self.assertEqual(object.s3, u'baz')
+
+
+    def test_inalid_type(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # submit invalid type for text
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : 'foo' }) # not unicode
+
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(patternExists(
+            'name="field.s1".*Wrong type', response.getBody()))
+
+
+    def test_missing_value(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # submit missing values for s2 and s3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'foo',
+            'field.s2' : '',
+            'field.s3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, u'foo') 
+        self.assertEqual(object.s2, u'')   # default missing_value
+        self.assertEqual(object.s3, None)  # None is s3's missing_value
+
+
+    def test_required_validation(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # submit missing values for required field s1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : '',
+            'field.s2' : '',
+            'field.s3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('s1', response.getBody()))
+        self.assert_(not missingInputErrorExists('s2', response.getBody()))
+        self.assert_(not missingInputErrorExists('s3', response.getBody()))
+
+
+    def test_length_validation(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # submit value for s1 that is too short
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'a' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(patternExists(
+            'name="field.s1".*Too short', response.getBody()))
+
+        # submit value for s1 that is too long
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'12345678901' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('s1', 'Too long', 
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # confirm default values
+        object = traverse(self.getRootFolder(), 'test')
+        self.assertEqual(object.s1, '')
+        self.assertEqual(object.s2, u'foo')
+        self.assert_(object.s3 is None)
+
+        # submit change with only s2 present -- note that required
+        # field s1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s2' : u'bar' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, '')
+        self.assertEqual(object.s2, u'bar')
+        self.assert_(object.s3 is None)
+
+
+    def test_conversion(self):
+        self.getRootFolder().setObject('test', TextTest())
+        get_transaction().commit()
+
+        # confirm that line terminators are converted correctly on post
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s2' : u'line1\r\nline2' }) # CRLF per RFC 822
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s2, u'line1\nline2')
+
+        # confirm conversion to HTML
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(patternExists('line1\r\nline2', response.getBody()))
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+


=== Zope3/src/zope/app/browser/form/ftests/test_textwidget.py 1.1 => 1.2 ===
--- /dev/null	Wed Aug 13 17:29:08 2003
+++ Zope3/src/zope/app/browser/form/ftests/test_textwidget.py	Wed Aug 13 17:27:58 2003
@@ -0,0 +1,228 @@
+##############################################################################
+#
+# 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.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.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import unittest
+from persistence import Persistent
+from transaction import get_transaction
+
+from zope.interface import Interface
+from zope.interface import implements
+
+from zope.schema import TextLine
+from zope.schema import EnumeratedTextLine
+
+from support import *
+from zope.app.traversing import traverse
+
+from zope.testing.functional import BrowserTestCase
+
+
+class ITextLineTest(Interface):
+
+    s1 = TextLine(
+        required=True,
+        min_length=2,
+        max_length=10)
+
+    s2 = TextLine(
+        required=False,
+        missing_value=u'')
+
+    s3 = EnumeratedTextLine(
+        required=False,
+        allowed_values=(u'Bob', u'is', u'Your', u'Uncle'))
+
+registerEditForm(ITextLineTest)
+
+
+class TextLineTest(Persistent):
+
+    implements(ITextLineTest)
+
+    def __init__(self):
+        self.s1 = ''
+        self.s2 = u'foo'
+        self.s3 = None
+
+defineSecurity(TextLineTest, ITextLineTest)
+
+
+class Test(BrowserTestCase):
+
+    def test_display_editform(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # s1 and s2 should be displayed in text fields
+        self.assert_(patternExists(
+            '<input .* name="field.s1".* value="".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.s2".* value="foo".*>', response.getBody()))
+
+        # s3 should be in a dropdown
+        self.assert_(patternExists(
+            '<select .* name="field.s3".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<option value="" selected></option>', response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'foo',
+            'field.s2' : u'bar',
+            'field.s3' : u'Uncle' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, u'foo') 
+        self.assertEqual(object.s2, u'bar')
+        self.assertEqual(object.s3, u'Uncle')
+
+
+    def test_inalid_type(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit invalud type for text line
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : 'foo' }) # not unicode
+
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(patternExists(
+            'name="field.s1".*Wrong type', response.getBody()))
+
+
+    def test_missing_value(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit missing values for s2 and s3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'foo',
+            'field.s2' : u'',
+            'field.s3' : u'' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, u'foo')
+        self.assertEqual(object.s2, u'')   # default missing_value
+        self.assertEqual(object.s3, None)  # None is s3's missing_value
+
+
+    def test_required_validation(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit missing values for required field s1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : '',
+            'field.s2' : '',
+            'field.s3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(missingInputErrorExists('s1', response.getBody()))
+        self.assert_(not missingInputErrorExists('s2', response.getBody()))
+        self.assert_(not missingInputErrorExists('s3', response.getBody()))
+
+
+    def test_inalid_value(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit a value for s3 that isn't allowed
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s3' : u'Bob is *Not* My Uncle' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(invalidValueErrorExists('s3', response.getBody()))
+
+
+    def test_length_validation(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # submit value for s1 that is too short
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'a' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(patternExists(
+            'name="field.s1".*Too short', response.getBody()))
+
+        # submit value for s1 that is too long
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s1' : u'12345678901' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('s1', 'Too long', 
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder().setObject('test', TextLineTest())
+        get_transaction().commit()
+
+        # confirm default values
+        object = traverse(self.getRootFolder(), 'test')
+        self.assertEqual(object.s1, '')
+        self.assertEqual(object.s2, u'foo')
+        self.assert_(object.s3 is None)
+
+        # submit change with only s2 present -- note that required
+        # field s1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.s2' : u'bar' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+        
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        object._p_jar.sync()
+        self.assertEqual(object.s1, '')
+        self.assertEqual(object.s2, u'bar')
+        self.assert_(object.s3 is None)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+




More information about the Zope3-Checkins mailing list