source: products/quintagroup.transmogrifier/trunk/quintagroup/transmogrifier/tests.py @ 706

Last change on this file since 706 was 706, checked in by mylan, 17 years ago

Create 0.2 version tag.

File size: 29.9 KB
Line 
1import unittest
2import pprint
3import os
4
5from zope.testing import doctest, cleanup
6from zope.component import provideUtility, provideAdapter, adapts
7from zope.interface import classProvides, implements
8
9from collective.transmogrifier.interfaces import ISectionBlueprint, ISection
10from collective.transmogrifier.tests import tearDown
11from collective.transmogrifier.sections.tests import sectionsSetUp
12from collective.transmogrifier.sections.tests import SampleSource
13
14from Products.Five import zcml
15
16import quintagroup.transmogrifier
17from quintagroup.transmogrifier.xslt import stylesheet_registry
18
19class DataPrinter(object):
20    classProvides(ISectionBlueprint)
21    implements(ISection)
22
23    def __init__(self, transmogrifier, name, options, previous):
24        self.previous = previous
25        self.printkey = [i.strip() for i in options['print'].splitlines() if i.strip()]
26        if 'prettyprint' in options:
27            self.pprint = pprint.PrettyPrinter().pprint
28
29    def __iter__(self):
30        for item in self.previous:
31            if self.printkey:
32                data = item
33                for i in self.printkey:
34                    if i in data:
35                        data = data[i]
36                    else:
37                        data = None
38                        break
39                if data is not None:
40                    if hasattr(self, 'pprint'):
41                        self.pprint(data)
42                    else:
43                        print data
44            yield item
45
46ctSectionsSetup = sectionsSetUp
47def sectionsSetUp(test):
48    ctSectionsSetup(test)
49    import Products.Five
50    import Products.GenericSetup
51    import zope.annotation
52    zcml.load_config('meta.zcml', Products.Five)
53    zcml.load_config('permissions.zcml', Products.Five)
54    zcml.load_config('meta.zcml', Products.GenericSetup)
55    zcml.load_config('configure.zcml', zope.annotation)
56    zcml.load_config('configure.zcml', quintagroup.transmogrifier)
57
58    from Products.CMFCore import utils
59    def getToolByName(context, tool_id):
60        return context
61    utils.getToolByName = getToolByName
62
63    import Acquisition
64    def aq_base(obj):
65        return obj
66    Acquisition.aq_base = aq_base
67
68    provideUtility(DataPrinter,
69        name=u'quintagroup.transmogrifier.tests.dataprinter')
70
71def siteWalkerSetUp(test):
72    sectionsSetUp(test)
73
74    from Products.CMFCore.interfaces import IFolderish
75    from Products.Archetypes.interfaces import IBaseFolder
76
77    class MockContent(object):
78        path = ()
79
80        def getPhysicalPath(self):
81            return self.path
82
83        def getPortalTypeName(self):
84            return self.__class__.__name__
85
86    class Document(MockContent):
87        pass
88
89    class Folder(MockContent, dict):
90        implements(IBaseFolder)
91
92        contentItems = dict.items
93        contentValues = dict.values
94
95    class MockPortal(MockContent, dict):
96        implements(IFolderish)
97
98        contentItems = dict.items
99        contentValues = dict.values
100
101    portal = MockPortal()
102
103    test.globs['plone'] = portal
104    test.globs['transmogrifier'].context = test.globs['plone']
105
106    portal.path = ('', 'plone')
107    portal['document1'] = Document()
108    portal['document1'].path = ('', 'plone', 'document1')
109    portal['folder1'] = Folder()
110    portal['folder1'].path = ('', 'plone', 'folder1')
111    portal['folder1']['document2'] = Document()
112    portal['folder1']['document2'].path = ('', 'plone', 'folder1', 'document2')
113    portal['folder1']['folder2'] = Folder()
114    portal['folder1']['folder2'].path = ('', 'plone', 'folder1', 'folder2')
115    portal['document3'] = Document()
116    portal['document3'].path = ('', 'plone', 'document3')
117
118def manifestSetUp(test):
119    sectionsSetUp(test)
120
121    root = dict(
122        _path='',
123        _entries=(
124            ('news', 'Folder'),
125            ('events', 'Folder'),
126            ('front-page', 'Document'),
127            ('only-in-manifest', 'Document')
128        )
129    )
130
131    news = dict(
132        _path='news',
133        _entries=(
134            ('aggregator', 'Topic'),
135            ('once-more', 'File')
136        )
137    )
138
139    aggregator = dict(
140        _path='news/aggregator',
141    )
142
143    events = dict(
144        _path='events'
145    )
146
147    front_page = dict(
148        _path='front-page',
149    )
150
151    members = dict(
152        _path='Members'
153    )
154
155    class ManifestSource(SampleSource):
156        classProvides(ISectionBlueprint)
157        implements(ISection)
158
159        def __init__(self, *args, **kw):
160            super(ManifestSource, self).__init__(*args, **kw)
161            self.sample = (root, dict(), news, aggregator, events, front_page, members)
162
163    provideUtility(ManifestSource,
164        name=u'quintagroup.transmogrifier.tests.manifestsource')
165
166def marshallSetUp(test):
167    sectionsSetUp(test)
168
169    from Products.Archetypes.interfaces import IBaseObject
170
171    class Field(object):
172        def __init__(self, name):
173            self.name = name
174            self.obj = None
175
176        def getAccessor(self, obj):
177            self.obj = obj
178            return self
179
180        def getMutator(self, obj):
181            self.obj = obj
182            return self
183
184        def __call__(self, value=None):
185            if value is None:
186                return self.obj.fields[self.name]
187            else:
188                self.obj.fields[self.name] = value
189
190    class MockBase(object):
191        def __init__(self, effective=None):
192            self.fields = {
193                'effectiveDate': effective,
194                'modification_date': 'changed',
195            }
196
197        def checkCreationFlag(self):
198            return True
199
200        def unmarkCreationFlag(self):
201            pass
202
203        def at_post_create_script(self):
204            pass
205
206        def at_post_edit_script(self):
207            pass
208
209        indexed = ()
210        def indexObject(self):
211            self.indexed += (self._last_path,)
212
213        def getField(self, fname):
214            return Field(fname)
215
216    class MockCriterion(MockBase):
217        implements(IBaseObject)
218        _last_path = None
219        indexed = ()
220        def indexObject(self):
221            self.indexed += (self._last_path,)
222
223    class MockPortal(MockBase):
224        implements(IBaseObject)
225
226        criterion = MockCriterion('not changed')
227
228        _last_path = None
229        def unrestrictedTraverse(self, path, default):
230            if path[0] == '/':
231                return default # path is absolute
232            if isinstance(path, unicode):
233                return default
234            if path == 'not/existing/bar':
235                return default
236            if path == 'topic/criterion':
237                self._last_path = path
238                self.criterion._last_path = path
239                return self.criterion
240            if path.endswith('/notatcontent'):
241                return object()
242            self._last_path = path
243            return self
244
245        def getId(self):
246            return "plone"
247
248        indexed = ()
249        def indexObject(self):
250            self.indexed += (self._last_path,)
251
252        updatedRoles = False
253        def updateRoleMappings(self):
254            self.updatedRoles = True
255
256        reindexed = False
257        def reindexIndex(self, name, extra=None):
258            self.reindexed = True
259
260        marshalled = ()
261        def marshall(self, instance, **kwargs):
262            self.marshalled += ((self._last_path, kwargs.get('atns_exclude')),)
263            # Marshall often fails to export topic criteria
264            if isinstance(instance, MockCriterion):
265                return None, None, None
266            else:
267                return None, None, "marshalled"
268
269        demarshalled = ()
270        def demarshall(self, instance, data):
271            # we don't need to test Marshall product, only check if we call it's components
272            self.demarshalled += (self._last_path,)
273
274    portal = MockPortal()
275    test.globs['plone'] = portal
276    test.globs['transmogrifier'].context = test.globs['plone']
277
278    from Products.Marshall import registry
279    def getComponent(name):
280        return portal
281    registry.getComponent = getComponent
282
283    class MarshallSource(SampleSource):
284        classProvides(ISectionBlueprint)
285        implements(ISection)
286
287        def __init__(self, *args, **kw):
288            super(MarshallSource, self).__init__(*args, **kw)
289            self.sample = (
290                dict(),
291                dict(_path='spam/eggs/foo', _excluded_fields=('file', 'image')),
292                dict(_path='topic/criterion'),
293                dict(_path='not/existing/bar'),
294                dict(_path='spam/eggs/notatcontent', 
295                     _files=dict(marshall=dict(data='xml', name='.marshall.xml'))),
296            )
297    provideUtility(MarshallSource,
298        name=u'quintagroup.transmogrifier.tests.marshallsource')
299
300def propertyManagerSetUp(test):
301    sectionsSetUp(test)
302
303    from OFS.interfaces import IPropertyManager
304
305    class MockPortal(object):
306        implements(IPropertyManager)
307
308        _properties = (
309            {'id':'title', 'type': 'string', 'mode': 'w'},
310            {'id':'description', 'type': 'string', 'mode': 'w'},
311            {'id':'encoding', 'type': 'string', 'mode': 'w'},
312            {'id':'author', 'type': 'string', 'mode': 'w'}
313        )
314
315        _last_path = None
316        def unrestrictedTraverse(self, path, default):
317            if path[0] == '/':
318                return default # path is absolute
319            if isinstance(path, unicode):
320                return default
321            if path == 'not/existing/bar':
322                return default
323            if path.endswith('/notatcontent'):
324                return object()
325            self._last_path = path
326            return self
327
328        def _propertyMap(self):
329            return self._properties
330
331        def getProperty(self, id, d=None):
332            return 'value'
333
334        def propdict(self):
335            d={}
336            for p in self._properties:
337                d[p['id']]=p
338            return d
339
340        updated = ()
341        def _updateProperty(self, id, value):
342            self.updated += ((self._last_path, id, value))
343
344    portal = MockPortal()
345    test.globs['plone'] = portal
346    test.globs['transmogrifier'].context = test.globs['plone']
347
348    class PropertyManagerSource(SampleSource):
349        classProvides(ISectionBlueprint)
350        implements(ISection)
351
352        def __init__(self, *args, **kw):
353            super(PropertyManagerSource, self).__init__(*args, **kw)
354            self.sample = (
355                dict(),
356                dict(_path='not/existing/bar'),
357                dict(_path='spam/eggs/notatcontent'),
358                dict(_path='spam/eggs/foo', _excluded_properties=('encoding',)),
359            )
360
361    provideUtility(PropertyManagerSource,
362        name=u'quintagroup.transmogrifier.tests.propertymanagersource')
363
364def commentsSetUp(test):
365    sectionsSetUp(test)
366
367    class MockDiscussionItem(object):
368        creator = 'creator'
369        modified = 'date'
370
371        def __init__(self, reply, text=""):
372            self.in_reply_to = reply
373            self.text = text
374
375        def __of__(self, container):
376            return self
377
378        def getMetadataHeaders(self):
379            return []
380
381        def setMetadata(self, headers):
382            pass
383
384        def Creator(self):
385            return self.creator
386
387        def addCreator(self, creator):
388            self.creator = creator
389
390        def ModificationDate(self):
391            return self.modified
392
393        def setModificationDate(self, date):
394            self.modified = date
395
396        def setFormat(self, format):
397            pass
398
399        def _edit(self, text=None):
400            self.text = text
401
402        def indexObject(self):
403            pass
404
405        def __repr__(self):
406            return "<DicussionItem %s %s %s %s>" % (
407                self.Creator(),
408                self.ModificationDate(),
409                self.in_reply_to,
410                self.text
411                )
412
413    from Products.CMFDefault import DiscussionItem
414    DiscussionItem.DiscussionItem = MockDiscussionItem
415
416    class MockPortal(object):
417        _discussion = {
418            '1': MockDiscussionItem(None, 'comment to content'),
419            '2': MockDiscussionItem('1', 'reply to first comment'),
420            '3': MockDiscussionItem(None, 'other comment to content')
421        }
422        _container = {}
423
424        @property
425        def talkback(self):
426            return self
427
428        def objectItems(self):
429            l = self._discussion.items()
430            l.sort(key=lambda x: int(x[0]))
431            return l
432
433        def unrestrictedTraverse(self, path, default):
434            if path[0] == '/':
435                return default # path is absolute
436            if isinstance(path, unicode):
437                return default
438            if path == 'not/existing/bar':
439                return default
440            if path.endswith('/notdiscussable'):
441                return object()
442            return self
443
444        def getDiscussionFor(self, obj):
445            return self
446
447    portal = MockPortal()
448    test.globs['plone'] = portal
449    test.globs['transmogrifier'].context = test.globs['plone']
450
451    class CommentsSource(SampleSource):
452        classProvides(ISectionBlueprint)
453        implements(ISection)
454
455        def __init__(self, *args, **kw):
456            super(CommentsSource, self).__init__(*args, **kw)
457            self.sample = (
458                dict(),
459                dict(_path='not/existing/bar'),
460                dict(_path='spam/eggs/notdiscussable'),
461                dict(_path='spam/eggs/foo'),
462            )
463
464    provideUtility(CommentsSource,
465        name=u'quintagroup.transmogrifier.tests.commentssource')
466
467
468def dataCorrectorSetUp(test):
469    sectionsSetUp(test)
470
471    class MockPortal(object):
472        def unrestrictedTraverse(self, path, default):
473            if path[0] == '/':
474                return default # path is absolute
475            if isinstance(path, unicode):
476                return default
477            if path == 'not/existing/bar':
478                return default
479            if path.endswith('/notadaptable'):
480                return object()
481            return self
482
483    portal = MockPortal()
484    test.globs['plone'] = portal
485    test.globs['transmogrifier'].context = test.globs['plone']
486
487    from quintagroup.transmogrifier.interfaces import IExportDataCorrector, \
488        IImportDataCorrector
489
490    class MockExportAdapter(object):
491        implements(IExportDataCorrector)
492        adapts(MockPortal)
493        def __init__(self, context):
494            self.context = context
495
496        def __call__(self, data):
497            return "modified export data"
498
499    provideAdapter(MockExportAdapter, name="marshall")
500
501    class MockImportAdapter(object):
502        implements(IImportDataCorrector)
503        adapts(MockPortal)
504        def __init__(self, context):
505            self.context = context
506
507        def __call__(self, data):
508            return "modified import data"
509
510    provideAdapter(MockImportAdapter, name="manifest")
511
512    class DataCorrectorSource(SampleSource):
513        classProvides(ISectionBlueprint)
514        implements(ISection)
515
516        def __init__(self, *args, **kw):
517            super(DataCorrectorSource, self).__init__(*args, **kw)
518            self.sample = (
519                dict(),
520                dict(_files=dict(marshall="item hasn't path")),
521                dict(_path='spam/eggs/foo'),
522                dict(_path='not/existing/bar'),
523                dict(_path='spam/eggs/notadaptable', _files=dict(marshall="object isn't adaptable")),
524                dict(_path='spam/eggs/foo',
525                     _files=dict(marshall='marshall data', unchanged='this must be unchanged')),
526                dict(_path='spam/eggs/foo',
527                     _files=dict(manifest='manifest data', unchanged='this must be unchanged')),
528            )
529
530    provideUtility(DataCorrectorSource,
531        name=u'quintagroup.transmogrifier.tests.datacorrectorsource')
532
533def writerSetUp(test):
534    sectionsSetUp(test)
535
536    class MockExportContext(object):
537        def __init__( self, *args, **kwargs):
538            self.args = args
539            for k, v in kwargs.items():
540                setattr(self, k, v)
541            self._wrote = []
542
543        def __getitem__(self, name):
544            return getattr(self, name, None)
545
546        def __contains__(self, name):
547            return hasattr(self, name)
548
549        def writeDataFile(self, filename, text, content_type, subdir=None):
550            filename = '%s/%s' % (subdir, filename)
551            self._wrote.append((filename, text, content_type))
552
553        def __repr__(self):
554            s = " ".join(["%s=%s" % (k,v) for k,v in self.__dict__.items()])
555            return "<%s %s>" % (self.__class__.__name__, s)
556
557
558    from Products.GenericSetup import context
559
560    context.DirectoryExportContext = type('Directory', (MockExportContext,), {})
561    context.TarballExportContext = type('Tarball', (MockExportContext,), {})
562    context.SnapshotExportContext = type('Snapshot', (MockExportContext,), {})
563
564    class WriterSource(SampleSource):
565        classProvides(ISectionBlueprint)
566        implements(ISection)
567
568        def __init__(self, *args, **kw):
569            super(WriterSource, self).__init__(*args, **kw)
570            self.sample = (
571                dict(_path='spam/eggs/foo'),
572                dict(_files=dict(mock=dict(name='.first.xml', data='some data'))),
573                dict(_path='spam/eggs/foo',
574                     _files=dict(mock=dict(name='.first.xml', data='some data'),
575                                 other=dict(name='.second.xml', data='other data'))),
576                dict(_path='other/path',
577                     _files=dict(mock=dict(name='.third.xml', data='some data')))
578            )
579
580    provideUtility(WriterSource,
581        name=u'quintagroup.transmogrifier.tests.writersource')
582
583    class SingleItemSource(SampleSource):
584        classProvides(ISectionBlueprint)
585        implements(ISection)
586
587        def __init__(self, *args, **kw):
588            super(SingleItemSource, self).__init__(*args, **kw)
589            self.sample = (
590                dict(_path='', _files={}),
591            )
592
593    provideUtility(SingleItemSource,
594        name=u"quintagroup.transmogrifier.tests.singleitemsource")
595
596def readerSetUp(test):
597    sectionsSetUp(test)
598
599    class MockImportContext(object):
600
601        _dirs = [
602            'structure',
603            'structure/news', 'structure/news/recent',
604            'structure/pages', 'structure/pages/front-page',
605        ]
606        _files = [
607            'structure/.properties.xml',
608            'structure/other.file',
609            'structure/news/.objects.xml',
610            'structure/pages/.objects.xml',
611            'structure/pages/front-page/.marshall.xml',
612            'structure/pages/front-page/.comments.xml',
613        ]
614
615        def __init__( self, *args, **kwargs):
616            self.args = args
617            for k, v in kwargs.items():
618                setattr(self, k, v)
619
620        def __repr__(self):
621            s = " ".join(["%s=%s" % (k,v) for k,v in self.__dict__.items()])
622            return "<%s %s>" % (self.__class__.__name__, s)
623
624        def readDataFile(self, filename, subdir=None):
625            return 'some data'
626
627        def isDirectory(self, path):
628            return path == '' or path in self._dirs
629
630        def listDirectory(self, path):
631            all_names = self._dirs + self._files
632            if path:
633                pfx_len = len(path)+1
634            else:
635                pfx_len = 0
636            names = []
637            for name in all_names:
638                if name == path:
639                    continue
640                if not name.startswith(path):
641                    continue
642                name = name[pfx_len:]
643                if '/' in name:
644                    continue
645                names.append(name)
646            return names
647
648    from Products.GenericSetup import context
649
650    context.DirectoryImportContext = type('Directory', (MockImportContext,),
651        {'listDirectory': lambda self, path: []})
652    context.TarballImportContext = type('Tarball', (MockImportContext,), {})
653    context.SnapshotImportContext = type('Snapshot', (MockImportContext,),
654        {'listDirectory': lambda self, path: []})
655
656def substitutionSetUp(test):
657    sectionsSetUp(test)
658
659    class SubstitutionSource(SampleSource):
660        classProvides(ISectionBlueprint)
661        implements(ISection)
662
663        def __init__(self, *args, **kw):
664            super(SubstitutionSource, self).__init__(*args, **kw)
665            self.sample = (
666                {},
667                {'_type': 'Blog'},
668                {'_type': 'PloneFormMailer'},
669                {'_type': 'Document'},
670            )
671
672    provideUtility(SubstitutionSource,
673        name=u'quintagroup.transmogrifier.tests.substitutionsource')
674
675class MetaDirectivesTests(unittest.TestCase):
676    def setUp(self):
677        zcml.load_config('meta.zcml', quintagroup.transmogrifier)
678
679    def tearDown(self):
680        stylesheet_registry.clear()
681        cleanup.cleanUp()
682
683    def testEmptyZCML(self):
684        zcml.load_string('''\
685<configure xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
686</configure>''')
687        self.assertEqual(stylesheet_registry.listStylesheetNames(), ())
688
689    def testConfigZCML(self):
690        zcml.load_string('''\
691<configure
692    xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
693<transmogrifier:stylesheet
694    source="marshall"
695    from="Blog"
696    to="Weblog"
697    file="blog.xsl"
698    />
699</configure>''')
700        self.assertEqual(stylesheet_registry.listStylesheetNames(),
701                         (u'marshall:Blog:Weblog',))
702        path = os.path.split(quintagroup.transmogrifier.__file__)[0]
703        self.assertEqual(
704            stylesheet_registry.getStylesheet('marshall', 'Blog', 'Weblog'),
705            dict(from_=u'Blog',
706                 to=u'Weblog',
707                 file=os.path.join(path, 'blog.xsl'))
708        )
709
710    def testMultipleZCML(self):
711        zcml.load_string('''\
712<configure
713    xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
714<transmogrifier:stylesheet
715    source="marshall"
716    from="Blog"
717    to="Weblog"
718    file="blog.xsl"
719    />
720<transmogrifier:stylesheet
721    source="propertymanager"
722    from="BlogEntry"
723    to="WeblogEntry"
724    file="blogentry.xsl"
725    />
726</configure>''')
727        self.assertEqual(stylesheet_registry.listStylesheetNames(),
728                         (u'marshall:Blog:Weblog', u'propertymanager:BlogEntry:WeblogEntry'))
729
730def xsltSetUp(test):
731    sectionsSetUp(test)
732
733    class XSLTSource(SampleSource):
734        classProvides(ISectionBlueprint)
735        implements(ISection)
736
737        def __init__(self, *args, **kw):
738            super(XSLTSource, self).__init__(*args, **kw)
739            self.sample = (
740                {},
741                {'_type': 'Weblog'},
742                {'_old_type': 'Blog'},
743                {'_old_type': 'Blog',
744                 '_type': 'Weblog',
745                 '_files': {'manifest': {'data': 'xml', 'name': 'manifest.xml'}}},
746                {'_old_type': 'Blog',
747                 '_type': 'Weblog',
748                 '_files': {'marshall': {'data': 'xml', 'name': 'marshall.xml'}}},
749            )
750
751    provideUtility(XSLTSource,
752        name=u'quintagroup.transmogrifier.tests.xsltsource')
753
754    from quintagroup.transmogrifier.xslt import XSLTSection, stylesheet_registry
755
756    XSLTSection.applyTransformations = lambda self, xml, xslt: 'transformed xml'
757    test.globs['stylesheet_registry'] = stylesheet_registry
758
759def binarySetUp(test):
760    sectionsSetUp(test)
761
762    from Products.Archetypes.interfaces import IBaseObject
763
764    class MockPortal(object):
765        implements(IBaseObject)
766
767        _last_path = None
768        def unrestrictedTraverse(self, path, default):
769            if path[0] == '/':
770                return default # path is absolute
771            if isinstance(path, unicode):
772                return default
773            if path == 'not/existing/bar':
774                return default
775            if path.endswith('/notatcontent'):
776                return object()
777            self._last_path = path
778            return self
779
780        fields = ['id', 'title', 'file', 'image']
781
782        def Schema(self):
783            return dict.fromkeys(self.fields)
784
785        def isBinary(self, field):
786            return field in ('file', 'image')
787
788        _current_field = None
789        def getField(self, field):
790            self._current_field = field
791            return self
792
793        def getBaseUnit(self, obj):
794            return self
795
796        def getFilename(self):
797            if self._current_field == 'file':
798                return 'archive.tar.gz'
799            else:
800                return ''
801
802        def getContentType(self):
803            if self._current_field == 'file':
804                return 'application/x-tar'
805            else:
806                return 'image/png'
807
808        def getRaw(self):
809            if self._current_field == 'file':
810                return 'binary data'
811            else:
812                return ''
813
814        def getMutator(self, obj):
815            return self
816
817        updated = ()
818        def __call__(self, data, filename=None, mimetype=None):
819            self.updated += (filename, mimetype, data)
820
821    portal = MockPortal()
822    test.globs['plone'] = portal
823    test.globs['transmogrifier'].context = test.globs['plone']
824
825    class BinarySource(SampleSource):
826        classProvides(ISectionBlueprint)
827        implements(ISection)
828
829        def __init__(self, *args, **kw):
830            super(BinarySource, self).__init__(*args, **kw)
831            self.sample = (
832                dict(),
833                dict(_path='not/existing/bar'),
834                dict(_path='spam/eggs/notatcontent'),
835                dict(_path='spam/eggs/foo'),
836            )
837
838    provideUtility(BinarySource,
839        name=u'quintagroup.transmogrifier.tests.binarysource')
840
841from DateTime import DateTime
842
843def catalogSourceSetUp(test):
844    sectionsSetUp(test)
845
846    class MockContent(dict):
847        def __init__(self, **kw):
848            self.update(kw)
849            self['id'] = self.getId
850
851        def getPath(self):
852            return self['path']
853
854        @property
855        def getId(self):
856            path = self.getPath()
857            return path.rsplit('/', 1)[-1]
858
859        @property
860        def portal_type(self):
861            return self['portal_type']
862
863        @property
864        def is_folderish(self):
865            return self['portal_type'] == 'Folder' and True or False
866
867    class MockPortal(dict):
868
869        content = ()
870        def __call__(self, **kw):
871            res = []
872            for obj in self.content:
873                matched = True
874                for index, query in kw.items():
875                    if index not in obj:
876                        matched = False
877                        break
878                    if matched and index == 'modified':
879                        if isinstance(query, dict):
880                            value = query['query']
881                            range_ = query['range']
882                            if range_ == 'min' and DateTime(obj[index]) >= DateTime(value):
883                                matched = True
884                            elif range_ == 'max' and DateTime(obj[index]) <= DateTime(value):
885                                matched = True
886                            else:
887                                matched = False
888                        else:
889                            if DateTime(obj[index]) == DateTime(query):
890                                matched = True
891                            else:
892                                matched = False
893                    elif matched and index == 'path':
894                        if obj[index].startswith(query):
895                            matched = True
896                        else:
897                            matched = False
898                    elif matched:
899                        if obj[index] == query:
900                            matched = True
901                        else:
902                            matched = False
903                if matched:
904                    res.append(obj)
905
906            return res
907
908    portal = MockPortal()
909    doc1 = MockContent(path='/plone/document1', portal_type='Document',
910        modified='2008-11-01T12:00:00Z')
911    folder1 = MockContent(path='/plone/folder1', portal_type='Folder',
912        modified='2008-11-01T12:00:00Z')
913    doc2 = MockContent(path='/plone/folder1/document2', portal_type='Document',
914        modified='2008-11-02T12:00:00Z')
915    doc3 = MockContent(path='/plone/folder1/document3', portal_type='Document',
916        modified='2008-11-02T12:00:00Z')
917    folder2 = MockContent(path='/plone/folder2', portal_type='Folder',
918        modified='2008-11-02T12:00:00Z')
919    doc4 = MockContent(path='/plone/folder2/document4', portal_type='Document',
920        modified='2008-11-01T12:00:00Z')
921    comment = MockContent(path='/plone/folder2/document4/talkback/1234567890', portal_type='Discussion Item',
922        modified='2008-11-02T12:00:00Z')
923    # items are sorted on their modification date
924    portal.content = (doc1, folder1, folder2, doc2, doc3, doc4, comment)
925
926    test.globs['plone'] = portal
927    test.globs['transmogrifier'].context = test.globs['plone']
928
929def test_suite():
930    import sys
931    suite = unittest.findTestCases(sys.modules[__name__])
932    suite.addTests((
933        doctest.DocFileSuite(
934            'sitewalker.txt',
935            setUp=siteWalkerSetUp, tearDown=tearDown),
936        doctest.DocFileSuite(
937            'manifest.txt',
938            setUp=manifestSetUp, tearDown=tearDown),
939        doctest.DocFileSuite(
940            'marshall.txt',
941            setUp=marshallSetUp, tearDown=tearDown),
942        doctest.DocFileSuite(
943            'propertymanager.txt',
944            setUp=propertyManagerSetUp, tearDown=tearDown),
945        doctest.DocFileSuite(
946            'comments.txt',
947            setUp=commentsSetUp, tearDown=tearDown),
948        doctest.DocFileSuite(
949            'datacorrector.txt',
950            setUp=dataCorrectorSetUp, tearDown=tearDown),
951        doctest.DocFileSuite(
952            'writer.txt',
953            setUp=writerSetUp, tearDown=tearDown),
954        doctest.DocFileSuite(
955            'reader.txt',
956            setUp=readerSetUp, tearDown=tearDown),
957        doctest.DocFileSuite(
958            'substitution.txt',
959            setUp=substitutionSetUp, tearDown=tearDown),
960        doctest.DocFileSuite(
961            'xslt.txt',
962            setUp=xsltSetUp, tearDown=tearDown),
963        doctest.DocFileSuite(
964            'binary.txt',
965            setUp=binarySetUp, tearDown=tearDown),
966        doctest.DocFileSuite(
967            'catalogsource.txt',
968            setUp=catalogSourceSetUp, tearDown=tearDown),
969    ))
970    return suite
Note: See TracBrowser for help on using the repository browser.