• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / Products.PluginRegistry / 12348256203

12 Jun 2024 06:30AM UTC coverage: 91.854% (-0.4%) from 92.243%
12348256203

push

github

web-flow
- Add support for Python 3.12.  - Drop support for Python 3.7. (#26)

61 of 82 branches covered (74.39%)

Branch coverage included in aggregate %.

15 of 17 new or added lines in 2 files covered. (88.24%)

3 existing lines in 2 files now uncovered.

796 of 851 relevant lines covered (93.54%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.36
/src/Products/PluginRegistry/tests/test_exportimport.py
1
##############################################################################
2
#
3
# Copyright (c) 2005 Zope Foundation and Contributors
4
# Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this
8
# distribution.
9
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
10
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
12
# FOR A PARTICULAR PURPOSE
13
#
14
##############################################################################
15
""" Unit tests for GenericSetup-based export / import of PluginRegistry.
16
"""
17
import unittest
1✔
18

19

20
try:
1✔
21
    import Products.GenericSetup  # noqa
1✔
NEW
22
except ModuleNotFoundError:
×
23
    # No GenericSetup, so no tests
UNCOV
24
    def test_suite():
×
UNCOV
25
        return unittest.TestSuite()
×
26
else:
27
    from Products.GenericSetup.tests.common import BaseRegistryTests
1✔
28
    from Products.GenericSetup.tests.common import DummyExportContext
1✔
29
    from Products.GenericSetup.tests.common import DummyImportContext
1✔
30
    from Products.GenericSetup.utils import _getDottedName
1✔
31
    from zope.component import provideAdapter
1✔
32
    from zope.component.testing import PlacelessSetup
1✔
33
    from zope.interface import Interface
1✔
34
    from zope.interface import directlyProvides
1✔
35
    from zope.traversing.interfaces import ITraversable
1✔
36
    from zope.traversing.interfaces import TraversalError
1✔
37

38
    class IFoo(Interface):
1✔
39
        pass
1✔
40

41
    class IBar(Interface):
1✔
42
        pass
1✔
43

44
    _EMPTY_PLUGINREGISTRY_EXPORT = """\
1✔
45
<?xml version="1.0"?>
46
<plugin-registry>
47
</plugin-registry>
48
"""
49

50
    _PLUGIN_TYPE_INFO = ((IFoo, 'IFoo', 'foo', 'Some plugin interface'),
1✔
51
                         (IBar, 'IBar', 'bar', 'Another plugin interface'))
52

53
    _NO_PLUGINS_PLUGINREGISTRY_EXPORT = """\
1✔
54
<?xml version="1.0"?>
55
<plugin-registry>
56
 <plugin-type
57
    id="IFoo"
58
    interface="{}"
59
    title="foo"
60
    description="Some plugin interface">
61
 </plugin-type>
62
 <plugin-type
63
    id="IBar"
64
    interface="{}"
65
    title="bar"
66
    description="Another plugin interface">
67
 </plugin-type>
68
</plugin-registry>
69
""".format(_getDottedName(IFoo), _getDottedName(IBar))
70

71
    _NORMAL_PLUGINREGISTRY_EXPORT = """\
1✔
72
<?xml version="1.0"?>
73
<plugin-registry>
74
 <plugin-type
75
    id="IFoo"
76
    interface="{}"
77
    title="foo"
78
    description="Some plugin interface">
79
  <plugin id="foo_plugin_1" />
80
  <plugin id="foo_plugin_2" />
81
 </plugin-type>
82
 <plugin-type
83
    id="IBar"
84
    interface="{}"
85
    title="bar"
86
    description="Another plugin interface">
87
 </plugin-type>
88
</plugin-registry>
89
""".format(_getDottedName(IFoo), _getDottedName(IBar))
90

91
    class _TestBase(PlacelessSetup, BaseRegistryTests):
1✔
92

93
        def _initRegistry(self, plugin_type_info=(), plugins={}):
1✔
94
            from OFS.Folder import Folder
1✔
95
            from OFS.SimpleItem import SimpleItem
1✔
96

97
            from Products.PluginRegistry.PluginRegistry import PluginRegistry
1✔
98

99
            app = Folder()
1✔
100
            app.getPhysicalPath = lambda: ()
1✔
101
            app.getPhysicalRoot = lambda: app
1✔
102

103
            app._setObject('foo_plugin_1', SimpleItem())
1✔
104
            app._setObject('foo_plugin_2', SimpleItem())
1✔
105

106
            registry = PluginRegistry(plugin_type_info)
1✔
107
            registry._plugins = {}  # it is usually lazy
1✔
108

109
            for plugin_type, registered in plugins.items():
1✔
110
                for obj_id in registered:
1✔
111
                    obj = app._getOb(obj_id)
1✔
112
                    directlyProvides(obj, plugin_type)
1✔
113
                registry._plugins[plugin_type] = registered
1✔
114

115
            app._setObject('plugin_registry', registry)
1✔
116
            registry = app._getOb('plugin_registry')
1✔
117
            return app, registry
1✔
118

119
    class PluginRegistryExporterTests(_TestBase):
1✔
120

121
        def _getTargetClass(self):
1✔
122
            from Products.PluginRegistry.exportimport import \
1✔
123
                PluginRegistryExporter
124
            return PluginRegistryExporter
1✔
125

126
        def test_empty(self):
1✔
127
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
128

129
            app, registry = self._initRegistry()
1✔
130
            exporter = self._makeOne(registry).__of__(registry)
1✔
131
            xml = exporter.generateXML()
1✔
132

133
            self._compareDOM(xml, _EMPTY_PLUGINREGISTRY_EXPORT)
1✔
134

135
        def test_normal_no_plugins(self):
1✔
136
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
137

138
            app, registry = self._initRegistry(
1✔
139
                plugin_type_info=_PLUGIN_TYPE_INFO)
140
            exporter = self._makeOne(registry).__of__(registry)
1✔
141
            xml = exporter.generateXML()
1✔
142

143
            self._compareDOM(xml, _NO_PLUGINS_PLUGINREGISTRY_EXPORT)
1✔
144

145
        def test_normal_with_plugins(self):
1✔
146
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
147

148
            app, registry = self._initRegistry(
1✔
149
                plugin_type_info=_PLUGIN_TYPE_INFO,
150
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')},
151
            )
152
            exporter = self._makeOne(registry).__of__(registry)
1✔
153
            xml = exporter.generateXML()
1✔
154

155
            self._compareDOM(xml, _NORMAL_PLUGINREGISTRY_EXPORT)
1✔
156

157
    class Test_exportPluginRegistry(_TestBase):
1✔
158

159
        def test_empty(self):
1✔
160
            from Products.PluginRegistry.exportimport import \
1✔
161
                exportPluginRegistry
162
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
163

164
            app, registry = self._initRegistry()
1✔
165
            context = DummyExportContext(app)
1✔
166
            exportPluginRegistry(context)
1✔
167

168
            self.assertEqual(len(context._wrote), 1)
1✔
169
            filename, text, content_type = context._wrote[0]
1✔
170
            self.assertEqual(filename, 'pluginregistry.xml')
1✔
171
            self._compareDOM(text, _EMPTY_PLUGINREGISTRY_EXPORT)
1✔
172
            self.assertEqual(content_type, 'text/xml')
1✔
173

174
        def test_normal_no_plugins(self):
1✔
175
            from Products.PluginRegistry.exportimport import \
1✔
176
                exportPluginRegistry
177
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
178

179
            app, registry = self._initRegistry(
1✔
180
                plugin_type_info=_PLUGIN_TYPE_INFO)
181
            context = DummyExportContext(app)
1✔
182
            exportPluginRegistry(context)
1✔
183

184
            self.assertEqual(len(context._wrote), 1)
1✔
185
            filename, text, content_type = context._wrote[0]
1✔
186
            self.assertEqual(filename, 'pluginregistry.xml')
1✔
187
            self._compareDOM(text, _NO_PLUGINS_PLUGINREGISTRY_EXPORT)
1✔
188
            self.assertEqual(content_type, 'text/xml')
1✔
189

190
        def test_normal_with_plugins(self):
1✔
191
            from Products.PluginRegistry.exportimport import \
1✔
192
                exportPluginRegistry
193
            provideAdapter(AttrItemTraverser, (Interface, ), ITraversable)
1✔
194

195
            app, registry = self._initRegistry(
1✔
196
                plugin_type_info=_PLUGIN_TYPE_INFO,
197
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
198
            context = DummyExportContext(app)
1✔
199
            exportPluginRegistry(context)
1✔
200

201
            self.assertEqual(len(context._wrote), 1)
1✔
202
            filename, text, content_type = context._wrote[0]
1✔
203
            self.assertEqual(filename, 'pluginregistry.xml')
1✔
204
            self._compareDOM(text, _NORMAL_PLUGINREGISTRY_EXPORT)
1✔
205
            self.assertEqual(content_type, 'text/xml')
1✔
206

207
    class PluginRegistryImporterTests(_TestBase):
1✔
208

209
        def _getTargetClass(self):
1✔
210
            from Products.PluginRegistry.exportimport import \
1✔
211
                PluginRegistryImporter
212
            return PluginRegistryImporter
1✔
213

214
        def test_parseXML_empty(self):
1✔
215

216
            app, registry = self._initRegistry()
1✔
217
            importer = self._makeOne(registry).__of__(registry)
1✔
218
            reg_info = importer.parseXML(_EMPTY_PLUGINREGISTRY_EXPORT)
1✔
219

220
            self.assertEqual(len(reg_info['plugin_types']), 0)
1✔
221

222
        def test_parseXML_normal_no_plugins(self):
1✔
223

224
            app, registry = self._initRegistry()
1✔
225
            importer = self._makeOne(registry).__of__(registry)
1✔
226
            reg_info = importer.parseXML(_NO_PLUGINS_PLUGINREGISTRY_EXPORT)
1✔
227

228
            self.assertEqual(len(reg_info['plugin_types']), 2)
1✔
229

230
            info = reg_info['plugin_types'][0]
1✔
231
            self.assertEqual(info['id'], 'IFoo')
1✔
232
            self.assertEqual(info['interface'], _getDottedName(IFoo))
1✔
233
            self.assertEqual(info['title'], 'foo')
1✔
234
            self.assertEqual(info['description'], 'Some plugin interface')
1✔
235
            self.assertEqual(len(info['plugins']), 0)
1✔
236

237
            info = reg_info['plugin_types'][1]
1✔
238
            self.assertEqual(info['id'], 'IBar')
1✔
239
            self.assertEqual(info['interface'], _getDottedName(IBar))
1✔
240
            self.assertEqual(info['title'], 'bar')
1✔
241
            self.assertEqual(info['description'], 'Another plugin interface')
1✔
242
            self.assertEqual(len(info['plugins']), 0)
1✔
243

244
        def test_parseXML_normal_with_plugins(self):
1✔
245

246
            app, registry = self._initRegistry()
1✔
247
            importer = self._makeOne(registry).__of__(registry)
1✔
248
            reg_info = importer.parseXML(_NORMAL_PLUGINREGISTRY_EXPORT)
1✔
249

250
            self.assertEqual(len(reg_info['plugin_types']), 2)
1✔
251

252
            info = reg_info['plugin_types'][0]
1✔
253
            self.assertEqual(info['id'], 'IFoo')
1✔
254
            self.assertEqual(info['interface'], _getDottedName(IFoo))
1✔
255
            self.assertEqual(info['title'], 'foo')
1✔
256
            self.assertEqual(info['description'], 'Some plugin interface')
1✔
257
            plugins = info['plugins']
1✔
258
            self.assertEqual(len(plugins), 2)
1✔
259
            self.assertEqual(plugins[0]['id'], 'foo_plugin_1')
1✔
260
            self.assertEqual(plugins[1]['id'], 'foo_plugin_2')
1✔
261

262
            info = reg_info['plugin_types'][1]
1✔
263
            self.assertEqual(info['id'], 'IBar')
1✔
264
            self.assertEqual(info['interface'], _getDottedName(IBar))
1✔
265
            self.assertEqual(info['title'], 'bar')
1✔
266
            self.assertEqual(info['description'], 'Another plugin interface')
1✔
267
            self.assertEqual(len(info['plugins']), 0)
1✔
268

269
    class Test_importPluginRegistry(_TestBase):
1✔
270

271
        def test_empty_default_purge(self):
1✔
272
            from Products.PluginRegistry.exportimport import \
1✔
273
                importPluginRegistry
274

275
            app, registry = self._initRegistry(
1✔
276
                plugin_type_info=_PLUGIN_TYPE_INFO,
277
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
278

279
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
280
            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
1✔
281
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
282

283
            context = DummyImportContext(app)
1✔
284
            context._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
1✔
285

286
            importPluginRegistry(context)
1✔
287

288
            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
1✔
289
            self.assertRaises(KeyError, registry.listPlugins, IFoo)
1✔
290
            self.assertRaises(KeyError, registry.listPlugins, IBar)
1✔
291

292
        def test_empty_explicit_purge(self):
1✔
293
            from Products.PluginRegistry.exportimport import \
1✔
294
                importPluginRegistry
295

296
            app, registry = self._initRegistry(
1✔
297
                plugin_type_info=_PLUGIN_TYPE_INFO,
298
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
299

300
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
301
            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
1✔
302
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
303

304
            ctx = DummyImportContext(app, True)
1✔
305
            ctx._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
1✔
306

307
            importPluginRegistry(ctx)
1✔
308

309
            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
1✔
310
            self.assertRaises(KeyError, registry.listPlugins, IFoo)
1✔
311
            self.assertRaises(KeyError, registry.listPlugins, IBar)
1✔
312

313
        def test_empty_skip_purge(self):
1✔
314
            from Products.PluginRegistry.exportimport import \
1✔
315
                importPluginRegistry
316

317
            app, registry = self._initRegistry(
1✔
318
                plugin_type_info=_PLUGIN_TYPE_INFO,
319
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
320

321
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
322
            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
1✔
323
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
324

325
            ctx = DummyImportContext(app, False)
1✔
326
            ctx._files['pluginregistry.xml'] = _EMPTY_PLUGINREGISTRY_EXPORT
1✔
327

328
            importPluginRegistry(ctx)
1✔
329

330
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
331
            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
1✔
332
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
333

334
        def test_normal_no_plugins(self):
1✔
335
            from Products.PluginRegistry.exportimport import \
1✔
336
                importPluginRegistry
337

338
            app, registry = self._initRegistry(
1✔
339
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
340

341
            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
1✔
342
            self.assertRaises(KeyError, registry.listPlugins, IFoo)
1✔
343
            self.assertRaises(KeyError, registry.listPlugins, IBar)
1✔
344

345
            ctx = DummyImportContext(app, False)
1✔
346
            xml_data = _NO_PLUGINS_PLUGINREGISTRY_EXPORT
1✔
347
            ctx._files['pluginregistry.xml'] = xml_data
1✔
348

349
            importPluginRegistry(ctx)
1✔
350

351
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
352

353
            info = registry.listPluginTypeInfo()[0]
1✔
354
            self.assertEqual(info['id'], 'IFoo')
1✔
355
            self.assertEqual(info['title'], 'foo')
1✔
356
            self.assertEqual(info['description'], 'Some plugin interface')
1✔
357

358
            info = registry.listPluginTypeInfo()[1]
1✔
359
            self.assertEqual(info['id'], 'IBar')
1✔
360
            self.assertEqual(info['title'], 'bar')
1✔
361
            self.assertEqual(info['description'], 'Another plugin interface')
1✔
362

363
            self.assertEqual(len(registry.listPlugins(IFoo)), 0)
1✔
364
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
365

366
        def test_normal_with_plugins(self):
1✔
367
            from Products.PluginRegistry.exportimport import \
1✔
368
                importPluginRegistry
369

370
            app, registry = self._initRegistry(
1✔
371
                plugins={IFoo: ('foo_plugin_1', 'foo_plugin_2')})
372

373
            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
1✔
374
            self.assertRaises(KeyError, registry.listPlugins, IFoo)
1✔
375
            self.assertRaises(KeyError, registry.listPlugins, IBar)
1✔
376

377
            ctx = DummyImportContext(app, False)
1✔
378
            ctx._files['pluginregistry.xml'] = _NORMAL_PLUGINREGISTRY_EXPORT
1✔
379

380
            importPluginRegistry(ctx)
1✔
381

382
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
383

384
            info = registry.listPluginTypeInfo()[0]
1✔
385
            self.assertEqual(info['id'], 'IFoo')
1✔
386
            self.assertEqual(info['title'], 'foo')
1✔
387
            self.assertEqual(info['description'], 'Some plugin interface')
1✔
388

389
            info = registry.listPluginTypeInfo()[1]
1✔
390
            self.assertEqual(info['id'], 'IBar')
1✔
391
            self.assertEqual(info['title'], 'bar')
1✔
392
            self.assertEqual(info['description'], 'Another plugin interface')
1✔
393

394
            self.assertEqual(len(registry.listPlugins(IFoo)), 2)
1✔
395
            plugins = registry.listPlugins(IFoo)
1✔
396
            self.assertEqual(plugins[0][0], 'foo_plugin_1')
1✔
397
            self.assertEqual(plugins[0][1], app._getOb('foo_plugin_1'))
1✔
398
            self.assertEqual(plugins[1][0], 'foo_plugin_2')
1✔
399
            self.assertEqual(plugins[1][1], app._getOb('foo_plugin_2'))
1✔
400

401
            self.assertEqual(len(registry.listPlugins(IBar)), 0)
1✔
402

403
        def test_normal_with_plugins_skip_duplicates(self):
1✔
404
            # See http://www.zope.org/Collectors/PAS/52
405
            from Products.PluginRegistry.exportimport import \
1✔
406
                importPluginRegistry
407

408
            app, registry = self._initRegistry()
1✔
409

410
            self.assertEqual(len(registry.listPluginTypeInfo()), 0)
1✔
411
            self.assertRaises(KeyError, registry.listPlugins, IFoo)
1✔
412
            self.assertRaises(KeyError, registry.listPlugins, IBar)
1✔
413

414
            ctx = DummyImportContext(app, False)
1✔
415
            ctx._files['pluginregistry.xml'] = _NORMAL_PLUGINREGISTRY_EXPORT
1✔
416

417
            importPluginRegistry(ctx)
1✔
418
            importPluginRegistry(ctx)  # twice should not duplicate
1✔
419

420
            self.assertEqual(len(registry.listPluginTypeInfo()), 2)
1✔
421

422
    class AttrItemTraverser:
1✔
423
        _marker = object()
1✔
424

425
        def __init__(self, context):
1✔
426
            self.context = context
1✔
427

428
        def traverse(self, name, furtherPath):
1✔
429
            result = getattr(self.context, name, self._marker)
1✔
430
            if result is self._marker:
1✔
431
                try:
1✔
432
                    result = self.context.get(name, self._marker)
1✔
433
                except AttributeError:
×
434
                    pass
×
435
            if result is self._marker:
1!
436
                raise TraversalError(name)
×
437
            return result
1✔
438

439
    def test_suite():
1✔
440
        loader = unittest.defaultTestLoader
1✔
441
        return unittest.TestSuite(
1✔
442
            (loader.loadTestsFromTestCase(PluginRegistryExporterTests),
443
             loader.loadTestsFromTestCase(PluginRegistryImporterTests),
444
             loader.loadTestsFromTestCase(Test_exportPluginRegistry),
445
             loader.loadTestsFromTestCase(Test_importPluginRegistry)))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc