~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_plugins.py

  • Committer: Patch Queue Manager
  • Date: 2012-03-16 14:15:06 UTC
  • mfrom: (6503.3.1 typo-fix)
  • Revision ID: pqm@pqm.ubuntu.com-20120316141506-30gdc3wkbgmwkdus
(jelmer) Fix a typo: extention -> extension. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
# affects the global state of the process.  See bzrlib/plugins.py for more
21
21
# comments.
22
22
 
 
23
from cStringIO import StringIO
23
24
import logging
24
25
import os
25
 
from StringIO import StringIO
26
26
import sys
27
 
import zipfile
28
27
 
 
28
import bzrlib
29
29
from bzrlib import (
 
30
    errors,
30
31
    osutils,
31
32
    plugin,
 
33
    plugins,
32
34
    tests,
33
 
    )
34
 
import bzrlib.plugin
35
 
import bzrlib.plugins
36
 
import bzrlib.commands
37
 
import bzrlib.help
38
 
from bzrlib.tests import (
39
 
    TestCase,
40
 
    TestCaseInTempDir,
41
 
    TestUtil,
42
 
    )
43
 
from bzrlib.osutils import pathjoin, abspath, normpath
44
 
 
45
 
 
46
 
PLUGIN_TEXT = """\
47
 
import bzrlib.commands
48
 
class cmd_myplug(bzrlib.commands.Command):
49
 
    '''Just a simple test plugin.'''
50
 
    aliases = ['mplg']
51
 
    def run(self):
52
 
        print 'Hello from my plugin'
53
 
"""
 
35
    trace,
 
36
    )
 
37
 
54
38
 
55
39
# TODO: Write a test for plugin decoration of commands.
56
40
 
57
 
class TestLoadingPlugins(TestCaseInTempDir):
 
41
class BaseTestPlugins(tests.TestCaseInTempDir):
 
42
 
 
43
    def create_plugin(self, name, source=None, dir='.', file_name=None):
 
44
        if source is None:
 
45
            source = '''\
 
46
"""This is the doc for %s"""
 
47
''' % (name)
 
48
        if file_name is None:
 
49
            file_name = name + '.py'
 
50
        # 'source' must not fail to load
 
51
        path = osutils.pathjoin(dir, file_name)
 
52
        f = open(path, 'w')
 
53
        self.addCleanup(os.unlink, path)
 
54
        try:
 
55
            f.write(source + '\n')
 
56
        finally:
 
57
            f.close()
 
58
 
 
59
    def create_plugin_package(self, name, dir=None, source=None):
 
60
        if dir is None:
 
61
            dir = name
 
62
        if source is None:
 
63
            source = '''\
 
64
"""This is the doc for %s"""
 
65
dir_source = '%s'
 
66
''' % (name, dir)
 
67
        os.makedirs(dir)
 
68
        def cleanup():
 
69
            # Workaround lazy import random? madness
 
70
            osutils.rmtree(dir)
 
71
        self.addCleanup(cleanup)
 
72
        self.create_plugin(name, source, dir,
 
73
                           file_name='__init__.py')
 
74
 
 
75
    def _unregister_plugin(self, name):
 
76
        """Remove the plugin from sys.modules and the bzrlib namespace."""
 
77
        py_name = 'bzrlib.plugins.%s' % name
 
78
        if py_name in sys.modules:
 
79
            del sys.modules[py_name]
 
80
        if getattr(bzrlib.plugins, name, None) is not None:
 
81
            delattr(bzrlib.plugins, name)
 
82
 
 
83
    def _unregister_plugin_submodule(self, plugin_name, submodule_name):
 
84
        """Remove the submodule from sys.modules and the bzrlib namespace."""
 
85
        py_name = 'bzrlib.plugins.%s.%s' % (plugin_name, submodule_name)
 
86
        if py_name in sys.modules:
 
87
            del sys.modules[py_name]
 
88
        plugin = getattr(bzrlib.plugins, plugin_name, None)
 
89
        if plugin is not None:
 
90
            if getattr(plugin, submodule_name, None) is not None:
 
91
                delattr(plugin, submodule_name)
 
92
 
 
93
    def assertPluginUnknown(self, name):
 
94
        self.assertFalse(getattr(bzrlib.plugins, name, None) is not None)
 
95
        self.assertFalse('bzrlib.plugins.%s' % name in sys.modules)
 
96
 
 
97
    def assertPluginKnown(self, name):
 
98
        self.assertTrue(getattr(bzrlib.plugins, name, None) is not None)
 
99
        self.assertTrue('bzrlib.plugins.%s' % name in sys.modules)
 
100
 
 
101
 
 
102
class TestLoadingPlugins(BaseTestPlugins):
58
103
 
59
104
    activeattributes = {}
60
105
 
64
109
        # file name we can use which is also a valid attribute for accessing in
65
110
        # activeattributes. - we cannot give import parameters.
66
111
        tempattribute = "0"
67
 
        self.failIf(tempattribute in self.activeattributes)
 
112
        self.assertFalse(tempattribute in self.activeattributes)
68
113
        # set a place for the plugins to record their loading, and at the same
69
114
        # time validate that the location the plugins should record to is
70
115
        # valid and correct.
71
 
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
72
 
            [tempattribute] = []
73
 
        self.failUnless(tempattribute in self.activeattributes)
 
116
        self.__class__.activeattributes [tempattribute] = []
 
117
        self.assertTrue(tempattribute in self.activeattributes)
74
118
        # create two plugin directories
75
119
        os.mkdir('first')
76
120
        os.mkdir('second')
99
143
        finally:
100
144
            # remove the plugin 'plugin'
101
145
            del self.activeattributes[tempattribute]
102
 
            if 'bzrlib.plugins.plugin' in sys.modules:
103
 
                del sys.modules['bzrlib.plugins.plugin']
104
 
            if getattr(bzrlib.plugins, 'plugin', None):
105
 
                del bzrlib.plugins.plugin
106
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
146
            self._unregister_plugin('plugin')
 
147
        self.assertPluginUnknown('plugin')
107
148
 
108
149
    def test_plugins_from_different_dirs_can_demand_load(self):
 
150
        self.assertFalse('bzrlib.plugins.pluginone' in sys.modules)
 
151
        self.assertFalse('bzrlib.plugins.plugintwo' in sys.modules)
109
152
        # This test tests that having two plugins in different
110
153
        # directories with different names allows them both to be loaded, when
111
154
        # we do a direct import statement.
112
155
        # Determine a file name we can use which is also a valid attribute
113
156
        # for accessing in activeattributes. - we cannot give import parameters.
114
157
        tempattribute = "different-dirs"
115
 
        self.failIf(tempattribute in self.activeattributes)
 
158
        self.assertFalse(tempattribute in self.activeattributes)
116
159
        # set a place for the plugins to record their loading, and at the same
117
160
        # time validate that the location the plugins should record to is
118
161
        # valid and correct.
119
162
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
120
163
            [tempattribute] = []
121
 
        self.failUnless(tempattribute in self.activeattributes)
 
164
        self.assertTrue(tempattribute in self.activeattributes)
122
165
        # create two plugin directories
123
166
        os.mkdir('first')
124
167
        os.mkdir('second')
143
186
 
144
187
        oldpath = bzrlib.plugins.__path__
145
188
        try:
 
189
            self.assertFalse('bzrlib.plugins.pluginone' in sys.modules)
 
190
            self.assertFalse('bzrlib.plugins.plugintwo' in sys.modules)
146
191
            bzrlib.plugins.__path__ = ['first', 'second']
147
192
            exec "import bzrlib.plugins.pluginone"
148
193
            self.assertEqual(['first'], self.activeattributes[tempattribute])
152
197
        finally:
153
198
            # remove the plugin 'plugin'
154
199
            del self.activeattributes[tempattribute]
155
 
            if getattr(bzrlib.plugins, 'pluginone', None):
156
 
                del bzrlib.plugins.pluginone
157
 
            if getattr(bzrlib.plugins, 'plugintwo', None):
158
 
                del bzrlib.plugins.plugintwo
159
 
        self.failIf(getattr(bzrlib.plugins, 'pluginone', None))
160
 
        self.failIf(getattr(bzrlib.plugins, 'plugintwo', None))
 
200
            self._unregister_plugin('pluginone')
 
201
            self._unregister_plugin('plugintwo')
 
202
        self.assertPluginUnknown('pluginone')
 
203
        self.assertPluginUnknown('plugintwo')
161
204
 
162
205
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
163
206
        # This test tests that a plugin can load from a directory when the
164
207
        # directory in the path has a trailing slash.
165
208
        # check the plugin is not loaded already
166
 
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
209
        self.assertPluginUnknown('ts_plugin')
167
210
        tempattribute = "trailing-slash"
168
 
        self.failIf(tempattribute in self.activeattributes)
 
211
        self.assertFalse(tempattribute in self.activeattributes)
169
212
        # set a place for the plugin to record its loading, and at the same
170
213
        # time validate that the location the plugin should record to is
171
214
        # valid and correct.
172
215
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
173
216
            [tempattribute] = []
174
 
        self.failUnless(tempattribute in self.activeattributes)
 
217
        self.assertTrue(tempattribute in self.activeattributes)
175
218
        # create a directory for the plugin
176
219
        os.mkdir('plugin_test')
177
220
        # write a plugin that will record when its loaded in the
190
233
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
191
234
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
192
235
        finally:
193
 
            # remove the plugin 'plugin'
194
236
            del self.activeattributes[tempattribute]
195
 
            if getattr(bzrlib.plugins, 'ts_plugin', None):
196
 
                del bzrlib.plugins.ts_plugin
197
 
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
237
            self._unregister_plugin('ts_plugin')
 
238
        self.assertPluginUnknown('ts_plugin')
198
239
 
199
240
    def load_and_capture(self, name):
200
241
        """Load plugins from '.' capturing the output.
226
267
            stream.close()
227
268
 
228
269
    def test_plugin_with_bad_api_version_reports(self):
229
 
        # This plugin asks for bzrlib api version 1.0.0, which is not supported
230
 
        # anymore.
 
270
        """Try loading a plugin that requests an unsupported api.
 
271
        
 
272
        Observe that it records the problem but doesn't complain on stderr.
 
273
 
 
274
        See https://bugs.launchpad.net/bzr/+bug/704195
 
275
        """
 
276
        self.overrideAttr(plugin, 'plugin_warnings', {})
231
277
        name = 'wants100.py'
232
278
        f = file(name, 'w')
233
279
        try:
235
281
                "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n")
236
282
        finally:
237
283
            f.close()
238
 
 
239
284
        log = self.load_and_capture(name)
240
 
        self.assertContainsRe(log,
 
285
        self.assertNotContainsRe(log,
 
286
            r"It requested API version")
 
287
        self.assertEquals(
 
288
            ['wants100'],
 
289
            plugin.plugin_warnings.keys())
 
290
        self.assertContainsRe(
 
291
            plugin.plugin_warnings['wants100'][0],
241
292
            r"It requested API version")
242
293
 
243
294
    def test_plugin_with_bad_name_does_not_load(self):
251
302
            "it to 'bad_plugin_name_'\.")
252
303
 
253
304
 
254
 
class TestPlugins(TestCaseInTempDir):
 
305
class TestPlugins(BaseTestPlugins):
255
306
 
256
307
    def setup_plugin(self, source=""):
257
308
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
258
309
        # check the plugin is not loaded already
259
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
310
        self.assertPluginUnknown('plugin')
260
311
        # write a plugin that _cannot_ fail to load.
261
 
        file('plugin.py', 'w').write(source + '\n')
 
312
        with file('plugin.py', 'w') as f: f.write(source + '\n')
262
313
        self.addCleanup(self.teardown_plugin)
263
 
        bzrlib.plugin.load_from_path(['.'])
 
314
        plugin.load_from_path(['.'])
264
315
 
265
316
    def teardown_plugin(self):
266
 
        # remove the plugin 'plugin'
267
 
        if 'bzrlib.plugins.plugin' in sys.modules:
268
 
            del sys.modules['bzrlib.plugins.plugin']
269
 
        if getattr(bzrlib.plugins, 'plugin', None):
270
 
            del bzrlib.plugins.plugin
271
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
317
        self._unregister_plugin('plugin')
 
318
        self.assertPluginUnknown('plugin')
272
319
 
273
320
    def test_plugin_appears_in_plugins(self):
274
321
        self.setup_plugin()
275
 
        self.failUnless('plugin' in bzrlib.plugin.plugins())
276
 
        self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
277
 
        plugins = bzrlib.plugin.plugins()
278
 
        plugin = plugins['plugin']
279
 
        self.assertIsInstance(plugin, bzrlib.plugin.PlugIn)
280
 
        self.assertEqual(bzrlib.plugins.plugin, plugin.module)
 
322
        self.assertPluginKnown('plugin')
 
323
        p = plugin.plugins()['plugin']
 
324
        self.assertIsInstance(p, bzrlib.plugin.PlugIn)
 
325
        self.assertEqual(p.module, plugins.plugin)
281
326
 
282
327
    def test_trivial_plugin_get_path(self):
283
328
        self.setup_plugin()
284
 
        plugins = bzrlib.plugin.plugins()
285
 
        plugin = plugins['plugin']
 
329
        p = plugin.plugins()['plugin']
286
330
        plugin_path = self.test_dir + '/plugin.py'
287
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
331
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
288
332
 
289
333
    def test_plugin_get_path_py_not_pyc(self):
290
 
        self.setup_plugin()         # after first import there will be plugin.pyc
 
334
        # first import creates plugin.pyc
 
335
        self.setup_plugin()
291
336
        self.teardown_plugin()
292
 
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
293
 
        plugins = bzrlib.plugin.plugins()
294
 
        plugin = plugins['plugin']
 
337
        plugin.load_from_path(['.']) # import plugin.pyc
 
338
        p = plugin.plugins()['plugin']
295
339
        plugin_path = self.test_dir + '/plugin.py'
296
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
340
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
297
341
 
298
342
    def test_plugin_get_path_pyc_only(self):
299
 
        self.setup_plugin()         # after first import there will be plugin.pyc
 
343
        # first import creates plugin.pyc (or plugin.pyo depending on __debug__)
 
344
        self.setup_plugin()
300
345
        self.teardown_plugin()
301
346
        os.unlink(self.test_dir + '/plugin.py')
302
 
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
303
 
        plugins = bzrlib.plugin.plugins()
304
 
        plugin = plugins['plugin']
 
347
        plugin.load_from_path(['.']) # import plugin.pyc (or .pyo)
 
348
        p = plugin.plugins()['plugin']
305
349
        if __debug__:
306
350
            plugin_path = self.test_dir + '/plugin.pyc'
307
351
        else:
308
352
            plugin_path = self.test_dir + '/plugin.pyo'
309
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
353
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
310
354
 
311
355
    def test_no_test_suite_gives_None_for_test_suite(self):
312
356
        self.setup_plugin()
313
 
        plugin = bzrlib.plugin.plugins()['plugin']
314
 
        self.assertEqual(None, plugin.test_suite())
 
357
        p = plugin.plugins()['plugin']
 
358
        self.assertEqual(None, p.test_suite())
315
359
 
316
360
    def test_test_suite_gives_test_suite_result(self):
317
361
        source = """def test_suite(): return 'foo'"""
318
362
        self.setup_plugin(source)
319
 
        plugin = bzrlib.plugin.plugins()['plugin']
320
 
        self.assertEqual('foo', plugin.test_suite())
 
363
        p = plugin.plugins()['plugin']
 
364
        self.assertEqual('foo', p.test_suite())
321
365
 
322
366
    def test_no_load_plugin_tests_gives_None_for_load_plugin_tests(self):
323
367
        self.setup_plugin()
324
 
        loader = TestUtil.TestLoader()
325
 
        plugin = bzrlib.plugin.plugins()['plugin']
326
 
        self.assertEqual(None, plugin.load_plugin_tests(loader))
 
368
        loader = tests.TestUtil.TestLoader()
 
369
        p = plugin.plugins()['plugin']
 
370
        self.assertEqual(None, p.load_plugin_tests(loader))
327
371
 
328
372
    def test_load_plugin_tests_gives_load_plugin_tests_result(self):
329
373
        source = """
330
374
def load_tests(standard_tests, module, loader):
331
375
    return 'foo'"""
332
376
        self.setup_plugin(source)
333
 
        loader = TestUtil.TestLoader()
334
 
        plugin = bzrlib.plugin.plugins()['plugin']
335
 
        self.assertEqual('foo', plugin.load_plugin_tests(loader))
 
377
        loader = tests.TestUtil.TestLoader()
 
378
        p = plugin.plugins()['plugin']
 
379
        self.assertEqual('foo', p.load_plugin_tests(loader))
 
380
 
 
381
    def check_version_info(self, expected, source='', name='plugin'):
 
382
        self.setup_plugin(source)
 
383
        self.assertEqual(expected, plugin.plugins()[name].version_info())
336
384
 
337
385
    def test_no_version_info(self):
338
 
        self.setup_plugin()
339
 
        plugin = bzrlib.plugin.plugins()['plugin']
340
 
        self.assertEqual(None, plugin.version_info())
 
386
        self.check_version_info(None)
341
387
 
342
388
    def test_with_version_info(self):
343
 
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
344
 
        plugin = bzrlib.plugin.plugins()['plugin']
345
 
        self.assertEqual((1, 2, 3, 'dev', 4), plugin.version_info())
 
389
        self.check_version_info((1, 2, 3, 'dev', 4),
 
390
                                "version_info = (1, 2, 3, 'dev', 4)")
346
391
 
347
392
    def test_short_version_info_gets_padded(self):
348
393
        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
349
394
        # so we adapt it
350
 
        self.setup_plugin("version_info = (1, 2, 3)")
351
 
        plugin = bzrlib.plugin.plugins()['plugin']
352
 
        self.assertEqual((1, 2, 3, 'final', 0), plugin.version_info())
 
395
        self.check_version_info((1, 2, 3, 'final', 0),
 
396
                                "version_info = (1, 2, 3)")
 
397
 
 
398
    def check_version(self, expected, source=None, name='plugin'):
 
399
        self.setup_plugin(source)
 
400
        self.assertEqual(expected, plugins[name].__version__)
353
401
 
354
402
    def test_no_version_info___version__(self):
355
403
        self.setup_plugin()
404
452
    def test_final_fallback__version__with_version_info(self):
405
453
        self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
406
454
        plugin = bzrlib.plugin.plugins()['plugin']
407
 
        self.assertEqual("1.2.3.final.2", plugin.__version__)
408
 
 
409
 
 
410
 
class TestPluginHelp(TestCaseInTempDir):
 
455
        self.assertEqual("1.2.3.2", plugin.__version__)
 
456
 
 
457
 
 
458
class TestPluginHelp(tests.TestCaseInTempDir):
411
459
 
412
460
    def split_help_commands(self):
413
461
        help = {}
442
490
    def test_plugin_help_shows_plugin(self):
443
491
        # Create a test plugin
444
492
        os.mkdir('plugin_test')
445
 
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
446
 
        f.write(PLUGIN_TEXT)
 
493
        f = open(osutils.pathjoin('plugin_test', 'myplug.py'), 'w')
 
494
        f.write("""\
 
495
from bzrlib import commands
 
496
class cmd_myplug(commands.Command):
 
497
    __doc__ = '''Just a simple test plugin.'''
 
498
    aliases = ['mplg']
 
499
    def run(self):
 
500
        print 'Hello from my plugin'
 
501
 
 
502
"""
 
503
)
447
504
        f.close()
448
505
 
449
506
        try:
558
615
    def test_get_help_text_with_additional_see_also(self):
559
616
        mod = FakeModule('two lines of help\nand more', 'demo')
560
617
        topic = plugin.ModuleHelpTopic(mod)
561
 
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
562
 
            topic.get_help_text(['foo', 'bar']))
 
618
        self.assertEqual("two lines of help\nand more\n\n:See also: bar, foo\n",
 
619
                         topic.get_help_text(['foo', 'bar']))
563
620
 
564
621
    def test_get_help_topic(self):
565
622
        """The help topic for a plugin is its module name."""
566
623
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
567
624
        topic = plugin.ModuleHelpTopic(mod)
568
625
        self.assertEqual('demo', topic.get_help_topic())
569
 
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
 
626
        mod = FakeModule('two lines of help\nand more',
 
627
                         'bzrlib.plugins.foo_bar')
570
628
        topic = plugin.ModuleHelpTopic(mod)
571
629
        self.assertEqual('foo_bar', topic.get_help_topic())
572
630
 
609
667
                    self.fail('No path to global plugins')
610
668
 
611
669
    def test_get_standard_plugins_path_env(self):
612
 
        os.environ['BZR_PLUGIN_PATH'] = 'foo/'
 
670
        self.overrideEnv('BZR_PLUGIN_PATH', 'foo/')
613
671
        path = plugin.get_standard_plugins_path()
614
672
        for directory in path:
615
673
            self.assertNotContainsRe(directory, r'\\/$')
627
685
        self.assertEqual(path, bzrlib.plugins.__path__)
628
686
 
629
687
 
630
 
class TestEnvPluginPath(tests.TestCaseInTempDir):
 
688
class TestEnvPluginPath(tests.TestCase):
631
689
 
632
690
    def setUp(self):
633
691
        super(TestEnvPluginPath, self).setUp()
645
703
 
646
704
    def _set_path(self, *args):
647
705
        path = os.pathsep.join(self._list2paths(*args))
648
 
        osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
 
706
        self.overrideEnv('BZR_PLUGIN_PATH', path)
649
707
 
650
708
    def check_path(self, expected_dirs, setting_dirs):
651
709
        if setting_dirs:
680
738
        self.check_path([self.user, self.core, self.site],
681
739
                        ['+user', '+user'])
682
740
        # And only the first reference is kept (since the later references will
683
 
        # onnly produce <plugin> already loaded mutters)
 
741
        # only produce '<plugin> already loaded' mutters)
684
742
        self.check_path([self.user, self.core, self.site],
685
743
                        ['+user', '+user', '+core',
686
744
                         '+user', '+site', '+site',
687
745
                         '+core'])
688
746
 
689
 
    def test_disable_overrides_disable(self):
 
747
    def test_disable_overrides_enable(self):
690
748
        self.check_path([self.core, self.site], ['-user', '+user'])
691
749
 
692
750
    def test_disable_core(self):
719
777
    def test_bogus_references(self):
720
778
        self.check_path(['+foo', '-bar', self.core, self.site],
721
779
                        ['+foo', '-bar'])
 
780
 
 
781
 
 
782
class TestDisablePlugin(BaseTestPlugins):
 
783
 
 
784
    def setUp(self):
 
785
        super(TestDisablePlugin, self).setUp()
 
786
        self.create_plugin_package('test_foo')
 
787
        # Make sure we don't pollute the plugins namespace
 
788
        self.overrideAttr(plugins, '__path__')
 
789
        # Be paranoid in case a test fail
 
790
        self.addCleanup(self._unregister_plugin, 'test_foo')
 
791
 
 
792
    def test_cannot_import(self):
 
793
        self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
 
794
        plugin.set_plugins_path(['.'])
 
795
        try:
 
796
            import bzrlib.plugins.test_foo
 
797
        except ImportError:
 
798
            pass
 
799
        self.assertPluginUnknown('test_foo')
 
800
 
 
801
    def test_regular_load(self):
 
802
        self.overrideAttr(plugin, '_loaded', False)
 
803
        plugin.load_plugins(['.'])
 
804
        self.assertPluginKnown('test_foo')
 
805
        self.assertDocstring("This is the doc for test_foo",
 
806
                             bzrlib.plugins.test_foo)
 
807
 
 
808
    def test_not_loaded(self):
 
809
        self.warnings = []
 
810
        def captured_warning(*args, **kwargs):
 
811
            self.warnings.append((args, kwargs))
 
812
        self.overrideAttr(trace, 'warning', captured_warning)
 
813
        # Reset the flag that protect against double loading
 
814
        self.overrideAttr(plugin, '_loaded', False)
 
815
        self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
 
816
        plugin.load_plugins(['.'])
 
817
        self.assertPluginUnknown('test_foo')
 
818
        # Make sure we don't warn about the plugin ImportError since this has
 
819
        # been *requested* by the user.
 
820
        self.assertLength(0, self.warnings)
 
821
 
 
822
 
 
823
 
 
824
class TestLoadPluginAtSyntax(tests.TestCase):
 
825
 
 
826
    def _get_paths(self, paths):
 
827
        return plugin._get_specific_plugin_paths(paths)
 
828
 
 
829
    def test_empty(self):
 
830
        self.assertEquals([], self._get_paths(None))
 
831
        self.assertEquals([], self._get_paths(''))
 
832
 
 
833
    def test_one_path(self):
 
834
        self.assertEquals([('b', 'man')], self._get_paths('b@man'))
 
835
 
 
836
    def test_bogus_path(self):
 
837
        # We need a '@'
 
838
        self.assertRaises(errors.BzrCommandError, self._get_paths, 'batman')
 
839
        # Too much '@' isn't good either
 
840
        self.assertRaises(errors.BzrCommandError, self._get_paths,
 
841
                          'batman@mobile@cave')
 
842
        # An empty description probably indicates a problem
 
843
        self.assertRaises(errors.BzrCommandError, self._get_paths,
 
844
                          os.pathsep.join(['batman@cave', '', 'robin@mobile']))
 
845
 
 
846
 
 
847
class TestLoadPluginAt(BaseTestPlugins):
 
848
 
 
849
    def setUp(self):
 
850
        super(TestLoadPluginAt, self).setUp()
 
851
        # Make sure we don't pollute the plugins namespace
 
852
        self.overrideAttr(plugins, '__path__')
 
853
        # Reset the flag that protect against double loading
 
854
        self.overrideAttr(plugin, '_loaded', False)
 
855
        # Create the same plugin in two directories
 
856
        self.create_plugin_package('test_foo', dir='non-standard-dir')
 
857
        # The "normal" directory, we use 'standard' instead of 'plugins' to
 
858
        # avoid depending on the precise naming.
 
859
        self.create_plugin_package('test_foo', dir='standard/test_foo')
 
860
        # All the tests will load the 'test_foo' plugin from various locations
 
861
        self.addCleanup(self._unregister_plugin, 'test_foo')
 
862
        # Unfortunately there's global cached state for the specific
 
863
        # registered paths.
 
864
        self.addCleanup(plugin.PluginImporter.reset)
 
865
 
 
866
    def assertTestFooLoadedFrom(self, path):
 
867
        self.assertPluginKnown('test_foo')
 
868
        self.assertDocstring('This is the doc for test_foo',
 
869
                             bzrlib.plugins.test_foo)
 
870
        self.assertEqual(path, bzrlib.plugins.test_foo.dir_source)
 
871
 
 
872
    def test_regular_load(self):
 
873
        plugin.load_plugins(['standard'])
 
874
        self.assertTestFooLoadedFrom('standard/test_foo')
 
875
 
 
876
    def test_import(self):
 
877
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
878
        plugin.set_plugins_path(['standard'])
 
879
        try:
 
880
            import bzrlib.plugins.test_foo
 
881
        except ImportError:
 
882
            pass
 
883
        self.assertTestFooLoadedFrom('non-standard-dir')
 
884
 
 
885
    def test_loading(self):
 
886
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
887
        plugin.load_plugins(['standard'])
 
888
        self.assertTestFooLoadedFrom('non-standard-dir')
 
889
 
 
890
    def test_compiled_loaded(self):
 
891
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
892
        plugin.load_plugins(['standard'])
 
893
        self.assertTestFooLoadedFrom('non-standard-dir')
 
894
        self.assertIsSameRealPath('non-standard-dir/__init__.py',
 
895
                                  bzrlib.plugins.test_foo.__file__)
 
896
 
 
897
        # Try importing again now that the source has been compiled
 
898
        self._unregister_plugin('test_foo')
 
899
        plugin._loaded = False
 
900
        plugin.load_plugins(['standard'])
 
901
        self.assertTestFooLoadedFrom('non-standard-dir')
 
902
        if __debug__:
 
903
            suffix = 'pyc'
 
904
        else:
 
905
            suffix = 'pyo'
 
906
        self.assertIsSameRealPath('non-standard-dir/__init__.%s' % suffix,
 
907
                                  bzrlib.plugins.test_foo.__file__)
 
908
 
 
909
    def test_submodule_loading(self):
 
910
        # We create an additional directory under the one for test_foo
 
911
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
 
912
        self.addCleanup(self._unregister_plugin_submodule,
 
913
                        'test_foo', 'test_bar')
 
914
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
915
        plugin.set_plugins_path(['standard'])
 
916
        import bzrlib.plugins.test_foo
 
917
        self.assertEqual('bzrlib.plugins.test_foo',
 
918
                         bzrlib.plugins.test_foo.__package__)
 
919
        import bzrlib.plugins.test_foo.test_bar
 
920
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
 
921
                                  bzrlib.plugins.test_foo.test_bar.__file__)
 
922
 
 
923
    def test_relative_submodule_loading(self):
 
924
        self.create_plugin_package('test_foo', dir='another-dir', source='''
 
925
import test_bar
 
926
''')
 
927
        # We create an additional directory under the one for test_foo
 
928
        self.create_plugin_package('test_bar', dir='another-dir/test_bar')
 
929
        self.addCleanup(self._unregister_plugin_submodule,
 
930
                        'test_foo', 'test_bar')
 
931
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@another-dir')
 
932
        plugin.set_plugins_path(['standard'])
 
933
        import bzrlib.plugins.test_foo
 
934
        self.assertEqual('bzrlib.plugins.test_foo',
 
935
                         bzrlib.plugins.test_foo.__package__)
 
936
        self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
 
937
                                  bzrlib.plugins.test_foo.test_bar.__file__)
 
938
 
 
939
    def test_loading_from___init__only(self):
 
940
        # We rename the existing __init__.py file to ensure that we don't load
 
941
        # a random file
 
942
        init = 'non-standard-dir/__init__.py'
 
943
        random = 'non-standard-dir/setup.py'
 
944
        os.rename(init, random)
 
945
        self.addCleanup(os.rename, random, init)
 
946
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
947
        plugin.load_plugins(['standard'])
 
948
        self.assertPluginUnknown('test_foo')
 
949
 
 
950
    def test_loading_from_specific_file(self):
 
951
        plugin_dir = 'non-standard-dir'
 
952
        plugin_file_name = 'iamtestfoo.py'
 
953
        plugin_path = osutils.pathjoin(plugin_dir, plugin_file_name)
 
954
        source = '''\
 
955
"""This is the doc for %s"""
 
956
dir_source = '%s'
 
957
''' % ('test_foo', plugin_path)
 
958
        self.create_plugin('test_foo', source=source,
 
959
                           dir=plugin_dir, file_name=plugin_file_name)
 
960
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
 
961
        plugin.load_plugins(['standard'])
 
962
        self.assertTestFooLoadedFrom(plugin_path)
 
963
 
 
964
 
 
965
class TestDescribePlugins(BaseTestPlugins):
 
966
 
 
967
    def test_describe_plugins(self):
 
968
        class DummyModule(object):
 
969
            __doc__ = 'Hi there'
 
970
        class DummyPlugin(object):
 
971
            __version__ = '0.1.0'
 
972
            module = DummyModule()
 
973
        def dummy_plugins():
 
974
            return { 'good': DummyPlugin() }
 
975
        self.overrideAttr(plugin, 'plugin_warnings',
 
976
            {'bad': ['Failed to load (just testing)']})
 
977
        self.overrideAttr(plugin, 'plugins', dummy_plugins)
 
978
        self.assertEquals("""\
 
979
bad (failed to load)
 
980
  ** Failed to load (just testing)
 
981
 
 
982
good 0.1.0
 
983
  Hi there
 
984
 
 
985
""", ''.join(plugin.describe_plugins()))