[Zope3-checkins] SVN: Zope3/branches/mkerrin-webdav/src/zope/app/dav/ Added tests for the COPY method. These tests highlighted some

Michael Kerrin michael.kerrin at openapp.biz
Fri Jan 13 06:50:09 EST 2006


Log message for revision 41295:
  Added tests for the COPY method. These tests highlighted some
  bugs which have being fixed.
  
  Also fixed a few tests for the widgets.
  

Changed:
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/copy.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/ifhandler.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_common_if.py
  A   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_copy.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_mkcol.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/unitfixtures.py
  U   Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py

-=-
Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/copy.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/copy.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/copy.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -19,7 +19,6 @@
 
 from urlparse import urlsplit
 
-from zope.publisher.interfaces import NotFound
 from zope.app import zapi
 from zope.app.copypastemove.interfaces import IObjectMover, IObjectCopier
 from zope.app.publication.http import MethodNotAllowed
@@ -27,6 +26,8 @@
 from zope.app.traversing.api import traverse, getRoot
 from zope.app.traversing.interfaces import TraversalError
 
+from interfaces import IIfHeader
+
 class COPY(object):
     def __init__(self, context, request):
         self.context = context
@@ -61,7 +62,7 @@
         elif overwrite == 'f':
             overwrite = False
         else:
-            self.requset.response.setStatus(400)
+            self.request.response.setStatus(400)
             return ''
 
         # find destination if it exists and if it
@@ -70,9 +71,6 @@
         try:
             destob = traverse(getRoot(self.context), destpath)
             exists = True
-        except NotFound:
-            destob = None
-            exists = False
         except TraversalError:
             destob = None
             exists = False
@@ -80,21 +78,24 @@
         if destob is not None and not overwrite:
             self.request.response.setStatus(412)
             return ''
+        elif destob is not None and destob is self.context:
+            self.request.response.setStatus(403)
+            return ''            
         elif destob is not None:
             ifparser = zapi.queryMultiAdapter((destob, self.request), IIfHeader)
             if ifparser is not None and not ifparser():
                 self.request.response.setStatus(423)
                 return ''
+
             # we need to delete this object
-            raise NotImplementedError, "please delete the destination object"
+            parent = destob.__parent__
+            del parent[destob.__name__]
 
         # check parent
         parentpath = destpath.split('/')
         destname   = parentpath.pop()
         try:
             parent = traverse(getRoot(self.context), parentpath)
-        except NotFound:
-            parent = None
         except TraversalError:
             parent = None
         if parent is None:
@@ -102,7 +103,6 @@
             return ''
 
         if not copier.copyableTo(parent):
-            # XXX - should this be 405 ???
             self.request.response.setStatus(409)
             return ''
 

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/ifhandler.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/ifhandler.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/ifhandler.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -109,13 +109,14 @@
 
     def __call__(self):
         ifhdr = self.request.getHeader('if', None)
-        if ifhdr is None:
-            return True
 
         lockable = ILockable(self.context)
         if not lockable.locked():
             return True
 
+        if ifhdr is None:
+            return False
+
         lockinfo = lockable.getLockInfo()
 
         tags = self.ifParser(ifhdr)

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/locking.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -107,9 +107,6 @@
     def getDepth(self):
         return self._depth
 
-    def setDepth(self, depth):
-        self._depth = depth
-
     def getTimeout(self):
         timeoutheader = self.request.getHeader('timeout', 'infinity')
 

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/propfind.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -188,8 +188,15 @@
             if not iface:
                 for name in props:
                     if self.oprops:
+                        status = 200
                         el = self.oprops.renderProperty(ns, ns_prefix, name)
-                        re.addPropertyByStatus(ns, ns_prefix, el, 200)
+                        if el is None:
+                            # We can't add a None property in the MultiStatus
+                            # utility so add an empty property registered has
+                            # a 404 stats not found property.
+                            status = 404
+                            el = re.createEmptyElement(ns, ns_prefix, name)
+                        re.addPropertyByStatus(ns, ns_prefix, el, status)
                     else:
                         el = re.createEmptyElement(ns, ns_prefix, name)
                         re.addPropertyByStatus(ns, ns_prefix, el, 404)

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_common_if.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_common_if.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_common_if.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -143,6 +143,13 @@
         # context not locked -> true
         self.assertEqual(ifparser(), True)
 
+    def test_on_locked_file_no_header(self):
+        request = TestRequest()
+        context = File('some content', 'text/plain')
+        lockinfo = self._lockcontent(context)
+        ifparser = IfParser(context, request)
+        self.assertEqual(ifparser(), False)
+
     def test_on_locked_file_no_token(self):
         request = TestRequest(**{'IF': '(<%s>)' % self.token})
         context = File('some content', 'text/plain')

