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

Last change on this file since 275 was 275, checked in by mylan, 18 years ago

Removed file/folder

File size: 21.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
19# Doctest support
20
21class DataPrinter(object):
22    classProvides(ISectionBlueprint)
23    implements(ISection)
24
25    def __init__(self, transmogrifier, name, options, previous):
26        self.previous = previous
27        self.printkey = [i.strip() for i in options['print'].splitlines() if i.strip()]
28        if 'prettyprint' in options:
29            self.pprint = pprint.PrettyPrinter().pprint
30
31    def __iter__(self):
32        for item in self.previous:
33            if self.printkey:
34                data = item
35                for i in self.printkey:
36                    if i in data:
37                        data = data[i]
38                    else:
39                        data = None
40                        break
41                if data is not None:
42                    if hasattr(self, 'pprint'):
43                        self.pprint(data)
44                    else:
45                        print data
46            yield item
47
48ctSectionsSetup = sectionsSetUp
49def sectionsSetUp(test):
50    ctSectionsSetup(test)
51    # load meta.zcml of directives that are used in out package config
52    import Products.GenericSetup
53    zcml.load_config('meta.zcml', Products.GenericSetup)
54    zcml.load_config('configure.zcml', quintagroup.transmogrifier)
55
56    provideUtility(DataPrinter,
57        name=u'quintagroup.transmogrifier.tests.dataprinter')
58
59def siteWalkerSetUp(test):
60    sectionsSetUp(test)
61
62    from Products.CMFCore.interfaces import IFolderish
63    from Products.Archetypes.interfaces import IBaseFolder
64
65    class MockContent(object):
66        path = ()
67
68        def getPhysicalPath(self):
69            return self.path
70
71        def getPortalTypeName(self):
72            return self.__class__.__name__
73
74    class Document(MockContent):
75        pass
76
77    class Folder(MockContent, dict):
78        implements(IBaseFolder)
79
80        contentItems = dict.items
81        contentValues = dict.values
82
83    class MockPortal(MockContent, dict):
84        implements(IFolderish)
85
86        contentItems = dict.items
87        contentValues = dict.values
88
89    portal = MockPortal()
90
91    test.globs['plone'] = portal
92    test.globs['transmogrifier'].context = test.globs['plone']
93
94    portal.path = ('', 'plone')
95    portal['document1'] = Document()
96    portal['document1'].path = ('', 'plone', 'document1')
97    portal['folder1'] = Folder()
98    portal['folder1'].path = ('', 'plone', 'folder1')
99    portal['folder1']['document2'] = Document()
100    portal['folder1']['document2'].path = ('', 'plone', 'folder1', 'document2')
101    portal['folder1']['folder2'] = Folder()
102    portal['folder1']['folder2'].path = ('', 'plone', 'folder1', 'folder2')
103    portal['document3'] = Document()
104    portal['document3'].path = ('', 'plone', 'document3')
105
106def manifestSetUp(test):
107    sectionsSetUp(test)
108
109    item = {'_entries' : (
110        ('document1', 'Document'),
111        ('folder1', 'Folder'),
112        ('document3', 'Document'),)
113    }
114
115    class ManifestSource(SampleSource):
116        classProvides(ISectionBlueprint)
117        implements(ISection)
118
119        def __init__(self, *args, **kw):
120            super(ManifestSource, self).__init__(*args, **kw)
121            self.sample = (item, dict())
122
123    provideUtility(ManifestSource,
124        name=u'quintagroup.transmogrifier.tests.manifestsource')
125
126    from quintagroup.transmogrifier.manifest import ManifestSection
127    section = ManifestSection(test.globs['transmogrifier'], 
128        'manifest', {'blueprint': ''}, iter(()))
129    data = section.createManifest(item['_entries'])
130    test.globs['data'] = data
131
132def marshallSetUp(test):
133    sectionsSetUp(test)
134
135    from Products.Archetypes.interfaces import IBaseObject
136
137    class MockCriterion(object):
138        implements(IBaseObject)
139
140    class MockPortal(object):
141        implements(IBaseObject)
142
143        _last_path = None
144        def unrestrictedTraverse(self, path, default):
145            if path[0] == '/':
146                return default # path is absolute
147            if isinstance(path, unicode):
148                return default
149            if path == 'not/existing/bar':
150                return default
151            if path == 'topic/criterion':
152                self._last_path = path
153                return MockCriterion()
154            if path.endswith('/notatcontent'):
155                return object()
156            self._last_path = path
157            return self
158
159        def getId(self):
160            return "plone"
161
162        exported = ()
163        def marshall(self, instance, **kwargs):
164            self.exported += ((self._last_path, kwargs.get('atns_exclude')),)
165            # Marshall often fails to export topic criteria
166            if isinstance(instance, MockCriterion):
167                return None, None, None
168            else:
169                return None, None, "marshalled"
170
171    portal = MockPortal()
172    test.globs['plone'] = portal
173    test.globs['transmogrifier'].context = test.globs['plone']
174
175    from Products.Marshall import registry
176    def getComponent(name):
177        return portal
178    registry.getComponent = getComponent
179
180    class MarshallSource(SampleSource):
181        classProvides(ISectionBlueprint)
182        implements(ISection)
183
184        def __init__(self, *args, **kw):
185            super(MarshallSource, self).__init__(*args, **kw)
186            self.sample = (
187                dict(_path='spam/eggs/foo', _excluded_fields=('fieldone','fieldtwo')),
188                dict(_path='topic/criterion'),
189                dict(_path='not/existing/bar'),
190                dict(),
191                dict(_path='spam/eggs/notatcontent'),
192            )
193    provideUtility(MarshallSource,
194        name=u'quintagroup.transmogrifier.tests.marshallsource')
195
196def propertyManagerSetUp(test):
197    sectionsSetUp(test)
198
199    from OFS.interfaces import IPropertyManager
200
201    class MockPortal(object):
202        implements(IPropertyManager)
203
204        _last_path = None
205        def unrestrictedTraverse(self, path, default):
206            if path[0] == '/':
207                return default # path is absolute
208            if isinstance(path, unicode):
209                return default
210            if path == 'not/existing/bar':
211                return default
212            if path.endswith('/notatcontent'):
213                return object()
214            self._last_path = path
215            return self
216
217        updated = ()
218        def _propertyMap(self):
219            self.updated += (self._last_path,)
220            return ({'id':'propone', 'type': 'string', 'mode': 'w'},
221                    {'id':'proptwo', 'type': 'string', 'mode': 'w'},
222                    {'id':'propthree', 'type': 'string', 'mode': 'w'},
223                    {'id':'propfour', 'type': 'string', 'mode': 'w'})
224
225        def getProperty(id, d=None):
226            return 'value'
227
228    portal = MockPortal()
229    test.globs['plone'] = portal
230    test.globs['transmogrifier'].context = test.globs['plone']
231
232    class PropertyManagerSource(SampleSource):
233        classProvides(ISectionBlueprint)
234        implements(ISection)
235
236        def __init__(self, *args, **kw):
237            super(PropertyManagerSource, self).__init__(*args, **kw)
238            self.sample = (
239                dict(_path='spam/eggs/foo', _excluded_properties=('proptwo','propthree')),
240                dict(_path='not/existing/bar'),
241                dict(),
242                dict(_path='spam/eggs/notatcontent'),
243            )
244
245    provideUtility(PropertyManagerSource,
246        name=u'quintagroup.transmogrifier.tests.propertymanagersource')
247
248def discussionContainerSetUp(test):
249    sectionsSetUp(test)
250
251    class MockDiscussionItem(object):
252        def __init__(self, reply, text):
253            self.in_reply_to = reply
254            self.text = text
255
256        def Creator(self):
257            return "creator"
258
259        def ModificationDate(self):
260            return "date"
261
262        def getMetadataHeaders(self):
263            return []
264
265    class MockPortal(object):
266        discussion = {
267            '1': MockDiscussionItem(None, 'comment to content'),
268            '2': MockDiscussionItem('1', 'reply to first comment'),
269            '3': MockDiscussionItem(None, 'other comment to content')
270        }
271
272        @property
273        def talkback(self):
274            return self
275
276        def objectItems(self):
277            l = self.discussion.items()
278            l.sort(key=lambda x: int(x[0]))
279            return l
280
281        def unrestrictedTraverse(self, path, default):
282            if path[0] == '/':
283                return default # path is absolute
284            if isinstance(path, unicode):
285                return default
286            if path == 'not/existing/bar':
287                return default
288            if path.endswith('/notdiscussable'):
289                return object()
290            return self
291
292    portal = MockPortal()
293    test.globs['plone'] = portal
294    test.globs['transmogrifier'].context = test.globs['plone']
295
296    import Acquisition
297    def aq_base(obj):
298        return obj
299    Acquisition.aq_base = aq_base
300
301    class DiscussionContainerSource(SampleSource):
302        classProvides(ISectionBlueprint)
303        implements(ISection)
304
305        def __init__(self, *args, **kw):
306            super(DiscussionContainerSource, self).__init__(*args, **kw)
307            self.sample = (
308                dict(_path='spam/eggs/foo'),
309                dict(_path='not/existing/bar'),
310                dict(),
311                dict(_path='spam/eggs/notdiscussable'),
312            )
313
314    provideUtility(DiscussionContainerSource,
315        name=u'quintagroup.transmogrifier.tests.discussioncontainersource')
316
317
318def exportAdaptersSetUp(test):
319    sectionsSetUp(test)
320
321    class MockPortal(object):
322        def unrestrictedTraverse(self, path, default):
323            if path[0] == '/':
324                return default # path is absolute
325            if isinstance(path, unicode):
326                return default
327            if path == 'not/existing/bar':
328                return default
329            if path.endswith('/notadaptable'):
330                return object()
331            return self
332
333    portal = MockPortal()
334    test.globs['plone'] = portal
335    test.globs['transmogrifier'].context = test.globs['plone']
336
337    from quintagroup.transmogrifier.exportadapters import IExportDataCorrector
338
339    class MockAdapter(object):
340        implements(IExportDataCorrector)
341        adapts(MockPortal)
342        def __init__(self, context):
343            self.context = context
344
345        def __call__(self, data):
346            return "modified data"
347
348    provideAdapter(MockAdapter, name="mock")
349
350    class ExportAdaptersSource(SampleSource):
351        classProvides(ISectionBlueprint)
352        implements(ISection)
353
354        def __init__(self, *args, **kw):
355            super(ExportAdaptersSource, self).__init__(*args, **kw)
356            self.sample = (
357                dict(_path='spam/eggs/foo',
358                     _files=dict(mock='some data', unchanged='this must be unchanged')),
359                dict(_path='not/existing/bar'),
360                dict(),
361                dict(_files=dict(mock="item hasn't path")),
362                dict(_path='spam/eggs/notadaptable', _files=dict(mock="object isn't adaptable")),
363            )
364
365    provideUtility(ExportAdaptersSource,
366        name=u'quintagroup.transmogrifier.tests.exportadapterssource')
367
368def writerSetUp(test):
369    sectionsSetUp(test)
370
371    class MockExportContext(object):
372        def __init__( self, *args, **kwargs):
373            self.args = args
374            for k, v in kwargs.items():
375                setattr(self, k, v)
376            self._wrote = []
377
378        def __getitem__(self, name):
379            return getattr(self, name, None)
380
381        def __contains__(self, name):
382            return hasattr(self, name)
383
384        def writeDataFile(self, filename, text, content_type, subdir=None):
385            filename = '%s/%s' % (subdir, filename)
386            self._wrote.append((filename, text, content_type))
387
388        def __repr__(self):
389            s = " ".join(["%s=%s" % (k,v) for k,v in self.__dict__.items()])
390            return "<%s %s>" % (self.__class__.__name__, s)
391
392
393    from Products.GenericSetup import context
394
395    context.DirectoryExportContext = type('Directory', (MockExportContext,), {})
396    context.TarballExportContext = type('Tarball', (MockExportContext,), {})
397    context.SnapshotExportContext = type('Snapshot', (MockExportContext,), {})
398
399    from Products.CMFCore import utils
400    def getToolByName(context, tool_id):
401        return context
402    utils.getToolByName = getToolByName
403
404    class WriterSource(SampleSource):
405        classProvides(ISectionBlueprint)
406        implements(ISection)
407
408        def __init__(self, *args, **kw):
409            super(WriterSource, self).__init__(*args, **kw)
410            self.sample = (
411                dict(_path='spam/eggs/foo'),
412                dict(_files=dict(mock=dict(name='.first.xml', data='some data'))),
413                dict(_path='spam/eggs/foo',
414                     _files=dict(mock=dict(name='.first.xml', data='some data'),
415                                 other=dict(name='.second.xml', data='other data'))),
416                dict(_path='other/path',
417                     _files=dict(mock=dict(name='.third.xml', data='some data')))
418            )
419
420    provideUtility(WriterSource,
421        name=u'quintagroup.transmogrifier.tests.writersource')
422
423    class SingleItemSource(SampleSource):
424        classProvides(ISectionBlueprint)
425        implements(ISection)
426
427        def __init__(self, *args, **kw):
428            super(SingleItemSource, self).__init__(*args, **kw)
429            self.sample = (
430                dict(_path='', _files={}),
431            )
432
433    provideUtility(SingleItemSource,
434        name=u"quintagroup.transmogrifier.tests.singleitemsource")
435
436def readerSetUp(test):
437    sectionsSetUp(test)
438
439    class MockImportContext(object):
440
441        _dirs = [
442            'structure',
443            'structure/news', 'structure/news/recent',
444            'structure/pages', 'structure/pages/front-page',
445        ]
446        _files = [
447            'structure/.properties.xml',
448            'structure/other.file',
449            'structure/news/.objects.xml',
450            'structure/pages/.objects.xml',
451            'structure/pages/front-page/.marshall.xml',
452            'structure/pages/front-page/.comments.xml',
453        ]
454
455        def __init__( self, *args, **kwargs):
456            self.args = args
457            for k, v in kwargs.items():
458                setattr(self, k, v)
459
460        def __repr__(self):
461            s = " ".join(["%s=%s" % (k,v) for k,v in self.__dict__.items()])
462            return "<%s %s>" % (self.__class__.__name__, s)
463
464        def readDataFile(self, filename, subdir=None):
465            return 'some data'
466
467        def isDirectory(self, path):
468            return path == '' or path in self._dirs
469
470        def listDirectory(self, path):
471            all_names = self._dirs + self._files
472            if path:
473                pfx_len = len(path)+1
474            else:
475                pfx_len = 0
476            names = []
477            for name in all_names:
478                if name == path:
479                    continue
480                if not name.startswith(path):
481                    continue
482                name = name[pfx_len:]
483                if '/' in name:
484                    continue
485                names.append(name)
486            return names
487
488    from Products.GenericSetup import context
489
490    context.DirectoryImportContext = type('Directory', (MockImportContext,),
491        {'listDirectory': lambda self, path: []})
492    context.TarballImportContext = type('Tarball', (MockImportContext,), {})
493    context.SnapshotImportContext = type('Snapshot', (MockImportContext,),
494        {'listDirectory': lambda self, path: []})
495
496    from Products.CMFCore import utils
497    def getToolByName(context, tool_id):
498        return context
499    utils.getToolByName = getToolByName
500
501def manifestImportSetUp(test):
502    sectionsSetUp(test)
503
504    man1 = """<?xml version="1.0" ?>
505<manifest>
506  <record type="Document">document1</record>
507  <record type="Folder">folder1</record>
508</manifest>
509"""
510
511    man2 = """<?xml version="1.0" ?>
512<manifest>
513  <record type="Document">document2</record>
514  <record type="Document">document3</record>
515</manifest>
516"""
517
518    item1 = dict(
519        _path='',
520        _files=dict(
521            manifest=dict(
522                name='.objects.xml',
523                data=man1
524            )
525        )
526    )
527
528    item2 = dict(
529        _path='document1',
530    )
531
532    item3 = dict(
533        _path='folder1',
534        _files=dict(
535            manifest=dict(
536                name='.objects.xml',
537                data=man2
538            )
539        )
540    )
541
542    item4 = dict(
543        _path='folder1/document2',
544    )
545
546    item5 = dict(
547        _path='document4',
548    )
549
550    class ManifestSource(SampleSource):
551        classProvides(ISectionBlueprint)
552        implements(ISection)
553
554        def __init__(self, *args, **kw):
555            super(ManifestSource, self).__init__(*args, **kw)
556            self.sample = (item1, dict(), item2, item3, item4, item5)
557
558    provideUtility(ManifestSource,
559        name=u'quintagroup.transmogrifier.tests.manifestsource')
560
561def substitutionSetUp(test):
562    sectionsSetUp(test)
563
564    class SubstitutionSource(SampleSource):
565        classProvides(ISectionBlueprint)
566        implements(ISection)
567
568        def __init__(self, *args, **kw):
569            super(SubstitutionSource, self).__init__(*args, **kw)
570            self.sample = (
571                {},
572                {'_type': 'Blog'},
573                {'_type': 'PloneFormMailer'},
574                {'_type': 'Document'},
575            )
576
577    provideUtility(SubstitutionSource,
578        name=u'quintagroup.transmogrifier.tests.substitutionsource')
579
580class MetaDirectivesTests(unittest.TestCase):
581    def setUp(self):
582        zcml.load_config('meta.zcml', quintagroup.transmogrifier)
583
584    def tearDown(self):
585        stylesheet_registry.clear()
586        cleanup.cleanUp()
587
588    def testEmptyZCML(self):
589        zcml.load_string('''\
590<configure xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
591</configure>''')
592        self.assertEqual(stylesheet_registry.listStylesheetNames(), ())
593
594    def testConfigZCML(self):
595        zcml.load_string('''\
596<configure
597    xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
598<transmogrifier:stylesheet
599    source="marshall"
600    from="Blog"
601    to="Weblog"
602    file="blog.xsl"
603    />
604</configure>''')
605        self.assertEqual(stylesheet_registry.listStylesheetNames(),
606                         (u'marshall:Blog:Weblog',))
607        path = os.path.split(quintagroup.transmogrifier.__file__)[0]
608        self.assertEqual(
609            stylesheet_registry.getStylesheet('marshall', 'Blog', 'Weblog'),
610            dict(from_=u'Blog',
611                 to=u'Weblog',
612                 file=os.path.join(path, 'blog.xsl'))
613        )
614
615    def testMultipleZCML(self):
616        zcml.load_string('''\
617<configure
618    xmlns:transmogrifier="http://namespaces.plone.org/transmogrifier">
619<transmogrifier:stylesheet
620    source="marshall"
621    from="Blog"
622    to="Weblog"
623    file="blog.xsl"
624    />
625<transmogrifier:stylesheet
626    source="propertymanager"
627    from="BlogEntry"
628    to="WeblogEntry"
629    file="blogentry.xsl"
630    />
631</configure>''')
632        self.assertEqual(stylesheet_registry.listStylesheetNames(),
633                         (u'marshall:Blog:Weblog', u'propertymanager:BlogEntry:WeblogEntry'))
634
635def xsltSetUp(test):
636    sectionsSetUp(test)
637
638    class XSLTSource(SampleSource):
639        classProvides(ISectionBlueprint)
640        implements(ISection)
641
642        def __init__(self, *args, **kw):
643            super(XSLTSource, self).__init__(*args, **kw)
644            self.sample = (
645                {},
646                {'_type': 'Weblog'},
647                {'_old_type': 'Blog'},
648                {'_old_type': 'Blog',
649                 '_type': 'Weblog',
650                 '_files': {'manifest': {'data': 'xml', 'name': 'marshall.xml'}}},
651                {'_old_type': 'Blog',
652                 '_type': 'Weblog',
653                 '_files': {'marshall': {'data': 'xml', 'name': 'marshall.xml'}}},
654            )
655
656    provideUtility(XSLTSource,
657        name=u'quintagroup.transmogrifier.tests.xsltsource')
658
659    import tempfile
660    from quintagroup.transmogrifier.xslt import XSLTSection, stylesheet_registry
661
662    XSLTSection.applyTransformations = lambda xml, xslt: 'transformed xml'
663
664    tmp = tempfile.NamedTemporaryFile('w+', suffix='.xsl')
665    tmp.write("stylesheet")
666    tmp.flush()
667
668    stylesheet_registry.registerStylesheet('marshall', 'Blog', 'Weblog', tmp.name)
669
670def test_suite():
671    import sys
672    suite = unittest.findTestCases(sys.modules[__name__])
673    suite.addTests((
674        doctest.DocFileSuite(
675            'sitewalker.txt',
676            setUp=siteWalkerSetUp, tearDown=tearDown),
677        doctest.DocFileSuite(
678            'manifest.txt',
679            setUp=manifestSetUp, tearDown=tearDown),
680        doctest.DocFileSuite(
681            'marshall.txt',
682            setUp=marshallSetUp, tearDown=tearDown),
683        doctest.DocFileSuite(
684            'propertymanager.txt',
685            setUp=propertyManagerSetUp, tearDown=tearDown),
686        doctest.DocFileSuite(
687            'discussioncontainer.txt',
688            setUp=discussionContainerSetUp, tearDown=tearDown),
689        doctest.DocFileSuite(
690            'exportadapters.txt',
691            setUp=exportAdaptersSetUp, tearDown=tearDown),
692        doctest.DocFileSuite(
693            'writer.txt',
694            setUp=writerSetUp, tearDown=tearDown),
695        doctest.DocFileSuite(
696            'reader.txt',
697            setUp=readerSetUp, tearDown=tearDown),
698        doctest.DocFileSuite(
699            'manifest_import.txt',
700            setUp=manifestImportSetUp, tearDown=tearDown),
701        doctest.DocFileSuite(
702            'substitution.txt',
703            setUp=substitutionSetUp, tearDown=tearDown),
704        doctest.DocFileSuite(
705            'xslt.txt',
706            setUp=xsltSetUp, tearDown=tearDown),
707    ))
708    return suite
Note: See TracBrowser for help on using the repository browser.