[Zope3-checkins] CVS: Zope3/src/zope/app/content/tests - __init__.py:1.2 test_arguments.py:1.2 test_dtmlpage.py:1.2 test_file.py:1.2 test_folder.py:1.2 test_image.py:1.2 test_sqlscript.py:1.2 test_zptpage.py:1.2 testdt_sqlgroup.py:1.2 testdt_sqltest.py:1.2 testdt_sqlvar.py:1.2 testi18nfile.py:1.2 testi18nimage.py:1.2

Jim Fulton jim@zope.com
Wed, 25 Dec 2002 09:13:51 -0500


Update of /cvs-repository/Zope3/src/zope/app/content/tests
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/app/content/tests

Added Files:
	__init__.py test_arguments.py test_dtmlpage.py test_file.py 
	test_folder.py test_image.py test_sqlscript.py test_zptpage.py 
	testdt_sqlgroup.py testdt_sqltest.py testdt_sqlvar.py 
	testi18nfile.py testi18nimage.py 
Log Message:
Grand renaming:

- Renamed most files (especially python modules) to lower case.

- Moved views and interfaces into separate hierarchies within each
  project, where each top-level directory under the zope package
  is a separate project.

- Moved everything to src from lib/python.

  lib/python will eventually go away. I need access to the cvs
  repository to make this happen, however.

There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.



=== Zope3/src/zope/app/content/tests/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/__init__.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.


=== Zope3/src/zope/app/content/tests/test_arguments.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/test_arguments.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 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
+#
+##############################################################################
+"""DT_SQLVar Tests
+
+$Id$
+"""
+
+import unittest
+
+from zope.app.content.sql import Arguments, parseArguments, InvalidParameter
+
+
+class TestDT_SQLVar(unittest.TestCase):
+
+    def _compareArgumentObjects(self, result, args):
+        self.assertEqual(args.items(), result.items())
+
+    def testSimpleParseArgument(self):
+        args = parseArguments('arg1')
+        result = Arguments({'arg1': {}})
+        self._compareArgumentObjects(result, args)
+
+    def testParseArgumentWithType(self):
+        args = parseArguments('arg1:int')
+        result = Arguments({'arg1': {'type': 'int'}})
+        self._compareArgumentObjects(result, args)
+
+    def testParseArgumentWithDefault(self):
+        args1 = parseArguments('arg1=value')
+        result1 = Arguments({'arg1': {'default': 'value'}})
+        self._compareArgumentObjects(result1, args1)
+
+        args2 = parseArguments('arg1="value"')
+        result2 = Arguments({'arg1': {'default': 'value'}})
+        self._compareArgumentObjects(result2, args2)
+
+    def testParseArgumentWithTypeAndDefault(self):
+        args1 = parseArguments('arg1:string=value')
+        result1 = Arguments({'arg1': {'default': 'value', 'type': 'string'}})
+        self._compareArgumentObjects(result1, args1)
+
+        args2 = parseArguments('arg1:string="value"')
+        result2 = Arguments({'arg1': {'default': 'value', 'type': 'string'}})
+        self._compareArgumentObjects(result2, args2)
+
+    def testParseMultipleArguments(self):
+        args1 = parseArguments('arg1:string=value arg2')
+        result1 = Arguments({'arg1': {'default': 'value', 'type': 'string'},
+                             'arg2': {}})
+        self._compareArgumentObjects(result1, args1)
+
+        args2 = parseArguments('arg1:string=value\narg2')
+        result2 = Arguments({'arg1': {'default': 'value', 'type': 'string'},
+                             'arg2': {}})
+        self._compareArgumentObjects(result2, args2)
+
+    def testParseErrors(self):
+        self.assertRaises(InvalidParameter, parseArguments, 'arg1:""')
+        self.assertRaises(InvalidParameter, parseArguments, 'arg1 = value')
+        self.assertRaises(InvalidParameter, parseArguments, 'arg1="value\' ')
+        self.assertRaises(InvalidParameter, parseArguments, 'arg1:=value')
+
+
+def test_suite():
+    return unittest.makeSuite(TestDT_SQLVar)
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


