Back to index

plone3  3.1.7
test_marshall.py
Go to the documentation of this file.
00001 # Marshall: A framework for pluggable marshalling policies
00002 # Copyright (C) 2004-2006 Enfold Systems, LLC
00003 #
00004 # This program is free software; you can redistribute it and/or modify
00005 # it under the terms of the GNU General Public License as published by
00006 # the Free Software Foundation; either version 2 of the License, or
00007 # (at your option) any later version.
00008 #
00009 # This program is distributed in the hope that it will be useful,
00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 # GNU General Public License for more details.
00013 #
00014 # You should have received a copy of the GNU General Public License
00015 # along with this program; if not, write to the Free Software
00016 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 #
00018 """
00019 $Id: test_marshall.py 7825 2007-03-29 10:19:26Z nouri $
00020 """
00021 
00022 import os, sys
00023 import glob
00024 
00025 if __name__ == '__main__':
00026     execfile(os.path.join(sys.path[0], 'framework.py'))
00027 
00028 # Load fixture
00029 from Testing import ZopeTestCase
00030 from Products.Marshall.tests.base import BaseTest
00031 
00032 # Install our product
00033 ZopeTestCase.installProduct('Marshall')
00034 ZopeTestCase.installProduct('Archetypes')
00035 ZopeTestCase.installProduct('ATContentTypes')
00036 
00037 from Products.CMFCore.utils import getToolByName
00038 from Products.Marshall.registry import Registry, getRegisteredComponents
00039 from Products.Marshall.registry import getComponent
00040 from Products.Marshall.exceptions import MarshallingException
00041 from Products.Marshall.tests import PACKAGE_HOME
00042 from Products.Marshall.tests.examples import person
00043 from Products.Marshall.tests.examples import blob
00044 tool_id = Registry.id
00045 
00046 def get_data(fname):
00047     return open(os.path.join(PACKAGE_HOME, 'data', fname), 'rb').read()
00048 
00049 class MarshallerTest(BaseTest):
00050 
00051     def afterSetUp(self):
00052         super(MarshallerTest, self).afterSetUp()
00053         self.loginPortalOwner()
00054         self.qi = self.portal.portal_quickinstaller
00055         self.qi.installProduct('Marshall')
00056         self.tool = getToolByName(self.portal, tool_id)
00057         self.infile = open(self.input, 'rb+')
00058         self.portal.invokeFactory(self.type_name, self.type_name.lower())
00059         self.obj = self.portal._getOb(self.type_name.lower())
00060 
00061     def beforeTearDown(self):
00062         super(MarshallerTest, self).beforeTearDown()
00063         self.infile.close()
00064 
00065     def test_marshall_roundtrip(self):
00066         marshaller = getComponent(self.prefix)
00067         content = self.infile.read()
00068         marshaller.demarshall(self.obj, content)
00069         ctype, length, got = marshaller.marshall(self.obj, filename=self.input)
00070         normalize = self.input.endswith('xml')
00071         
00072         self.assertEqualsDiff(content, got, normalize=normalize)
00073 
00074 class ATXMLReferenceMarshallTest(BaseTest):
00075 
00076     def afterSetUp(self):
00077         super(ATXMLReferenceMarshallTest, self).afterSetUp()
00078         self.loginPortalOwner()
00079         self.qi = self.portal.portal_quickinstaller
00080         self.qi.installProduct('Marshall')
00081         self.tool = getToolByName(self.portal, tool_id)
00082         self.marshaller = getComponent('atxml')
00083 
00084     def createPerson(self, ctx, id, **kw):
00085         person.addPerson(ctx, id, **kw)
00086         ob = ctx._getOb(id)
00087         ob.indexObject()
00088         return ob
00089 
00090     def test_uid_references(self):
00091         paulo = self.createPerson(
00092             self.portal,
00093             'paulo',
00094             title='Paulo da Silva')
00095         eligia = self.createPerson(
00096             self.portal,
00097             'eligia',
00098             title='Eligia M. da Silva')
00099         sidnei = self.createPerson(
00100             self.portal,
00101             'sidnei',
00102             title='Sidnei da Silva')
00103 
00104         self.assertEquals(sidnei.getParents(), [])
00105 
00106         ref_xml = """<?xml version="1.0" ?>
00107         <metadata xmlns="http://plone.org/ns/archetypes/">
00108         <field id="parents">
00109         <reference>
00110         <uid>
00111         %(uid)s
00112         </uid>
00113         </reference>
00114         </field>
00115         </metadata>
00116         """ % {'uid':paulo.UID()}
00117         self.marshaller.demarshall(sidnei, ref_xml)
00118         # Test a simple UID reference
00119         self.assertEquals(sidnei['parents'], [paulo.UID()])
00120 
00121         ref_xml = """<?xml version="1.0" ?>
00122         <metadata xmlns="http://plone.org/ns/archetypes/">
00123         <field id="parents">
00124         <reference>
00125         <uid>
00126         XXX%(uid)sXXX
00127         </uid>
00128         </reference>
00129         </field>
00130         </metadata>
00131         """ % {'uid':paulo.UID()}
00132         # Test that invalid UID reference raises an exception
00133         self.assertRaises(MarshallingException, self.marshaller.demarshall,
00134                           sidnei, ref_xml)
00135 
00136 
00137         ref_xml = """<?xml version="1.0" ?>
00138         <metadata xmlns="http://plone.org/ns/archetypes/">
00139         <field id="parents">
00140         <reference>
00141         <uid>
00142         %(uid1)s
00143         </uid>
00144         </reference>
00145         </field>
00146         <field id="parents">
00147         <reference>
00148         <uid>
00149         %(uid2)s
00150         </uid>
00151         </reference>
00152         </field>
00153         </metadata>
00154         """ % {'uid1':paulo.UID(), 'uid2':eligia.UID()}
00155         self.marshaller.demarshall(sidnei, ref_xml)
00156         # Test that multiple UID references work.
00157         self.assertEquals(sidnei['parents'], [paulo.UID(), eligia.UID()])
00158 
00159         # *WARNING* the tests below are dependent on the one above.
00160         new_uid = '9x9x9x9x9x9x9x9x9x9x9x9x9x9x9x9x9x9x9'
00161         old_uid = paulo.UID()
00162         ref_xml = """<?xml version="1.0" ?>
00163         <metadata xmlns="http://plone.org/ns/archetypes/">
00164         <uid>
00165         %(uid)s
00166         </uid>
00167         </metadata>
00168         """ % {'uid':new_uid}
00169         self.marshaller.demarshall(paulo, ref_xml)
00170         # Test modifying a uid by marshalling
00171         self.assertEquals(paulo.UID(), new_uid)
00172         # Test that the references still apply
00173         self.assertEquals(sidnei['parents'], [paulo.UID(), eligia.UID()])
00174         # Test that trying to set a different object to the same UID
00175         # will raise an exception.
00176         self.assertRaises(MarshallingException, self.marshaller.demarshall,
00177                           sidnei, ref_xml)
00178 
00179     def test_path_references(self):
00180         paulo = self.createPerson(
00181             self.portal,
00182             'paulo',
00183             title='Paulo da Silva')
00184         eligia = self.createPerson(
00185             self.portal,
00186             'eligia',
00187             title='Eligia M. da Silva')
00188         sidnei = self.createPerson(
00189             self.portal,
00190             'sidnei',
00191             title='Sidnei da Silva')
00192 
00193         self.assertEquals(sidnei.getParents(), [])
00194 
00195         ref_xml = """<?xml version="1.0" ?>
00196         <metadata xmlns="http://plone.org/ns/archetypes/">
00197         <field id="parents">
00198         <reference>
00199         <path>
00200         %(path)s
00201         </path>
00202         </reference>
00203         </field>
00204         </metadata>
00205         """ % {'path':'paulo'}
00206         self.marshaller.demarshall(sidnei, ref_xml)
00207         # Test a simple path reference
00208         self.assertEquals(sidnei['parents'], [paulo.UID()])
00209 
00210         ref_xml = """<?xml version="1.0" ?>
00211         <metadata xmlns="http://plone.org/ns/archetypes/">
00212         <field id="parents">
00213         <reference>
00214         <path>
00215         XXX%(path)sXXX
00216         </path>
00217         </reference>
00218         </field>
00219         </metadata>
00220         """ % {'path':'paulo'}
00221         # Test that an invalid path reference raises an exception
00222         self.assertRaises(MarshallingException, self.marshaller.demarshall,
00223                           sidnei, ref_xml)
00224 
00225         ref_xml = """<?xml version="1.0" ?>
00226         <metadata xmlns="http://plone.org/ns/archetypes/">
00227         <field id="parents">
00228         <reference>
00229         <path>
00230         %(path1)s
00231         </path>
00232         </reference>
00233         </field>
00234         <field id="parents">
00235         <reference>
00236         <path>
00237         %(path2)s
00238         </path>
00239         </reference>
00240         </field>
00241         </metadata>
00242         """ % {'path1':'paulo', 'path2':'eligia'}
00243         self.marshaller.demarshall(sidnei, ref_xml)
00244         # Test multiple path references
00245         self.assertEquals(sidnei['parents'], [paulo.UID(), eligia.UID()])
00246 
00247 
00248     def test_metadata_references(self):
00249         paulo = self.createPerson(
00250             self.portal,
00251             'paulo',
00252             title='Paulo da Silva',
00253             description='Familia Silva')
00254         paulo_s = self.createPerson(
00255             self.portal,
00256             'paulo_s',
00257             title='Paulo Schuh',
00258             description='Familia Schuh')
00259         sidnei = self.createPerson(
00260             self.portal,
00261             'sidnei',
00262             title='Sidnei da Silva',
00263             description='Familia Silva')
00264 
00265         self.assertEquals(sidnei.getParents(), [])
00266 
00267         ref_xml = """<?xml version="1.0" ?>
00268         <metadata xmlns="http://plone.org/ns/archetypes/"
00269                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00270         <field id="parents">
00271         <reference>
00272         <metadata>
00273         <dc:title>
00274         Paulo Schuh
00275         </dc:title>
00276         <dc:description>
00277         Familia Schuh
00278         </dc:description>
00279         </metadata>
00280         </reference>
00281         </field>
00282         </metadata>
00283         """
00284         self.marshaller.demarshall(sidnei, ref_xml)
00285         # Test a simple metadata reference
00286         self.assertEquals(sidnei['parents'], [paulo_s.UID()])
00287 
00288         ref_xml = """<?xml version="1.0" ?>
00289         <metadata xmlns="http://plone.org/ns/archetypes/"
00290                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00291         <field id="parents">
00292         <reference>
00293         <metadata>
00294         <dc:title>
00295         Silva
00296         </dc:title>
00297         </metadata>
00298         </reference>
00299         </field>
00300         </metadata>
00301         """
00302 
00303         # Test that a metadata reference that doesn't uniquely
00304         # identifies a target raises an exception
00305         self.assertRaises(MarshallingException, self.marshaller.demarshall,
00306                           sidnei, ref_xml)
00307 
00308         ref_xml = """<?xml version="1.0" ?>
00309         <metadata xmlns="http://plone.org/ns/archetypes/"
00310                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00311         <field id="parents">
00312         <reference>
00313         <metadata>
00314         <dc:title>
00315         Souza
00316         </dc:title>
00317         </metadata>
00318         </reference>
00319         </field>
00320         </metadata>
00321         """
00322         # Test that a metadata reference that doesn't uniquely
00323         # find at least one object raises an exception
00324         self.assertRaises(MarshallingException, self.marshaller.demarshall,
00325                           sidnei, ref_xml)
00326 
00327         ref_xml = """<?xml version="1.0" ?>
00328         <metadata xmlns="http://plone.org/ns/archetypes/"
00329                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00330         <field id="parents">
00331         <reference>
00332         <metadata>
00333         <dc:title>
00334         Paulo da Silva
00335         </dc:title>
00336         <dc:description>
00337         Familia Silva
00338         </dc:description>
00339         </metadata>
00340         </reference>
00341         </field>
00342         </metadata>
00343         """
00344         self.marshaller.demarshall(sidnei, ref_xml)
00345         # Test simple metadata reference
00346         self.assertEquals(sidnei['parents'], [paulo.UID()])
00347 
00348         ref_xml = """<?xml version="1.0" ?>
00349         <metadata xmlns="http://plone.org/ns/archetypes/"
00350                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00351         <field id="parents">
00352         <reference>
00353         <metadata>
00354         <dc:title>
00355         Paulo da Silva
00356         </dc:title>
00357         <dc:description>
00358         Familia Silva
00359         </dc:description>
00360         </metadata>
00361         </reference>
00362         </field>
00363         <field id="parents">
00364         <reference>
00365         <metadata>
00366         <dc:title>
00367         Paulo Schuh
00368         </dc:title>
00369         <dc:description>
00370         Familia Schuh
00371         </dc:description>
00372         </metadata>
00373         </reference>
00374         </field>
00375         </metadata>
00376         """
00377         self.marshaller.demarshall(sidnei, ref_xml)
00378         # Test multiple metadata references
00379         self.assertEquals(sidnei['parents'], [paulo.UID(), paulo_s.UID()])
00380 
00381     def test_linesfield(self):
00382         sidnei = self.createPerson(
00383             self.portal,
00384             'sidnei',
00385             title='Sidnei da Silva',
00386             description='Familia Silva',
00387             food_preference='BBQ\nPizza\nShrimp')
00388 
00389         self.assertEquals(sidnei.getFoodPrefs(),
00390                           ('BBQ', 'Pizza', 'Shrimp'))
00391 
00392         lines_xml = """<?xml version="1.0" ?>
00393         <metadata xmlns="http://plone.org/ns/archetypes/"
00394                   xmlns:dc="http://purl.org/dc/elements/1.1/">
00395         <field id="food_preference">
00396         BBQ
00397         </field>
00398         <field id="food_preference">
00399         Camaron Diablo
00400         </field>
00401         </metadata>
00402         """
00403         self.marshaller.demarshall(sidnei, lines_xml)
00404         self.assertEquals(sidnei.getFoodPrefs(),
00405                           ('BBQ', 'Camaron Diablo'))
00406         ctype, length, got = self.marshaller.marshall(sidnei)
00407         expected = [s.strip() for s in """\
00408         <field id="food_preference">
00409         BBQ
00410         </field>
00411         <field id="food_preference">
00412         Camaron Diablo
00413         </field>""".splitlines()]
00414         got = [s.strip() for s in got.splitlines()]
00415         comp = [s for s in expected if s in got]
00416         self.assertEquals(comp, expected)
00417 
00418 class BlobMarshallTest(BaseTest):
00419 
00420     def afterSetUp(self):
00421         super(BlobMarshallTest, self).afterSetUp()
00422         self.loginPortalOwner()
00423         self.qi = self.portal.portal_quickinstaller
00424         self.qi.installProduct('Marshall')
00425         self.tool = getToolByName(self.portal, tool_id)
00426         self.marshaller = getComponent('atxml')
00427 
00428     def createBlob(self, ctx, id, **kw):
00429         blob.addBlob(ctx, id, **kw)
00430         ob = ctx._getOb(id)
00431         ob.indexObject()
00432         return ob
00433 
00434     def _test_blob_roundtrip(self, fname, data, mimetype, filename):
00435         blob = self.createBlob(self.portal, 'blob')
00436 
00437         field = blob.Schema()[fname]
00438         field.set(blob, data, mimetype=mimetype, filename=filename)
00439 
00440         # Marshall to XML
00441         ctype, length, got = self.marshaller.marshall(blob)
00442 
00443         # Populate from XML
00444         self.marshaller.demarshall(blob, got)
00445 
00446         # Marshall from XML again and compare to see if it's
00447         # unchanged.
00448         ctype, length, got2 = self.marshaller.marshall(blob)
00449         self.assertEqualsDiff(got, got2)
00450 
00451     def test_blob_image(self):
00452         data = get_data('image.gif')
00453         self._test_blob_roundtrip('aimage', data, 'image/gif', 'image.gif')
00454 
00455     def test_blob_file_text(self):
00456         data = get_data('file.txt')
00457         self._test_blob_roundtrip('afile', data, 'text/plain', 'file.txt')
00458 
00459     def test_blob_file_binary(self):
00460         data = get_data('file.pdf')
00461         self._test_blob_roundtrip('afile', data, 'application/pdf', 'file.pdf')
00462 
00463     def test_blob_file_html(self):
00464         data = get_data('file.html')
00465         self._test_blob_roundtrip('afile', data, 'text/html', 'file.html')
00466 
00467     def test_blob_text_text(self):
00468         data = get_data('file.txt')
00469         self._test_blob_roundtrip('atext', data, 'text/plain', 'file.txt')
00470 
00471     def test_blob_text_binary(self):
00472         data = get_data('file.pdf')
00473         self._test_blob_roundtrip('atext', data, 'application/pdf', 'file.pdf')
00474 
00475     def test_blob_text_html(self):
00476         data = get_data('file.html')
00477         self._test_blob_roundtrip('atext', data, 'text/html', 'file.html')
00478 
00479 from zExceptions.ExceptionFormatter import format_exception
00480 from ZPublisher.HTTPResponse import HTTPResponse
00481 
00482 orig_exception = HTTPResponse.exception
00483 def exception(self, **kw):
00484     def tag_search(*args):
00485         return False
00486     kw['tag_search'] = tag_search
00487     return orig_exception(self, **kw)
00488 
00489 orig_setBody = HTTPResponse.setBody
00490 def setBody(self, *args, **kw):
00491     kw['is_error'] = 0
00492     if len(args[0]) == 2:
00493         title, body = args[0]
00494         args = (body,) + args[1:]
00495     return orig_setBody(self, *args, **kw)
00496 
00497 def _traceback(self, t, v, tb, as_html=1):
00498     return ''.join(format_exception(t, v, tb, as_html=as_html))
00499 
00500 HTTPResponse._error_format = 'text/plain'
00501 HTTPResponse._traceback = _traceback
00502 HTTPResponse.exception = exception
00503 HTTPResponse.setBody = setBody
00504 
00505 class DocumentationTest(ZopeTestCase.Functional, BaseTest):
00506 
00507     def afterSetUp(self):
00508         super(DocumentationTest, self).afterSetUp()
00509         self.loginPortalOwner()
00510         self.qi = self.portal.portal_quickinstaller
00511         self.qi.installProduct('Marshall')
00512         self.qi.installProduct('ATContentTypes')
00513 
00514 def test_suite():
00515     import unittest
00516     from Testing.ZopeTestCase import FunctionalDocFileSuite
00517     suite = unittest.TestSuite()
00518     suite.addTest(FunctionalDocFileSuite('doc/README.txt',
00519                                          package='Products.Marshall',
00520                                          test_class=DocumentationTest))
00521 
00522     ## XXX: reenable Blob and Image tests
00523     #suite.addTest(unittest.makeSuite(ATXMLReferenceMarshallTest))
00524     #suite.addTest(unittest.makeSuite(BlobMarshallTest))
00525     dirs = glob.glob(os.path.join(PACKAGE_HOME, 'input', '*'))
00526     comps = [i['name'] for i in getRegisteredComponents()]
00527     for d in dirs:
00528         prefix = os.path.basename(d)
00529         if prefix not in comps:
00530             continue
00531         files = glob.glob(os.path.join(d, '*'))
00532         for f in files:
00533             if os.path.isdir(f):
00534                 continue
00535             f_name = os.path.basename(f)
00536             type_name = os.path.splitext(f_name)[0]
00537             k_dict = {'prefix':prefix,
00538                       'type_name':type_name,
00539                       'input':f}
00540             klass = type('%s%sTest' % (prefix, type_name),
00541                          (MarshallerTest,),
00542                          k_dict)
00543             suite.addTest(unittest.makeSuite(klass))
00544     return suite
00545 
00546 if __name__ == '__main__':
00547     framework(descriptions=1, verbosity=1)