/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
1
# Copyright (C) 2005, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
750 by Martin Pool
- stubbed-out tests for python plugins
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
750 by Martin Pool
- stubbed-out tests for python plugins
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
12
#
750 by Martin Pool
- stubbed-out tests for python plugins
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for plugins"""
18
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
19
# XXX: There are no plugin tests at the moment because the plugin module
20
# affects the global state of the process.  See bzrlib/plugins.py for more
21
# comments.
22
23
import os
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
24
from StringIO import StringIO
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
25
import sys
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
26
import zipfile
750 by Martin Pool
- stubbed-out tests for python plugins
27
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
28
from bzrlib import plugin, tests
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
29
import bzrlib.plugin
30
import bzrlib.plugins
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
31
import bzrlib.commands
32
import bzrlib.help
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
33
from bzrlib.symbol_versioning import zero_ninetyone
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
34
from bzrlib.tests import TestCase, TestCaseInTempDir
2839.2.1 by Alexander Belchenko
using functions from osutils instead of os.path.*
35
from bzrlib.osutils import pathjoin, abspath, normpath
1141 by Martin Pool
- rename FunctionalTest to TestCaseInTempDir
36
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
37
1185.16.84 by mbp at sourcefrog
- fix indents
38
PLUGIN_TEXT = """\
39
import bzrlib.commands
40
class cmd_myplug(bzrlib.commands.Command):
41
    '''Just a simple test plugin.'''
42
    aliases = ['mplg']
43
    def run(self):
44
        print 'Hello from my plugin'
45
"""
1492 by Robert Collins
Support decoration of commands.
46
47
# TODO: Write a test for plugin decoration of commands.
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
48
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
49
class TestLoadingPlugins(TestCaseInTempDir):
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
50
51
    activeattributes = {}
52
53
    def test_plugins_with_the_same_name_are_not_loaded(self):
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
54
        # This test tests that having two plugins in different directories does
55
        # not result in both being loaded when they have the same name.  get a
56
        # file name we can use which is also a valid attribute for accessing in
57
        # activeattributes. - we cannot give import parameters.
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
58
        tempattribute = "0"
59
        self.failIf(tempattribute in self.activeattributes)
60
        # set a place for the plugins to record their loading, and at the same
61
        # time validate that the location the plugins should record to is
62
        # valid and correct.
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
63
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
64
            [tempattribute] = []
65
        self.failUnless(tempattribute in self.activeattributes)
66
        # create two plugin directories
67
        os.mkdir('first')
68
        os.mkdir('second')
69
        # write a plugin that will record when its loaded in the 
70
        # tempattribute list.
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
71
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
72
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
73
74
        outfile = open(os.path.join('first', 'plugin.py'), 'w')
75
        try:
76
            print >> outfile, template % (tempattribute, 'first')
77
        finally:
78
            outfile.close()
79
80
        outfile = open(os.path.join('second', 'plugin.py'), 'w')
81
        try:
82
            print >> outfile, template % (tempattribute, 'second')
83
        finally:
84
            outfile.close()
85
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
86
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
87
            bzrlib.plugin.load_from_path(['first', 'second'])
88
            self.assertEqual(['first'], self.activeattributes[tempattribute])
89
        finally:
90
            # remove the plugin 'plugin'
91
            del self.activeattributes[tempattribute]
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
92
            if 'bzrlib.plugins.plugin' in sys.modules:
93
                del sys.modules['bzrlib.plugins.plugin']
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
94
            if getattr(bzrlib.plugins, 'plugin', None):
95
                del bzrlib.plugins.plugin
96
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
97
98
    def test_plugins_from_different_dirs_can_demand_load(self):
99
        # This test tests that having two plugins in different
100
        # directories with different names allows them both to be loaded, when
101
        # we do a direct import statement.
102
        # Determine a file name we can use which is also a valid attribute
103
        # for accessing in activeattributes. - we cannot give import parameters.
104
        tempattribute = "different-dirs"
105
        self.failIf(tempattribute in self.activeattributes)
106
        # set a place for the plugins to record their loading, and at the same
107
        # time validate that the location the plugins should record to is
108
        # valid and correct.
109
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
110
            [tempattribute] = []
111
        self.failUnless(tempattribute in self.activeattributes)
112
        # create two plugin directories
113
        os.mkdir('first')
114
        os.mkdir('second')
115
        # write plugins that will record when they are loaded in the 
116
        # tempattribute list.
117
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
118
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
119
120
        outfile = open(os.path.join('first', 'pluginone.py'), 'w')
121
        try:
122
            print >> outfile, template % (tempattribute, 'first')
123
        finally:
124
            outfile.close()
125
126
        outfile = open(os.path.join('second', 'plugintwo.py'), 'w')
127
        try:
128
            print >> outfile, template % (tempattribute, 'second')
129
        finally:
130
            outfile.close()
131
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
132
        oldpath = bzrlib.plugins.__path__
133
        try:
134
            bzrlib.plugins.__path__ = ['first', 'second']
135
            exec "import bzrlib.plugins.pluginone"
136
            self.assertEqual(['first'], self.activeattributes[tempattribute])
137
            exec "import bzrlib.plugins.plugintwo"
138
            self.assertEqual(['first', 'second'],
139
                self.activeattributes[tempattribute])
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
140
        finally:
141
            # remove the plugin 'plugin'
142
            del self.activeattributes[tempattribute]
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
143
            if getattr(bzrlib.plugins, 'pluginone', None):
144
                del bzrlib.plugins.pluginone
145
            if getattr(bzrlib.plugins, 'plugintwo', None):
146
                del bzrlib.plugins.plugintwo
147
        self.failIf(getattr(bzrlib.plugins, 'pluginone', None))
148
        self.failIf(getattr(bzrlib.plugins, 'plugintwo', None))
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
149
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
150
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
151
        # This test tests that a plugin can load from a directory when the
152
        # directory in the path has a trailing slash.
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
153
        # check the plugin is not loaded already
154
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
155
        tempattribute = "trailing-slash"
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
156
        self.failIf(tempattribute in self.activeattributes)
2652.2.3 by Blake Winton
Understand the code and comments of the test, instead of just cargo-culting them.
157
        # set a place for the plugin to record its loading, and at the same
158
        # time validate that the location the plugin should record to is
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
159
        # valid and correct.
160
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
161
            [tempattribute] = []
162
        self.failUnless(tempattribute in self.activeattributes)
2652.2.3 by Blake Winton
Understand the code and comments of the test, instead of just cargo-culting them.
163
        # create a directory for the plugin
164
        os.mkdir('plugin_test')
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
165
        # write a plugin that will record when its loaded in the 
166
        # tempattribute list.
167
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
168
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
169
170
        outfile = open(os.path.join('plugin_test', 'ts_plugin.py'), 'w')
171
        try:
172
            print >> outfile, template % (tempattribute, 'plugin')
173
        finally:
174
            outfile.close()
175
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
176
        try:
2652.2.3 by Blake Winton
Understand the code and comments of the test, instead of just cargo-culting them.
177
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
178
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
179
        finally:
180
            # remove the plugin 'plugin'
181
            del self.activeattributes[tempattribute]
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
182
            if getattr(bzrlib.plugins, 'ts_plugin', None):
183
                del bzrlib.plugins.ts_plugin
184
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
185
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
186
187
class TestAllPlugins(TestCaseInTempDir):
188
189
    def test_plugin_appears_in_all_plugins(self):
190
        # This test tests a new plugin appears in bzrlib.plugin.all_plugins().
191
        # check the plugin is not loaded already
192
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
193
        # write a plugin that _cannot_ fail to load.
194
        print >> file('plugin.py', 'w'), ""
195
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
196
            bzrlib.plugin.load_from_path(['.'])
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
197
            all_plugins = self.applyDeprecated(zero_ninetyone,
198
                bzrlib.plugin.all_plugins)
199
            self.failUnless('plugin' in all_plugins)
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
200
            self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
201
            self.assertEqual(all_plugins['plugin'], bzrlib.plugins.plugin)
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
202
        finally:
203
            # remove the plugin 'plugin'
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
204
            if 'bzrlib.plugins.plugin' in sys.modules:
205
                del sys.modules['bzrlib.plugins.plugin']
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
206
            if getattr(bzrlib.plugins, 'plugin', None):
207
                del bzrlib.plugins.plugin
208
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
209
210
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
211
class TestPlugins(TestCaseInTempDir):
212
213
    def setup_plugin(self, source=""):
214
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
215
        # check the plugin is not loaded already
216
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
217
        # write a plugin that _cannot_ fail to load.
218
        print >> file('plugin.py', 'w'), source
219
        self.addCleanup(self.teardown_plugin)
220
        bzrlib.plugin.load_from_path(['.'])
221
    
222
    def teardown_plugin(self):
223
        # remove the plugin 'plugin'
224
        if 'bzrlib.plugins.plugin' in sys.modules:
225
            del sys.modules['bzrlib.plugins.plugin']
226
        if getattr(bzrlib.plugins, 'plugin', None):
227
            del bzrlib.plugins.plugin
228
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
229
230
    def test_plugin_appears_in_plugins(self):
231
        self.setup_plugin()
232
        self.failUnless('plugin' in bzrlib.plugin.plugins())
233
        self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
234
        plugins = bzrlib.plugin.plugins()
235
        plugin = plugins['plugin']
236
        self.assertIsInstance(plugin, bzrlib.plugin.PlugIn)
237
        self.assertEqual(bzrlib.plugins.plugin, plugin.module)
238
239
    def test_trivial_plugin_get_path(self):
240
        self.setup_plugin()
241
        plugins = bzrlib.plugin.plugins()
242
        plugin = plugins['plugin']
243
        plugin_path = self.test_dir + '/plugin.py'
2823.1.10 by Vincent Ladeuil
merge bzr.dev
244
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
245
246
    def test_no_test_suite_gives_None_for_test_suite(self):
247
        self.setup_plugin()
248
        plugin = bzrlib.plugin.plugins()['plugin']
249
        self.assertEqual(None, plugin.test_suite())
250
251
    def test_test_suite_gives_test_suite_result(self):
252
        source = """def test_suite(): return 'foo'"""
253
        self.setup_plugin(source)
254
        plugin = bzrlib.plugin.plugins()['plugin']
255
        self.assertEqual('foo', plugin.test_suite())
256
257
    def test_no_version_info(self):
258
        self.setup_plugin()
259
        plugin = bzrlib.plugin.plugins()['plugin']
260
        self.assertEqual(None, plugin.version_info())
261
262
    def test_with_version_info(self):
263
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
264
        plugin = bzrlib.plugin.plugins()['plugin']
265
        self.assertEqual((1, 2, 3, 'dev', 4), plugin.version_info())
266
267
    def test_short_version_info_gets_padded(self):
268
        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
269
        # so we adapt it
270
        self.setup_plugin("version_info = (1, 2, 3)")
271
        plugin = bzrlib.plugin.plugins()['plugin']
272
        self.assertEqual((1, 2, 3, 'final', 0), plugin.version_info())
273
274
    def test_no_version_info___version__(self):
275
        self.setup_plugin()
276
        plugin = bzrlib.plugin.plugins()['plugin']
277
        self.assertEqual("unknown", plugin.__version__)
278
279
    def test___version__with_version_info(self):
280
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
281
        plugin = bzrlib.plugin.plugins()['plugin']
282
        self.assertEqual("1.2.3dev4", plugin.__version__)
283
284
    def test_final__version__with_version_info(self):
285
        self.setup_plugin("version_info = (1, 2, 3, 'final', 4)")
286
        plugin = bzrlib.plugin.plugins()['plugin']
287
        self.assertEqual("1.2.3", plugin.__version__)
288
289
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
290
class TestPluginHelp(TestCaseInTempDir):
291
292
    def split_help_commands(self):
293
        help = {}
294
        current = None
2530.3.4 by Martin Pool
Deprecate run_bzr_captured in favour of just run_bzr
295
        for line in self.run_bzr('help commands')[0].splitlines():
2034.1.2 by Aaron Bentley
Fix testcase
296
            if not line.startswith(' '):
297
                current = line.split()[0]
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
298
            help[current] = help.get(current, '') + line
299
300
        return help
301
302
    def test_plugin_help_builtins_unaffected(self):
303
        # Check we don't get false positives
304
        help_commands = self.split_help_commands()
305
        for cmd_name in bzrlib.commands.builtin_command_names():
306
            if cmd_name in bzrlib.commands.plugin_command_names():
307
                continue
308
            try:
2432.1.12 by Robert Collins
Relocate command help onto Command.
309
                help = bzrlib.commands.get_cmd_object(cmd_name).get_help_text()
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
310
            except NotImplementedError:
311
                # some commands have no help
312
                pass
313
            else:
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
314
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
315
2432.1.12 by Robert Collins
Relocate command help onto Command.
316
            if cmd_name in help_commands.keys():
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
317
                # some commands are hidden
318
                help = help_commands[cmd_name]
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
319
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
320
321
    def test_plugin_help_shows_plugin(self):
322
        # Create a test plugin
323
        os.mkdir('plugin_test')
324
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
325
        f.write(PLUGIN_TEXT)
326
        f.close()
327
328
        try:
329
            # Check its help
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
330
            bzrlib.plugin.load_from_path(['plugin_test'])
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
331
            bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
2530.3.4 by Martin Pool
Deprecate run_bzr_captured in favour of just run_bzr
332
            help = self.run_bzr('help myplug')[0]
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
333
            self.assertContainsRe(help, 'plugin "myplug"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
334
            help = self.split_help_commands()['myplug']
2034.1.4 by Aaron Bentley
Change angle brackets to square brackets
335
            self.assertContainsRe(help, '\[myplug\]')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
336
        finally:
2204.3.2 by Alexander Belchenko
cherrypicking: test_plugin_help_shows_plugin: fix cleanup after test
337
            # unregister command
338
            if bzrlib.commands.plugin_cmds.get('myplug', None):
339
                del bzrlib.commands.plugin_cmds['myplug']
340
            # remove the plugin 'myplug'
341
            if getattr(bzrlib.plugins, 'myplug', None):
342
                delattr(bzrlib.plugins, 'myplug')
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
343
344
345
class TestPluginFromZip(TestCaseInTempDir):
346
347
    def make_zipped_plugin(self, zip_name, filename):
348
        z = zipfile.ZipFile(zip_name, 'w')
349
        z.writestr(filename, PLUGIN_TEXT)
350
        z.close()
351
352
    def check_plugin_load(self, zip_name, plugin_name):
353
        self.assertFalse(plugin_name in dir(bzrlib.plugins),
354
                         'Plugin already loaded')
2610.2.1 by Martin Pool
(Lukas Lalinsky) don't create a duplicate zipimporter, avoiding loading plugins twice
355
        old_path = bzrlib.plugins.__path__
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
356
        try:
2610.2.1 by Martin Pool
(Lukas Lalinsky) don't create a duplicate zipimporter, avoiding loading plugins twice
357
            # this is normally done by load_plugins -> set_plugins_path
358
            bzrlib.plugins.__path__ = [zip_name]
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
359
            bzrlib.plugin.load_from_zip(zip_name)
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
360
            self.assertTrue(plugin_name in dir(bzrlib.plugins),
361
                            'Plugin is not loaded')
362
        finally:
363
            # unregister plugin
364
            if getattr(bzrlib.plugins, plugin_name, None):
365
                delattr(bzrlib.plugins, plugin_name)
2610.2.1 by Martin Pool
(Lukas Lalinsky) don't create a duplicate zipimporter, avoiding loading plugins twice
366
                del sys.modules['bzrlib.plugins.' + plugin_name]
367
            bzrlib.plugins.__path__ = old_path
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
368
369
    def test_load_module(self):
370
        self.make_zipped_plugin('./test.zip', 'ziplug.py')
371
        self.check_plugin_load('./test.zip', 'ziplug')
372
373
    def test_load_package(self):
374
        self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
375
        self.check_plugin_load('./test.zip', 'ziplug')
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
376
377
378
class TestSetPluginsPath(TestCase):
379
    
380
    def test_set_plugins_path(self):
381
        """set_plugins_path should set the module __path__ correctly."""
382
        old_path = bzrlib.plugins.__path__
383
        try:
384
            bzrlib.plugins.__path__ = []
385
            expected_path = bzrlib.plugin.set_plugins_path()
386
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
387
        finally:
388
            bzrlib.plugins.__path__ = old_path
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
389
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
390
    def test_set_plugins_path_with_trailing_slashes(self):
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
391
        """set_plugins_path should set the module __path__ based on
392
        BZR_PLUGIN_PATH."""
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
393
        old_path = bzrlib.plugins.__path__
394
        old_env = os.environ.get('BZR_PLUGIN_PATH')
395
        try:
396
            bzrlib.plugins.__path__ = []
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
397
            os.environ['BZR_PLUGIN_PATH'] = "first\\//\\" + os.pathsep + \
398
                "second/\\/\\/"
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
399
            bzrlib.plugin.set_plugins_path()
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
400
            expected_path = ['first', 'second',
401
                os.path.dirname(bzrlib.plugins.__file__)]
2652.2.1 by Blake Winton
Add a test for BZR_PLUGIN_PATH, and code and another test to allow BZR_PLUGIN_PATH to contain trailing slashes.
402
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
403
        finally:
404
            bzrlib.plugins.__path__ = old_path
405
            if old_env != None:
406
                os.environ['BZR_PLUGIN_PATH'] = old_env
407
            else:
408
                del os.environ['BZR_PLUGIN_PATH']
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
409
410
class TestHelpIndex(tests.TestCase):
411
    """Tests for the PluginsHelpIndex class."""
412
413
    def test_default_constructable(self):
414
        index = plugin.PluginsHelpIndex()
415
416
    def test_get_topics_None(self):
417
        """Searching for None returns an empty list."""
418
        index = plugin.PluginsHelpIndex()
419
        self.assertEqual([], index.get_topics(None))
420
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
421
    def test_get_topics_for_plugin(self):
422
        """Searching for plugin name gets its docstring."""
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
423
        index = plugin.PluginsHelpIndex()
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
424
        # make a new plugin here for this test, even if we're run with
425
        # --no-plugins
426
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
427
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
428
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
2457.1.1 by Robert Collins
(robertc) Fix bzr --no-plugins selftest which was broken by the help indices patch. (Robert Collins, Martin Pool)
429
        try:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
430
            topics = index.get_topics('demo_module')
2457.1.1 by Robert Collins
(robertc) Fix bzr --no-plugins selftest which was broken by the help indices patch. (Robert Collins, Martin Pool)
431
            self.assertEqual(1, len(topics))
432
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
433
            self.assertEqual(demo_module, topics[0].module)
434
        finally:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
435
            del sys.modules['bzrlib.plugins.demo_module']
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
436
437
    def test_get_topics_no_topic(self):
438
        """Searching for something that is not a plugin returns []."""
439
        # test this by using a name that cannot be a plugin - its not
440
        # a valid python identifier.
441
        index = plugin.PluginsHelpIndex()
442
        self.assertEqual([], index.get_topics('nothing by this name'))
443
444
    def test_prefix(self):
445
        """PluginsHelpIndex has a prefix of 'plugins/'."""
446
        index = plugin.PluginsHelpIndex()
447
        self.assertEqual('plugins/', index.prefix)
448
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
449
    def test_get_plugin_topic_with_prefix(self):
450
        """Searching for plugins/demo_module returns help."""
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
451
        index = plugin.PluginsHelpIndex()
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
452
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
453
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
454
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
2457.1.1 by Robert Collins
(robertc) Fix bzr --no-plugins selftest which was broken by the help indices patch. (Robert Collins, Martin Pool)
455
        try:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
456
            topics = index.get_topics('plugins/demo_module')
2457.1.1 by Robert Collins
(robertc) Fix bzr --no-plugins selftest which was broken by the help indices patch. (Robert Collins, Martin Pool)
457
            self.assertEqual(1, len(topics))
458
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
459
            self.assertEqual(demo_module, topics[0].module)
460
        finally:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
461
            del sys.modules['bzrlib.plugins.demo_module']
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
462
463
464
class FakeModule(object):
465
    """A fake module to test with."""
466
467
    def __init__(self, doc, name):
468
        self.__doc__ = doc
469
        self.__name__ = name
470
471
472
class TestModuleHelpTopic(tests.TestCase):
473
    """Tests for the ModuleHelpTopic class."""
474
475
    def test_contruct(self):
476
        """Construction takes the module to document."""
477
        mod = FakeModule('foo', 'foo')
478
        topic = plugin.ModuleHelpTopic(mod)
479
        self.assertEqual(mod, topic.module)
480
481
    def test_get_help_text_None(self):
482
        """A ModuleHelpTopic returns the docstring for get_help_text."""
483
        mod = FakeModule(None, 'demo')
484
        topic = plugin.ModuleHelpTopic(mod)
485
        self.assertEqual("Plugin 'demo' has no docstring.\n",
486
            topic.get_help_text())
487
488
    def test_get_help_text_no_carriage_return(self):
489
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
490
        mod = FakeModule('one line of help', 'demo')
491
        topic = plugin.ModuleHelpTopic(mod)
492
        self.assertEqual("one line of help\n",
493
            topic.get_help_text())
494
495
    def test_get_help_text_carriage_return(self):
496
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
497
        mod = FakeModule('two lines of help\nand more\n', 'demo')
498
        topic = plugin.ModuleHelpTopic(mod)
499
        self.assertEqual("two lines of help\nand more\n",
500
            topic.get_help_text())
501
502
    def test_get_help_text_with_additional_see_also(self):
503
        mod = FakeModule('two lines of help\nand more', 'demo')
504
        topic = plugin.ModuleHelpTopic(mod)
505
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
506
            topic.get_help_text(['foo', 'bar']))
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
507
508
    def test_get_help_topic(self):
509
        """The help topic for a plugin is its module name."""
2432.1.30 by Robert Collins
Fix the ModuleHelpTopic get_help_topic to be tested with closer to real world data and strip the bzrlib.plugins. prefix from the name.
510
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
511
        topic = plugin.ModuleHelpTopic(mod)
512
        self.assertEqual('demo', topic.get_help_topic())
2432.1.30 by Robert Collins
Fix the ModuleHelpTopic get_help_topic to be tested with closer to real world data and strip the bzrlib.plugins. prefix from the name.
513
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
514
        topic = plugin.ModuleHelpTopic(mod)
515
        self.assertEqual('foo_bar', topic.get_help_topic())