Added: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_copy.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_copy.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_copy.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -0,0 +1,266 @@
+##############################################################################
+#
+# Copyright (c) 2005 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 Copying
+
+$Id$
+"""
+import unittest
+
+from zope.interface import Interface
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces.http import IHTTPRequest
+from zope.security.testing import Principal, Participation
+from zope.security.management import newInteraction, endInteraction, \
+     queryInteraction
+from zope.app.testing import ztapi
+from zope.app.traversing.api import traverse
+from zope.app.traversing.interfaces import TraversalError
+from zope.app.component.testing import PlacefulSetup
+
+from zope.app.locking.interfaces import ILockable, ILockStorage
+from zope.app.locking.storage import PersistentLockStorage
+from zope.app.locking.adapter import LockingAdapterFactory
+from zope.app.keyreference.interfaces import IKeyReference
+from zope.app.copypastemove import ObjectCopier
+from zope.app.copypastemove.interfaces import IObjectCopier
+
+from zope.app.dav.copy import COPY
+from zope.app.dav.interfaces import IIfHeader
+from zope.app.dav.ifhandler import IfParser
+
+from test_locking import FakeKeyReference
+from unitfixtures import File, Folder, ConstraintFolder
+
+class TestDAVCopy(PlacefulSetup, unittest.TestCase):
+
+    def setUp(self):
+        PlacefulSetup.setUp(self)
+        PlacefulSetup.buildFolders(self)
+
+        ztapi.provideAdapter(Interface, IObjectCopier, ObjectCopier)
+
+        # locking
+        ztapi.provideAdapter(Interface, IKeyReference, FakeKeyReference)
+        ztapi.provideAdapter(Interface, ILockable, LockingAdapterFactory)
+
+        storage = self.storage = PersistentLockStorage()
+        ztapi.provideUtility(ILockStorage, storage)
+
+        ztapi.provideAdapter((Interface, IHTTPRequest), IIfHeader, IfParser)
+
+    def tearDown(self):
+        PlacefulSetup.tearDown(self)
+        del self.storage
+
+    def test_copy_file(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        content = 'this is some content'
+        file = File('bla', 'text/plain', content, container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        self.assertRaises(TraversalError, traverse, container, 'copy_bla')
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/folder1/copy_bla'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+        # check for 201 status since the new file will be created.
+        self.assertEqual(response.getStatus(), 201)
+        newfile = traverse(container, 'copy_bla')
+        self.assertEqual(newfile.data, content)
+
+    def test_copy_file_overwrite(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        file = File('bla', 'text/plain', 'this is some content', container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        copy_file = File('copy_bla', 'text/plain', 'this is the second file',
+                         container)
+        container['copy_bla'] = copy_file
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/folder1/copy_bla',
+                                         'OVERWRITE': 'T'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+        # check for 204 status since the no file is created.
+        self.assertEqual(response.getStatus(), 204)
+        newfile = traverse(container, 'copy_bla')
+        self.assertEqual(newfile.data, 'this is some content')
+
+    def test_copy_file_no_overwrite(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        file = File('bla', 'text/plain', 'this is some content', container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        copy_file = File('copy_bla', 'text/plain', 'this is the second file',
+                         container)
+        container['copy_bla'] = copy_file
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/folder1/copy_bla',
+                                         'OVERWRITE': 'F'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+
+        # 412 - precondition failed since overwrite is False.
+        self.assertEqual(response.getStatus(), 412)
+        newfile = traverse(container, 'copy_bla')
+        self.assertEqual(newfile.data, 'this is the second file')
+
+    def test_invalid_copy_request(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        content = 'this is some content'
+        file = File('bla', 'text/plain', content, container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/blafolder/copy_bla',
+                                         'OVERWRITE': 'X'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+        # check for 201 status since the new file will be created.
+        self.assertEqual(response.getStatus(), 400)
+
+        # now test a missing destination header.
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'OVERWRITE': 'T'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+        # check for 201 status since the new file will be created.
+        self.assertEqual(response.getStatus(), 400)
+
+    def test_no_destination_parent(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        content = 'this is some content'
+        file = File('bla', 'text/plain', content, container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        self.assertRaises(TraversalError, traverse, container, 'copy_bla')
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/blafolder/copy_bla'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+        # check for 201 status since the new file will be created.
+        self.assertEqual(response.getStatus(), 409)
+
+    def test_destination_file_locked(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        file = File('bla', 'text/plain', 'this is some content', container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        dest_file = File('copy_bla', 'text/plain', 'this is the second file',
+                         container)
+        container['copy_bla'] = dest_file
+        dest_file = traverse(container, 'copy_bla')
+
+        # now lock dest_file
+        mparticipation = Participation(Principal('michael'))
+        if queryInteraction():
+            endInteraction()
+        newInteraction(mparticipation)
+        lockable = ILockable(dest_file)
+        lockable.lock()
+        endInteraction()
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/folder1/copy_bla',
+                                         'OVERWRITE': 'T'})
+        response = request.response
+
+        copier = COPY(file, request)
+        copier.COPY()
+
+        # 423 - locked
+        self.assertEqual(response.getStatus(), 423)
+        newfile = traverse(container, 'copy_bla')
+        self.assertEqual(newfile.data, 'this is the second file')
+
+    def test_not_copyableTo(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        file = File('bla', 'text/plain', 'this is some content', container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        # the ConstraintFolder only allows implementations of IFolder to be
+        # added to it - so by copying a file into this folder we should get
+        # a conflict and hence a 409 response status.
+        folder = ConstraintFolder()
+        root['nofilefolder'] = folder
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/nofilefolder/bla',
+                                         'OVERWRITE': 'T'})
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+
+        # conflict - a resource can't be created at the destination.
+        self.assertEqual(response.getStatus(), 409)
+
+    def test_source_dest_same(self):
+        root = self.rootFolder
+        container = traverse(root, 'folder1')
+        file = File('bla', 'text/plain', 'this is some content', container)
+        container['bla'] = file
+        file = traverse(container, 'bla')
+
+        request = TestRequest('/folder1/bla',
+                              environ = {'REQUEST_METHOD': 'COPY',
+                                         'DESTINATION': '/folder1/bla',
+                                         })
+        response = request.response
+        copier = COPY(file, request)
+        copier.COPY()
+
+        # 403 (Forbidden) _ The source and destination URIs are the same.
+        self.assertEqual(response.getStatus(), 403)
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(TestDAVCopy),
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest = 'test_suite')


Property changes on: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_copy.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_mkcol.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_mkcol.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_mkcol.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -30,7 +30,8 @@
 
 from zope.app.http.put import NullResource
 from zope.app.dav import mkcol
-from zope.app.dav.tests.test_propfind import _createRequest, File
+from zope.app.dav.tests.test_propfind import _createRequest
+from unitfixtures import File
 
 class TestPlacefulMKCOL(PlacefulSetup, TestCase):
 

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_propfind.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -500,6 +500,44 @@
         %s</prop>''' % expect
         self._checkPropfind(zpt, req, expect)
 
+    def test_propfind_opaque_without_property(self):
+        # test opaque properties when requested property is not in the current
+        # opaque annotation
+        root = self.rootFolder
+        zpt = traverse(root, 'zpt')
+        oprops = IDAVOpaqueNamespaces(zpt)
+        oprops[u'http://foo/bar'] = {u'egg': '<egg>spam</egg>'}
+
+        ## self._checkPropfind(zpt, req, expect)
+        body = '''<?xml version="1.0" ?>
+        <propfind xmlns="DAV:">
+        <prop xmlns:foo="http://foo/bar"><foo:srambleegg /></prop>
+        </propfind>
+        '''
+        depth = '0'
+        request = _createRequest(body = body,
+                                 headers = {'Content-type': 'text/xml',
+                                            'Depth': depth})
+        resource_url = zapi.absoluteURL(zpt, request)
+        resp = '''<?xml version="1.0" encoding="utf-8"?>
+        <multistatus xmlns="DAV:"><response>
+        <href>%(resource_url)s</href>
+        <propstat>
+        <prop xmlns:a0="http://foo/bar"><srambleegg xmlns="a0"/>
+        </prop>
+        <status>HTTP/1.1 404 Not Found</status>
+        </propstat></response></multistatus>
+        ''' % {'resource_url': resource_url}
+
+        pfind = propfind.PROPFIND(zpt, request)
+        pfind.PROPFIND()
+
+        self.assertEqual(request.response.getStatus(), 207)
+        self.assertEqual(pfind.getDepth(), depth)
+        s1 = normalize_xml(request.response.consumeBody())
+        s2 = normalize_xml(resp)
+        self.assertEqual(s1, s2)
+
     def test_propfind_opaque_simple(self):
         root = self.rootFolder
         zpt = traverse(root, 'zpt')

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/test_widget.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -11,18 +11,19 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""
+"""XXX - the tests in this file should be made a lot clearer.
+
 $Id$
 """
 __docformat__ = 'restructuredtext'
 
-from datetime import datetime
+import datetime
 from xml.dom import minidom
 from unittest import TestSuite, main, makeSuite, TestCase
 
 from zope.interface import Interface, implements
 from zope.interface.verify import verifyClass
-from zope.schema import Text, Datetime, List
+from zope.schema import Text, Datetime, Date, List, Tuple
 from zope.schema import ValidationError
 from zope.publisher.browser import TestRequest
 from zope.testing.doctest import DocTestSuite
@@ -32,7 +33,7 @@
 
 from zope.app.dav.interfaces import IDAVWidget
 from zope.app.dav.widget import DAVWidget, TextDAVWidget, DatetimeDAVWidget, \
-     XMLEmptyElementListDAVWidget
+     DateDAVWidget, XMLEmptyElementListDAVWidget, TupleDAVWidget
 
 
 class DAVWidgetTest(placelesssetup.PlacelessSetup, TestCase):
@@ -62,10 +63,6 @@
 
     def test_widget_input(self):
         content = self.test_content
-        # try multiple bad content
-        bad_contents = self.test_bad_contents
-        if not isinstance(bad_contents, list):
-            bad_contents = [bad_contents]
 
         self.failIf(self._widget.hasInput())
         self._widget.setRenderedValue(content)
@@ -73,11 +70,11 @@
         self.assert_(self._widget.hasValidInput())
         self.assertEqual(self._widget.getInputValue(), content)
 
-        for bad_content in bad_contents:
-            self._widget.setRenderedValue(bad_content)
-            self.assert_(self._widget.hasInput())
-            self.failIf(self._widget.hasValidInput())
-            self.assertRaises(WidgetInputError, self._widget.getInputValue)
+    def _test_widget_bad_input(self, propel):
+        self._widget.setProperty(propel)
+        self.assert_(self._widget.hasInput())
+        self.failIf(self._widget.hasValidInput())
+        self.assertRaises(WidgetInputError, self._widget.getInputValue)
 
     def test_widget_apply_content(self):
         content = self.test_content
@@ -92,27 +89,65 @@
     _WidgetFactory = TextDAVWidget
 
     test_content = u'This is some text content'
-    test_bad_contents = 10
 
-
 class DatetimeDAVWidgetTest(DAVWidgetTest):
     _WidgetFactory = DatetimeDAVWidget
     _FieldFactory = Datetime
 
-    test_content = datetime.fromtimestamp(1131234842)
-    test_bad_contents = [10, u'This is bad content']
+    test_content = datetime.datetime.fromtimestamp(1131234842)
 
     def test_widget_input(self):
-        date = datetime(1999, 12, 31, 23, 59, 59)
+        date = datetime.datetime(1999, 12, 31, 23, 59, 59)
+        # date.strftime = '1999-12-31 23:59:59Z'
+
         doc = minidom.Document()
         propel = doc.createElement('foo')
-        # date.strftime = '1999-12-31 23:59:59Z'
         propel.appendChild(doc.createTextNode(date.strftime('%F')))
         self._widget.setProperty(propel)
-        ## self._widget._value == date
-        ## TypeError: can't compare offset-naive and offset-aware datetimes
+        value = self._widget.getInputValue()
+        fmt = '%y%m%d-000000'
+        self.assertEqual(date.strftime(fmt), value.strftime(fmt))
 
+        doc = minidom.Document()
+        propel = doc.createElement('foo')
+        propel.appendChild(
+            doc.createTextNode(date.strftime('%a,  %d  %b %Y %H:%M:%S')))
+        self._widget.setProperty(propel)
+        value = self._widget.getInputValue()
+        fmt = '%y%m%d-%H%M%S'
+        self.assertEqual(date.strftime(fmt), value.strftime(fmt))
 
+    def test_widget_bad_input(self):
+        doc = minidom.Document()
+        propel = doc.createElement('foo')
+        propel.appendChild(doc.createTextNode('invalid datetime content'))
+        super(DatetimeDAVWidgetTest, self)._test_widget_bad_input(propel)
+
+
+class DateDAVWidgetTest(DAVWidgetTest):
+    _WidgetFactory = DateDAVWidget
+    _FieldFactory  = Date
+
+    test_content = datetime.date.fromtimestamp(1131234842)
+
+    def test_widget_input(self):
+        dateinst = datetime.datetime(1999, 12, 31, 23, 59, 59).date()
+        doc = minidom.Document()
+        propel = doc.createElement('foo')
+        # date.strftime = '1999-12-31 23:59:59Z'
+        propel.appendChild(doc.createTextNode(dateinst.strftime('%F')))
+        self._widget.setProperty(propel)
+
+        value = self._widget.getInputValue()
+        self.assertEqual(value, dateinst)
+
+    def test_widget_bad_input(self):
+        doc = minidom.Document()
+        propel = doc.createElement('foo')
+        propel.appendChild(doc.createTextNode('invalid date content'))
+        super(DateDAVWidgetTest, self)._test_widget_bad_input(propel)
+
+
 class XMLEmptyElementListDAVWidgetTest(DAVWidgetTest):
     _WidgetFactory = XMLEmptyElementListDAVWidget
     _FieldFactory = List
@@ -121,11 +156,21 @@
     test_bad_contents = [10, u'hello']
 
 
+class TupleDAVWidgetTest(DAVWidgetTest):
+    _WidgetFactory = TupleDAVWidget
+    _FieldFactory = Tuple
+
+    test_content = (u'hello', u'there')
+    test_bad_contents = [10, u'hello']
+
+
 def test_suite():
     return TestSuite((
         makeSuite(TextDAVWidgetTest),
         makeSuite(DatetimeDAVWidgetTest),
+        makeSuite(DateDAVWidgetTest),
         makeSuite(XMLEmptyElementListDAVWidgetTest),
+        makeSuite(TupleDAVWidgetTest),
         DocTestSuite('zope.app.dav.widget'),
         ))
 

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/unitfixtures.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/unitfixtures.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/tests/unitfixtures.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -19,13 +19,15 @@
 
 from BTrees.OOBTree import OOBTree
 from persistent import Persistent
-from zope.interface import implements
+from zope.interface import Interface, implements
 
 from zope.app.filerepresentation.interfaces import IWriteFile
 from zope.app.filerepresentation.interfaces import IReadDirectory
 from zope.app.container.interfaces import IReadContainer
+from zope.app.container.constraints import ItemTypePrecondition
 from zope.app.annotation.interfaces import IAnnotatable
 from zope.app.file.interfaces import IFile
+from zope.app.folder.folder import Folder as ZopeFolder
 
 import zope.app.location
 
@@ -41,7 +43,7 @@
         self.data = OOBTree()
         if level in (0, 1):
             self._setUp()
-        else:
+        elif level > 0:
             self.data['last'] = File('last', 'text/plain', 'blablabla', self)
 
     def _setUp(self):
@@ -57,6 +59,19 @@
         return tuple(items)
 
 
+class INoFileContainer(Interface):
+    """Don't allow any File's within this folder
+    """
+
+    def __setitem__(name, object):
+        """Add a directory to object to this folder."""
+    __setitem__.precondition = ItemTypePrecondition(IReadDirectory)
+
+
+class ConstraintFolder(ZopeFolder):
+    implements(INoFileContainer)
+
+
 class File(zope.app.location.Location, Persistent):
 
     implements(IWriteFile, IFile)

Modified: Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py
===================================================================
--- Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py	2006-01-13 04:13:46 UTC (rev 41294)
+++ Zope3/branches/mkerrin-webdav/src/zope/app/dav/widget.py	2006-01-13 11:50:08 UTC (rev 41295)
@@ -48,6 +48,8 @@
         self._xmldoc = minidom.Document()
         # field value
         self._value  = self._missing_value
+        # input value has a xml dom node
+        self._xmldom_value = self._missing_value
 
         self._error = None
 
@@ -62,13 +64,15 @@
         self.ns_prefix = ns_prefix
 
     def setRenderedValue(self, value):
+        # don't use this
         self._value = value
 
     def applyChanges(self, content):
         return super(DAVWidget, self).applyChanges(content)
 
     def hasInput(self):
-        return self._value is not self._missing_value
+        return self._value is not self._missing_value or \
+               self._xmldom_value is not self._missing_value
 
     def _getAndValidateInput(self):
         """get the input value contained within this widget in a valid format
@@ -79,7 +83,10 @@
         if not self.hasInput():
             raise MissingInputError(self.name, self.label, None)
 
-        value = self._value
+        if self._xmldom_value is not self._missing_value:
+            value = self._setFieldValue(self._xmldom_value)
+        else:
+            value = self._value
 
         # allow missing values only for non-required fields
         if value == field.missing_value: ## and not field.required:
@@ -105,7 +112,8 @@
         try:
             value = self._getAndValidateInput()
         except ConversionError, error:
-            self._error = error
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, error)
             raise self._error
         except ValidationError, error:
             self._error = WidgetInputError(
@@ -163,7 +171,7 @@
         return text
 
     def setProperty(self, propel):
-        self._value = self._setFieldValue(propel)
+        self._xmldom_value = propel # self._setFieldValue(propel)
 
 
 class TextDAVWidget(DAVWidget):



More information about the Zope3-Checkins mailing list