=== Zope3/src/zope/app/content/tests/test_dtmlpage.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/test_dtmlpage.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,82 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""
+Basic tests for Page Templates used in content-space.
+
+$Id$
+"""
+
+import unittest
+
+from zope.app.content.dtmlpage import DTMLPage
+
+# Wow, this is a lot of work. :(
+from zope.app.tests.placelesssetup import PlacelessSetup
+from zope.app.traversing.traverser import Traverser
+from zope.app.interfaces.traversing.traverser import ITraverser
+from zope.app.traversing.defaulttraversable import DefaultTraversable
+from zope.app.interfaces.traversing.traversable import ITraversable
+from zope.component.adapter import provideAdapter
+from zope.proxy.context import Wrapper
+from zope.security.checker import NamesChecker, defineChecker
+
+
+class Data(object):
+
+    def __init__(self, **kw):
+        self.__dict__.update(kw)
+
+    def __getitem__(self, name):
+        return getattr(self, name)
+
+
+class DTMLPageTests(PlacelessSetup, unittest.TestCase):
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        provideAdapter(None, ITraverser, Traverser)
+        provideAdapter(None, ITraversable, DefaultTraversable)
+        defineChecker(Data, NamesChecker(['URL', 'name', '__getitem__']))
+
+    def test(self):
+        page = DTMLPage()
+        page.setSource(
+            '<html>'
+            '<head><title><dtml-var title></title></head>'
+            '<body>'
+            '<a href="<dtml-var "REQUEST.URL[\'1\']">">'
+            '<dtml-var name>'
+            '</a></body></html>'
+            )
+
+        page = Wrapper(page, Data(name='zope'))
+
+        out = page.render(Data(URL={'1': 'http://foo.com/'}),
+                          title="Zope rules")
+        out = ' '.join(out.split())
+
+
+        self.assertEqual(
+            out,
+            '<html><head><title>Zope rules</title></head><body>'
+            '<a href="http://foo.com/">'
+            'zope'
+            '</a></body></html>'
+            )
+
+def test_suite():
+    return unittest.makeSuite(DTMLPageTests)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/test_file.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/test_file.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# 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 zope.interface.verify import verifyClass
+from zope.app.content.file import FileChunk
+
+
+class Test(unittest.TestCase):
+
+    def _makeFile(self, *args, **kw):
+        """ """
+        from zope.app.content.file import File
+
+        return File(*args, **kw)
+
+
+    def testEmpty(self):
+
+        file = self._makeFile()
+
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), '')
+
+
+    def testConstructor(self):
+
+        file = self._makeFile('Foobar')
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), 'Foobar')
+
+
+        file = self._makeFile('Foobar', 'text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Foobar')
+
+
+        file = self._makeFile(data='Foobar', contentType='text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Foobar')
+
+
+    def testMutators(self):
+
+        file = self._makeFile()
+
+        file.setContentType('text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+
+        file.setData('Foobar')
+        self.assertEqual(file.getData(), 'Foobar')
+
+        file.edit('Blah', 'text/html')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+
+
+    def testLargeDataInput(self):
+
+        file = self._makeFile()
+
+        # Insert as string
+        file.setData('Foobar'*60000)
+        self.assertEqual(file.getSize(), 6*60000)
+        self.assertEqual(file.getData(), 'Foobar'*60000)
+
+        # Insert data as FileChunk
+        fc = FileChunk('Foobar'*4000)
+        file.setData(fc)
+        self.assertEqual(file.getSize(), 6*4000)
+        self.assertEqual(file.getData(), 'Foobar'*4000)
+
+        # Insert data from file object
+        import cStringIO
+        sio = cStringIO.StringIO()
+        sio.write('Foobar'*100000)
+        sio.seek(0)
+        file.setData(sio)
+        self.assertEqual(file.getSize(), 6*100000)
+        self.assertEqual(file.getData(), 'Foobar'*100000)
+
+
+    def testInterface(self):
+
+        from zope.app.content.file import File, IFile
+
+        self.failUnless(IFile.isImplementedByInstancesOf(File))
+        self.failUnless(verifyClass(IFile, File))
+
+
+    def testEdit(self):
+        file = self._makeFile()
+
+        file.edit('Data', 'text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Data')
+
+
+def test_suite():
+    return unittest.makeSuite(Test)
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')


=== Zope3/src/zope/app/content/tests/test_folder.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/test_folder.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+import unittest
+from unittest import TestCase
+from zope.app.component.tests.test_servicemanagercontainer \
+     import BaseTestServiceManagerContainer
+from zope.app.container.tests.test_icontainer import BaseTestIContainer
+
+class Test(BaseTestIContainer, BaseTestServiceManagerContainer, TestCase):
+
+    def _Test__new(self):
+        from zope.app.content.folder import Folder
+        return Folder()
+
+def test_suite():
+    loader = unittest.TestLoader()
+    return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run( test_suite() )


=== Zope3/src/zope/app/content/tests/test_image.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:49 2002
+++ Zope3/src/zope/app/content/tests/test_image.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# 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 zope.interface.verify import verifyClass
+
+class Test(unittest.TestCase):
+
+    def _makeImage(self, *args, **kw):
+        from zope.app.content.image import Image
+        return Image(*args, **kw)
+
+
+    def testEmpty(self):
+        file = self._makeImage()
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), None)
+
+    def testConstructor(self):
+        file = self._makeImage('Data')
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), 'Data')
+
+    def testMutators(self):
+        # XXX What's the point of this test? Does it test that data
+        # contents override content-type? Or not? If the former, then
+        # real image data should be used.
+
+        file = self._makeImage()
+
+        file.setContentType('text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+
+        file.setData('Foobar')
+        self.assertEqual(file.getData(), 'Foobar')
+
+        file.edit('Blah', 'text/html')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+
+    def testInterface(self):
+        from zope.app.content.image import Image, IImage
+
+        self.failUnless(IImage.isImplementedByInstancesOf(Image))
+        self.failUnless(verifyClass(IImage, Image))
+
+def test_suite():
+    return unittest.makeSuite(Test)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/test_sqlscript.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:50 2002
+++ Zope3/src/zope/app/content/tests/test_sqlscript.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,218 @@
+##############################################################################
+#
+# Copyright (c) 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.
+#
+##############################################################################
+"""DT_SQLVar Tests
+
+$Id$
+"""
+
+import unittest
+
+from zope.app.interfaces.rdb import IConnectionService
+from zope.app.interfaces.rdb import IZopeConnection
+from zope.app.interfaces.rdb import IZopeCursor
+from zope.component import getService
+from zope.app.component import nextservice
+from zope.component.service import serviceManager as sm
+from zope.app.tests.placelesssetup import PlacelessSetup
+
+from zope.app.content.sql import SQLScript, Arguments
+from zope.app.interfaces.content.sql import ISQLScript
+
+from zope.app.interfaces.annotation import IAnnotatable
+from zope.app.interfaces.annotation import IAnnotations
+from zope.app.interfaces.annotation import IAttributeAnnotatable
+from zope.app.attributeannotations import AttributeAnnotations
+
+from zope.app.interfaces.cache.cache import ICacheable
+from zope.app.interfaces.cache.cache import ICachingService
+from zope.app.cache.annotationcacheable import AnnotationCacheable
+from zope.app.interfaces.traversing.physicallylocatable \
+     import IPhysicallyLocatable
+
+
+# Make spme fixes, so that we overcome some of the natural ZODB properties
+def getNextServiceManager(context):
+    return sm
+
+class CursorStub:
+
+    __implements__ = IZopeCursor
+
+    description = (('name', 'string'), ('counter', 'int'))
+    count = 0
+
+    def execute(self, operation, parameters=None):
+        CursorStub.count += 1
+        self.result = {"SELECT name, counter FROM Table WHERE id = 1":
+                       (('stephan', CursorStub.count),),
+                       "SELECT name, counter FROM Table WHERE id = 2":
+                       (('marius', CursorStub.count),),
+                       "SELECT name, counter FROM Table WHERE id = 3":
+                       (('erik', CursorStub.count),)
+                      }[operation]
+
+    def fetchall(self):
+        return self.result
+
+
+class ConnectionStub:
+    __implements__ = IZopeConnection
+
+    def cursor(self):
+        return CursorStub()
+
+
+class ConnectionServiceStub:
+    __implements__ = IConnectionService
+
+    def getConnection(self, name):
+        return ConnectionStub()
+
+
+class CacheStub:
+
+    def __init__(self):
+        self.cache = {}
+
+    def set(self, data, obj, key=None):
+        if key:
+            keywords = key.items()
+            keywords.sort()
+            keywords = tuple(keywords)
+        self.cache[obj, keywords] = data
+
+    def query(self, obj, key=None, default=None):
+        if key:
+            keywords = key.items()
+            keywords.sort()
+            keywords = tuple(keywords)
+        return self.cache.get((obj, keywords), default)
+
+
+class CachingServiceStub:
+
+    __implements__ = ICachingService
+
+    def __init__(self):
+        self.caches = {}
+
+    def getCache(self, name):
+        return self.caches[name]
+
+class LocatableStub:
+
+    __implements__ = IPhysicallyLocatable
+
+    def __init__(self, obj):
+        self.obj = obj
+
+    def getPhysicalRoot(self):
+        return None
+
+    def getPhysicalPath(self):
+        return (str(id(self.obj)),)
+
+
+class SQLScriptTest(unittest.TestCase, PlacelessSetup):
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        sm.defineService('SQLDatabaseConnections', IConnectionService)
+        sm.provideService('SQLDatabaseConnections', ConnectionServiceStub())
+        self._old_getNextServiceManager = nextservice.getNextServiceManager
+        nextservice.getNextServiceManager = getNextServiceManager
+        self.caching_service = CachingServiceStub()
+        sm.defineService('Caching', ICachingService)
+        sm.provideService('Caching', self.caching_service)
+        getService(None, "Adapters").provideAdapter(
+            IAttributeAnnotatable, IAnnotations,
+            AttributeAnnotations)
+        getService(None, "Adapters").provideAdapter(
+            ISQLScript, IPhysicallyLocatable,
+            LocatableStub)
+        getService(None, "Adapters").provideAdapter(
+            IAnnotatable, ICacheable,
+            AnnotationCacheable)
+
+    def tearDown(self):
+        nextservice.getNextServiceManager = self._old_getNextServiceManager
+
+    def _getScript(self):
+        return SQLScript("my_connection",
+                         "SELECT name, counter FROM Table WHERE"
+                         " <dtml-sqltest id type=int>",
+                         'id')
+
+    def testGetArguments(self):
+        assert isinstance(arguments, StringTypes), \
+               '"arguments" argument of setArguments() must be a string'
+        self._arg_string = arguments
+        self.arguments = parseArguments(arguments)
+
+    def testGetArguments(self):
+        result = Arguments({'id': {}})
+        args = self._getScript().getArguments()
+        self.assertEqual(args, result)
+
+    def testGetArgumentsString(self):
+        self.assertEqual('id', self._getScript().getArgumentsString())
+
+    def testSetSource(self):
+        script = self._getScript()
+        script.setSource('SELECT * FROM Table')
+        self.assertEqual('SELECT * FROM Table', script.getSource())
+
+    def testGetSource(self):
+        expected = ("SELECT name, counter FROM Table"
+                    " WHERE <dtml-sqltest id type=int>")
+        self.assertEqual(expected,
+                         self._getScript().getSource())
+
+    def testSetConnectionName(self):
+        script = self._getScript()
+        script.setConnectionName('test_conn')
+        self.assertEqual('test_conn', script.getConnectionName())
+
+    def testGetConnectionName(self):
+        self.assertEqual('my_connection',
+                         self._getScript().getConnectionName())
+
+    def testSQLScript(self):
+        result = self._getScript()(id=1)
+        self.assertEqual(result.columns, ('name','counter'))
+        self.assertEqual(result[0].name, 'stephan')
+
+    def testSQLScriptCaching(self):
+        script = self._getScript()
+        CursorStub.count = 0
+        # no caching: check that the counter grows
+        result = script(id=1)
+        self.assertEqual(result[0].counter, 1)
+        result = script(id=1)
+        self.assertEqual(result[0].counter, 2)
+        # caching: and check that the counter stays still
+        AnnotationCacheable(script).setCacheId('dumbcache')
+        self.caching_service.caches['dumbcache'] = CacheStub()
+        result = script(id=1)
+        self.assertEqual(result[0].counter, 3)
+        result = script(id=1)
+        self.assertEqual(result[0].counter, 3)
+        result = script(id=2)
+        self.assertEqual(result[0].counter, 4)
+
+
+def test_suite():
+    return unittest.makeSuite(SQLScriptTest)
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


=== Zope3/src/zope/app/content/tests/test_zptpage.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:50 2002
+++ Zope3/src/zope/app/content/tests/test_zptpage.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,102 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""
+Basic tests for Page Templates used in content-space.
+
+$Id$
+"""
+
+import unittest
+
+from zope.app.content.zpt import ZPTPage, \
+     SearchableText, IZPTPage
+from zope.app.interfaces.index.text.interfaces import ISearchableText
+from zope.component import getAdapter
+
+# Wow, this is a lot of work. :(
+from zope.app.tests.placelesssetup import PlacelessSetup
+from zope.app.traversing.traverser import Traverser
+from zope.app.interfaces.traversing.traverser import ITraverser
+from zope.app.traversing.defaulttraversable import DefaultTraversable
+from zope.app.interfaces.traversing.traversable import ITraversable
+from zope.component.adapter import provideAdapter
+from zope.proxy.context import Wrapper
+from zope.security.checker import NamesChecker, defineChecker
+
+class Data(object):
+    def __init__(self, **kw):
+        self.__dict__.update(kw)
+
+
+
+class ZPTPageTests(PlacelessSetup, unittest.TestCase):
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        provideAdapter(None, ITraverser, Traverser)
+        provideAdapter(None, ITraversable, DefaultTraversable)
+        provideAdapter(IZPTPage, ISearchableText, SearchableText)
+        defineChecker(Data, NamesChecker(['URL', 'name']))
+
+    def testSearchableText(self):
+        page = ZPTPage()
+        searchableText = getAdapter(page, ISearchableText)
+
+        utext = u'another test\n' # The source will grow a newline if ommited
+        html = u"<html><body>%s</body></html>\n" % (utext, )
+
+        page.setSource(utext)
+        self.failUnlessEqual(searchableText.getSearchableText(), [utext])
+
+        page.setSource(html, content_type='text/html')
+        self.assertEqual(searchableText.getSearchableText(), [utext+'\n'])
+
+        page.setSource(html, content_type='text/plain')
+        self.assertEqual(searchableText.getSearchableText(), [html])
+
+
+
+    def testZPTRendering(self):
+        page = ZPTPage()
+        page.setSource(
+            u''
+            '<html>'
+            '<head><title tal:content="options/title">blah</title></head>'
+            '<body>'
+            '<a href="foo" tal:attributes="href request/URL/1">'
+            '<span tal:replace="context/name">splat</span>'
+            '</a></body></html>'
+            )
+
+        page = Wrapper(page, Data(name='zope'))
+
+        out = page.render(Data(URL={'1': 'http://foo.com/'}),
+                          title="Zope rules")
+        out = ' '.join(out.split())
+
+        self.assertEqual(
+            out,
+            '<html><head><title>Zope rules</title></head><body>'
+            '<a href="http://foo.com/">'
+            'zope'
+            '</a></body></html>'
+            )
+
+
+
+def test_suite():
+    return unittest.makeSuite(ZPTPageTests)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/testdt_sqlgroup.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/content/tests/testdt_sqlgroup.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 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
+#
+##############################################################################
+"""DT_SQLVar Tests
+
+$Id$
+"""
+
+import unittest
+from zope.app.content.sql import SQLDTML
+
+
+class TestDT_SQLGroup(unittest.TestCase):
+
+    doc_class = SQLDTML
+
+
+    def testSimpleUse(self):
+        html = self.doc_class("""
+          <dtml-sqlgroup>
+            <dtml-sqlvar column type=nb>
+          </dtml-sqlgroup>""")
+        result = "'name'"
+
+        self.assertEqual(html(column='name').strip(), result)
+
+
+    def testComplexUse(self):
+        html = self.doc_class("""
+          <dtml-sqlgroup required>
+            <dtml-sqlgroup>
+              <dtml-sqltest name column=nick_name type=nb multiple optional>
+            <dtml-or>
+              <dtml-sqltest name column=first_name type=nb multiple optional>
+            </dtml-sqlgroup>
+          <dtml-and>
+            <dtml-sqltest home_town type=nb optional>
+          <dtml-and>
+            <dtml-if minimum_age>
+               age >= <dtml-sqlvar minimum_age type=int>
+            </dtml-if>
+          <dtml-and>
+            <dtml-if maximum_age>
+               age <= <dtml-sqlvar maximum_age type=int>
+            </dtml-if>
+          </dtml-sqlgroup>
+        """)
+
+        result = """
+((nick_name = 'stephan'
+ or first_name = 'stephan'
+)
+ and home_town = 'berlin'
+ and age >= 16
+ and age <= 21
+)"""
+        self.assertEqual(html(name="stephan", home_town="berlin",
+                              minimum_age=16, maximum_age="21").strip(),
+                         result.strip())
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest( unittest.makeSuite(TestDT_SQLGroup) )
+    return suite
+
+if __name__ == '__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/testdt_sqltest.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/content/tests/testdt_sqltest.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# Copyright (c) 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
+#
+##############################################################################
+"""DT_SQLVar Tests
+
+$Id$
+"""
+
+import unittest
+from zope.app.content.sql import SQLDTML, comparison_operators
+
+
+class TestDT_SQLTest(unittest.TestCase):
+
+    doc_class = SQLDTML
+
+
+    def testSimpleUse(self):
+        html = self.doc_class("<dtml-sqltest column type=nb>")
+        result = "column = 'name'"
+
+        self.assertEqual(html(column='name'), result)
+
+
+    def testIntType(self):
+        html = self.doc_class("<dtml-sqltest column type=int>")
+        result = "column = 3"
+
+        self.assertEqual(html(column=3), result)
+        self.assertEqual(html(column='3'), result)
+        self.assertEqual(html(column=3.1), result)
+
+
+    def testFloatType(self):
+        html = self.doc_class("<dtml-sqltest column type=float>")
+        result = "column = 3.1"
+
+        self.assertEqual(html(column=3), "column = 3.0")
+        self.assertEqual(html(column='3'), "column = 3")
+        self.assertEqual(html(column='3.1'), result)
+        self.assertEqual(html(column=3.1), result)
+        self.assertEqual(html(column=0.0), "column = 0.0")
+
+    def testStringTypeAndEscaping(self):
+        html = self.doc_class("<dtml-sqltest column type=nb>")
+
+        self.assertEqual(html(column='name'), "column = 'name'")
+        self.assertEqual(html(column='Let\'s do it'),
+                         "column = 'Let''s do it'")
+        # Acid test :)
+        self.assertEqual(html(column="\'\'"), "column = ''''''")
+
+
+    def testOperators(self):
+        for item in comparison_operators.items():
+            html = self.doc_class(
+                "<dtml-sqltest column type=nb op=%s>" %item[0])
+            result = "column %s 'name'" %item[1]
+
+            self.assertEqual(html(column='name'), result)
+
+
+    def testCustomColumnName(self):
+        html = self.doc_class(
+            "<dtml-sqltest col column=col type=nb optional>")
+        result1 = "col = 'name'"
+        result2 = ""
+
+        self.assertEqual(html(col='name'), result1)
+        self.assertEqual(html(col=''), result2)
+        self.assertEqual(html(), result2)
+
+
+    def testOptional(self):
+        html = self.doc_class("<dtml-sqltest column type=nb optional>")
+        result1 = "column = 'name'"
+        result2 = ""
+
+        self.assertEqual(html(column='name'), result1)
+        self.assertEqual(html(column=''), result2)
+        self.assertEqual(html(), result2)
+
+
+    def testMultiple(self):
+        html = self.doc_class(
+            "<dtml-sqltest column type=nb optional multiple>")
+        result1 = "column in ('name1', 'name2')"
+        result2 = ""
+
+        self.assertEqual(html(column=('name1', 'name2')), result1)
+        self.assertEqual(html(column=()), result2)
+        self.assertEqual(html(), result2)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest( unittest.makeSuite(TestDT_SQLTest) )
+    return suite
+
+if __name__ == '__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/testdt_sqlvar.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/content/tests/testdt_sqlvar.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 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
+#
+##############################################################################
+"""DT_SQLVar Tests
+
+$Id$
+"""
+
+import unittest
+from zope.app.content.sql import SQLDTML
+
+
+class TestDT_SQLVar(unittest.TestCase):
+
+    doc_class = SQLDTML
+
+
+    def testSimpleUse(self):
+        html = self.doc_class("<dtml-sqlvar column type=nb>")
+        result = "'name'"
+
+        self.assertEqual(html(column='name'), result)
+
+
+    def testIntType(self):
+        html = self.doc_class("<dtml-sqlvar column type=int>")
+        result = "3"
+
+        self.assertEqual(html(column=3), result)
+        self.assertEqual(html(column='3'), result)
+        self.assertEqual(html(column=3.1), result)
+
+
+    def testFloatType(self):
+        html = self.doc_class("<dtml-sqlvar column type=float>")
+        result = "3.1"
+
+        self.assertEqual(html(column=3), "3.0")
+        self.assertEqual(html(column='3'), "3")
+        self.assertEqual(html(column='3.1'), result)
+        self.assertEqual(html(column=3.1), result)
+
+
+    def testStringTypeAndEscaping(self):
+        html = self.doc_class("<dtml-sqlvar column type=nb>")
+
+        self.assertEqual(html(column='name'), "'name'")
+        self.assertEqual(html(column='Let\'s do it'), "'Let''s do it'")
+        # Acid test :)
+        self.assertEqual(html(column="\'\'"), "''''''")
+
+
+    def testOptional(self):
+        html = self.doc_class("""<dtml-sqlvar column type=nb optional>""")
+        result = "null"
+
+        self.assertEqual(html(column=None), result)
+        self.assertEqual(html(column=''), result)
+        self.assertEqual(html(), result)
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest( unittest.makeSuite(TestDT_SQLVar) )
+    return suite
+
+if __name__ == '__main__':
+    unittest.TextTestRunner().run(test_suite())


=== Zope3/src/zope/app/content/tests/testi18nfile.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/content/tests/testi18nfile.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,212 @@
+##############################################################################
+#
+# 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 zope.interface.verify import verifyClass
+from zope.app.content.file import FileChunk
+from zope.i18n.tests.testii18naware import TestII18nAware
+
+
+def sorted(list):
+    list.sort()
+    return list
+
+
+class Test(TestII18nAware):
+
+
+    def _makeFile(self, *args, **kw):
+        """ """
+        from zope.app.content.i18nfile import I18nFile
+
+        return I18nFile(*args, **kw)
+
+
+    def _createObject(self):
+        obj = self._makeFile(defaultLanguage='fr')
+        obj.setData('', 'lt')
+        obj.setData('', 'en')
+        return obj
+
+
+    def testEmpty(self):
+
+        file = self._makeFile()
+
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), '')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+
+
+    def testConstructor(self):
+
+        file = self._makeFile('Foobar')
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(file.getData('en'), 'Foobar')
+        self.assertEqual(file.getData('nonexistent'), 'Foobar')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+
+        file = self._makeFile('Foobar', 'text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(file.getData('en'), 'Foobar')
+        self.assertEqual(file.getData('nonexistent'), 'Foobar')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+
+        file = self._makeFile(data='Foobar', contentType='text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(file.getData('en'), 'Foobar')
+        self.assertEqual(file.getData('nonexistent'), 'Foobar')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+
+        file = self._makeFile(data='Foobar', contentType='text/plain',
+                              defaultLanguage='fr')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(file.getData('en'), 'Foobar')
+        self.assertEqual(file.getData('nonexistent'), 'Foobar')
+        self.assertEqual(file.getDefaultLanguage(), 'fr')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['fr'])
+
+
+    def testMutators(self):
+
+        file = self._makeFile()
+
+        file.setContentType('text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file.setData('Foobar')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file.setData('Barbaz', language='fr')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(file.getData('fr'), 'Barbaz')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+
+        file.edit('Blah', 'text/html')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Barbaz')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+
+        file.edit('Quux', 'text/html', 'lt')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Barbaz')
+        self.assertEqual(file.getData('lt'), 'Quux')
+        self.assertEqual(file.getSize(), len('Blah'))
+        self.assertEqual(file.getSize('fr'), len('Barbaz'))
+        self.assertEqual(file.getSize('lt'), len('Quux'))
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr', 'lt'])
+
+        file.removeLanguage('lt')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Barbaz')
+        self.assertEqual(file.getSize(), len('Blah'))
+        self.assertEqual(file.getSize('fr'), len('Barbaz'))
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+        self.assertEqual(file.getData('lt'), 'Blah')
+        self.assertEqual(file.getSize('lt'), len('Blah'))
+
+        file.removeLanguage('nonexistent')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Barbaz')
+        self.assertEqual(file.getSize(), len('Blah'))
+        self.assertEqual(file.getSize('fr'), len('Barbaz'))
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+        self.assertEqual(file.getData('lt'), 'Blah')
+        self.assertEqual(file.getSize('lt'), len('Blah'))
+
+        self.assertRaises(ValueError, file.removeLanguage, file.getDefaultLanguage())
+
+        self.assertRaises(ValueError, file.setDefaultLanguage, 'nonexistent')
+
+
+    def testLargeDataInput(self):
+
+        file = self._makeFile()
+
+        # Insert as string
+        file.setData('Foobar'*60000, 'en')
+        self.assertEqual(file.getSize('en'), 6*60000)
+        self.assertEqual(file.getData('en'), 'Foobar'*60000)
+
+        # Insert data as FileChunk
+        fc = FileChunk('Foobar'*4000)
+        file.setData(fc, 'lt')
+        self.assertEqual(file.getSize('lt'), 6*4000)
+        self.assertEqual(file.getData('lt'), 'Foobar'*4000)
+
+        # Insert data from file object
+        import cStringIO
+        sio = cStringIO.StringIO()
+        sio.write('Foobar'*100000)
+        sio.seek(0)
+        file.setData(sio, 'fr')
+        self.assertEqual(file.getSize('fr'), 6*100000)
+        self.assertEqual(file.getData('fr'), 'Foobar'*100000)
+
+
+    def testInterface(self):
+
+        from zope.app.interfaces.content.file import IFile
+        from zope.app.interfaces.content.i18nfile import II18nFile
+        from zope.app.content.i18nfile import I18nFile
+        from zope.interfaces.i18n import II18nAware
+
+        self.failUnless(IFile.isImplementedByInstancesOf(I18nFile))
+        self.failUnless(verifyClass(IFile, I18nFile))
+
+        self.failUnless(II18nAware.isImplementedByInstancesOf(I18nFile))
+        self.failUnless(verifyClass(II18nAware, I18nFile))
+
+        self.failUnless(II18nFile.isImplementedByInstancesOf(I18nFile))
+        self.failUnless(verifyClass(II18nFile, I18nFile))
+
+
+    def testSetDefaultLanguage(self):
+
+        # getDefaultLanguage and getAvailableLanguages are tested in the
+        # above tests
+
+        file = self._makeFile()
+
+        file.setData('', language='lt')
+        file.setDefaultLanguage('lt')
+        self.assertEqual(file.getDefaultLanguage(), 'lt')
+
+
+def test_suite():
+    loader = unittest.TestLoader()
+    return loader.loadTestsFromTestCase( Test )
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run( test_suite() )


=== Zope3/src/zope/app/content/tests/testi18nimage.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/content/tests/testi18nimage.py	Wed Dec 25 09:12:48 2002
@@ -0,0 +1,183 @@
+##############################################################################
+#
+# 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 zope.interface.verify import verifyClass
+from zope.i18n.tests.testii18naware import TestII18nAware
+
+
+def sorted(list):
+    list.sort()
+    return list
+
+
+class Test(TestII18nAware):
+
+
+    def _makeImage(self, *args, **kw):
+        """ """
+        from zope.app.content.i18nimage import I18nImage
+
+        return I18nImage(*args, **kw)
+
+
+    def _createObject(self):
+        obj = self._makeImage(defaultLanguage='fr')
+        obj.setData('', 'lt')
+        obj.setData('', 'en')
+        return obj
+
+
+    def testEmpty( self ):
+
+        file = self._makeImage()
+
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), '')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+
+
+    def testConstructor(self):
+
+        file = self._makeImage('Data')
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), 'Data')
+        self.assertEqual(file.getData('en'), 'Data')
+        self.assertEqual(file.getData('nonexistent'), 'Data')
+        self.assertEqual(file.getDefaultLanguage(), 'en')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file = self._makeImage('Data', defaultLanguage='fr')
+        self.assertEqual(file.getContentType(), '')
+        self.assertEqual(file.getData(), 'Data')
+        self.assertEqual(file.getData('en'), 'Data')
+        self.assertEqual(file.getData('nonexistent'), 'Data')
+        self.assertEqual(file.getDefaultLanguage(), 'fr')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['fr'])
+
+
+    def testMutators(self):
+
+        # XXX What's the point of this test? Does it test that data
+        # contents override content-type? Or not? If the former, then
+        # real image data should be used.
+
+        file = self._makeImage()
+
+        file.setContentType('text/plain')
+        self.assertEqual(file.getContentType(), 'text/plain')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file.setData('Foobar')
+        self.assertEqual(file.getData(), 'Foobar')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file.edit('Blah', 'text/html')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
+
+        file.setData('Foobar in lt', 'lt')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('lt'), 'Foobar in lt')
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'lt'])
+
+        file.edit('Blah in fr', 'text/html', 'fr')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('lt'), 'Foobar in lt')
+        self.assertEqual(file.getData('fr'), 'Blah in fr')
+        self.assertEqual(sorted(file.getAvailableLanguages()),
+                         ['en', 'fr', 'lt'])
+
+        file.removeLanguage('lt')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Blah in fr')
+        self.assertEqual(file.getSize(), len('Blah'))
+        self.assertEqual(file.getSize('fr'), len('Blah in fr'))
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+        self.assertEqual(file.getData('lt'), 'Blah')
+        self.assertEqual(file.getSize('lt'), len('Blah'))
+
+        file.removeLanguage('nonexistent')
+        self.assertEqual(file.getContentType(), 'text/html')
+        self.assertEqual(file.getData(), 'Blah')
+        self.assertEqual(file.getData('fr'), 'Blah in fr')
+        self.assertEqual(file.getSize(), len('Blah'))
+        self.assertEqual(file.getSize('fr'), len('Blah in fr'))
+        self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
+        self.assertEqual(file.getData('lt'), 'Blah')
+        self.assertEqual(file.getSize('lt'), len('Blah'))
+
+        self.assertRaises(ValueError, file.removeLanguage,
+                          file.getDefaultLanguage())
+
+        self.assertRaises(ValueError, file.setDefaultLanguage, 'nonexistent')
+
+        # Check that setData updates content type only when updating the
+        # default language.  Need some real images or at least headers
+        # for that.
+
+        gifHdr = 'GIF87a\x20\x00\x10\x00'
+        file.setData(gifHdr)
+        self.assertEqual(file.getContentType(), 'image/gif')
+
+        pngHdr = '\211PNG\r\n\032\n\0\0\0\x20\0\0\0\x10'
+        file.setData(pngHdr, 'fr')
+        self.assertEqual(file.getContentType(), 'image/gif')
+
+        file.setData(pngHdr, 'en')
+        self.assertEqual(file.getContentType(), 'image/png')
+
+
+    def testInterface(self):
+
+        from zope.app.content.image import IImage
+        from zope.app.content.i18nimage import I18nImage
+        from zope.app.interfaces.content.i18nfile import II18nFile
+        from zope.interfaces.i18n import II18nAware
+
+        self.failUnless(IImage.isImplementedByInstancesOf(I18nImage))
+        self.failUnless(verifyClass(IImage, I18nImage))
+
+        self.failUnless(II18nAware.isImplementedByInstancesOf(I18nImage))
+        self.failUnless(verifyClass(II18nAware, I18nImage))
+
+        self.failUnless(II18nFile.isImplementedByInstancesOf(I18nImage))
+        self.failUnless(verifyClass(II18nFile, I18nImage))
+
+
+    def testSetDefaultLanguage(self):
+
+        # getDefaultLanguage and getAvailableLanguages are tested in the
+        # above tests
+
+        file = self._makeImage()
+
+        file.setData('', language='lt')
+        file.setDefaultLanguage('lt')
+        self.assertEqual(file.getDefaultLanguage(), 'lt')
+
+
+def test_suite():
+    loader = unittest.TestLoader()
+    return loader.loadTestsFromTestCase( Test )
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run( test_suite() )