/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_plugins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-08-28 05:54:22 UTC
  • mfrom: (2754.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070828055422-9h8abp4darakavba
(Lukáš Lalinský) Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
 
18
17
"""Tests for plugins"""
19
18
 
20
19
# XXX: There are no plugin tests at the moment because the plugin module
22
21
# comments.
23
22
 
24
23
import os
 
24
from StringIO import StringIO
 
25
import sys
 
26
import zipfile
25
27
 
 
28
from bzrlib import plugin, tests
26
29
import bzrlib.plugin
27
30
import bzrlib.plugins
28
 
from bzrlib.tests import TestCaseInTempDir
 
31
import bzrlib.commands
 
32
import bzrlib.help
 
33
from bzrlib.tests import TestCase, TestCaseInTempDir
29
34
from bzrlib.osutils import pathjoin, abspath
30
35
 
31
 
class PluginTest(TestCaseInTempDir):
32
 
    """Create an external plugin and test loading."""
33
 
#    def test_plugin_loading(self):
34
 
#        orig_help = self.run_bzr_captured('bzr help commands')[0]
35
 
#        os.mkdir('plugin_test')
36
 
#        f = open(pathjoin('plugin_test', 'myplug.py'), 'wt')
37
 
#        f.write(PLUGIN_TEXT)
38
 
#        f.close()
39
 
#        newhelp = self.run_bzr_captured('bzr help commands')[0]
40
 
#        assert newhelp.startswith('You have been overridden\n')
41
 
#        # We added a line, but the rest should work
42
 
#        assert newhelp[25:] == help
43
 
#
44
 
#        assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
45
 
#
46
 
#        shutil.rmtree('plugin_test')
47
 
#
48
 
 
49
 
#         os.environ['BZRPLUGINPATH'] = abspath('plugin_test')
50
 
#         help = backtick('bzr help commands')
51
 
#         assert help.find('myplug') != -1
52
 
#         assert help.find('Just a simple test plugin.') != -1
53
 
 
54
 
 
55
 
#         assert backtick('bzr myplug') == 'Hello from my plugin\n'
56
 
#         assert backtick('bzr mplg') == 'Hello from my plugin\n'
57
 
 
58
 
#         f = open(pathjoin('plugin_test', 'override.py'), 'wb')
59
 
#         f.write("""import bzrlib, bzrlib.commands
60
 
#     class cmd_commit(bzrlib.commands.cmd_commit):
61
 
#         '''Commit changes into a new revision.'''
62
 
#         def run(self, *args, **kwargs):
63
 
#             print "I'm sorry dave, you can't do that"
64
 
 
65
 
#     class cmd_help(bzrlib.commands.cmd_help):
66
 
#         '''Show help on a command or other topic.'''
67
 
#         def run(self, *args, **kwargs):
68
 
#             print "You have been overridden"
69
 
#             bzrlib.commands.cmd_help.run(self, *args, **kwargs)
70
 
 
71
 
#         """
72
36
 
73
37
PLUGIN_TEXT = """\
74
38
import bzrlib.commands
81
45
 
82
46
# TODO: Write a test for plugin decoration of commands.
83
47
 
84
 
class TestOneNamedPluginOnly(TestCaseInTempDir):
 
48
class TestLoadingPlugins(TestCaseInTempDir):
85
49
 
86
50
    activeattributes = {}
87
51
 
88
52
    def test_plugins_with_the_same_name_are_not_loaded(self):
 
53
        # This test tests that having two plugins in different directories does
 
54
        # not result in both being loaded when they have the same name.  get a
 
55
        # file name we can use which is also a valid attribute for accessing in
 
56
        # activeattributes. - we cannot give import parameters.
 
57
        tempattribute = "0"
 
58
        self.failIf(tempattribute in self.activeattributes)
 
59
        # set a place for the plugins to record their loading, and at the same
 
60
        # time validate that the location the plugins should record to is
 
61
        # valid and correct.
 
62
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
63
            [tempattribute] = []
 
64
        self.failUnless(tempattribute in self.activeattributes)
 
65
        # create two plugin directories
 
66
        os.mkdir('first')
 
67
        os.mkdir('second')
 
68
        # write a plugin that will record when its loaded in the 
 
69
        # tempattribute list.
 
70
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
71
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
72
 
 
73
        outfile = open(os.path.join('first', 'plugin.py'), 'w')
 
74
        try:
 
75
            print >> outfile, template % (tempattribute, 'first')
 
76
        finally:
 
77
            outfile.close()
 
78
 
 
79
        outfile = open(os.path.join('second', 'plugin.py'), 'w')
 
80
        try:
 
81
            print >> outfile, template % (tempattribute, 'second')
 
82
        finally:
 
83
            outfile.close()
 
84
 
 
85
        try:
 
86
            bzrlib.plugin.load_from_path(['first', 'second'])
 
87
            self.assertEqual(['first'], self.activeattributes[tempattribute])
 
88
        finally:
 
89
            # remove the plugin 'plugin'
 
90
            del self.activeattributes[tempattribute]
 
91
            if getattr(bzrlib.plugins, 'plugin', None):
 
92
                del bzrlib.plugins.plugin
 
93
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
94
 
 
95
    def test_plugins_from_different_dirs_can_demand_load(self):
89
96
        # This test tests that having two plugins in different
90
 
        # directories does not result in both being loaded.
91
 
        # get a file name we can use which is also a valid attribute
 
97
        # directories with different names allows them both to be loaded, when
 
98
        # we do a direct import statement.
 
99
        # Determine a file name we can use which is also a valid attribute
92
100
        # for accessing in activeattributes. - we cannot give import parameters.
93
 
        tempattribute = "0"
 
101
        tempattribute = "different-dirs"
94
102
        self.failIf(tempattribute in self.activeattributes)
95
103
        # set a place for the plugins to record their loading, and at the same
96
104
        # time validate that the location the plugins should record to is
97
105
        # valid and correct.
98
 
        bzrlib.tests.test_plugins.TestOneNamedPluginOnly.activeattributes \
 
106
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
99
107
            [tempattribute] = []
100
108
        self.failUnless(tempattribute in self.activeattributes)
101
109
        # create two plugin directories
102
110
        os.mkdir('first')
103
111
        os.mkdir('second')
104
 
        # write a plugin that will record when its loaded in the 
 
112
        # write plugins that will record when they are loaded in the 
105
113
        # tempattribute list.
106
 
        template = ("from bzrlib.tests.test_plugins import TestOneNamedPluginOnly\n"
107
 
                    "TestOneNamedPluginOnly.activeattributes[%r].append('%s')\n")
108
 
        print >> file(os.path.join('first', 'plugin.py'), 'w'), template % (tempattribute, 'first')
109
 
        print >> file(os.path.join('second', 'plugin.py'), 'w'), template % (tempattribute, 'second')
110
 
        try:
111
 
            bzrlib.plugin.load_from_dirs(['first', 'second'])
 
114
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
115
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
116
 
 
117
        outfile = open(os.path.join('first', 'pluginone.py'), 'w')
 
118
        try:
 
119
            print >> outfile, template % (tempattribute, 'first')
 
120
        finally:
 
121
            outfile.close()
 
122
 
 
123
        outfile = open(os.path.join('second', 'plugintwo.py'), 'w')
 
124
        try:
 
125
            print >> outfile, template % (tempattribute, 'second')
 
126
        finally:
 
127
            outfile.close()
 
128
 
 
129
        oldpath = bzrlib.plugins.__path__
 
130
        try:
 
131
            bzrlib.plugins.__path__ = ['first', 'second']
 
132
            exec "import bzrlib.plugins.pluginone"
112
133
            self.assertEqual(['first'], self.activeattributes[tempattribute])
 
134
            exec "import bzrlib.plugins.plugintwo"
 
135
            self.assertEqual(['first', 'second'],
 
136
                self.activeattributes[tempattribute])
113
137
        finally:
114
138
            # remove the plugin 'plugin'
115
139
            del self.activeattributes[tempattribute]
117
141
                del bzrlib.plugins.plugin
118
142
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
119
143
 
 
144
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
 
145
        # This test tests that a plugin can load from a directory when the
 
146
        # directory in the path has a trailing slash.
 
147
        # check the plugin is not loaded already
 
148
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
149
        tempattribute = "trailing-slash"
 
150
        self.failIf(tempattribute in self.activeattributes)
 
151
        # set a place for the plugin to record its loading, and at the same
 
152
        # time validate that the location the plugin should record to is
 
153
        # valid and correct.
 
154
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
155
            [tempattribute] = []
 
156
        self.failUnless(tempattribute in self.activeattributes)
 
157
        # create a directory for the plugin
 
158
        os.mkdir('plugin_test')
 
159
        # write a plugin that will record when its loaded in the 
 
160
        # tempattribute list.
 
161
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
162
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
163
 
 
164
        outfile = open(os.path.join('plugin_test', 'ts_plugin.py'), 'w')
 
165
        try:
 
166
            print >> outfile, template % (tempattribute, 'plugin')
 
167
        finally:
 
168
            outfile.close()
 
169
 
 
170
        try:
 
171
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
 
172
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
 
173
        finally:
 
174
            # remove the plugin 'plugin'
 
175
            del self.activeattributes[tempattribute]
 
176
            if getattr(bzrlib.plugins, 'ts_plugin', None):
 
177
                del bzrlib.plugins.ts_plugin
 
178
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
179
 
120
180
 
121
181
class TestAllPlugins(TestCaseInTempDir):
122
182
 
127
187
        # write a plugin that _cannot_ fail to load.
128
188
        print >> file('plugin.py', 'w'), ""
129
189
        try:
130
 
            bzrlib.plugin.load_from_dirs(['.'])
 
190
            bzrlib.plugin.load_from_path(['.'])
131
191
            self.failUnless('plugin' in bzrlib.plugin.all_plugins())
132
192
            self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
133
193
            self.assertEqual(bzrlib.plugin.all_plugins()['plugin'],
134
194
                             bzrlib.plugins.plugin)
135
195
        finally:
136
196
            # remove the plugin 'plugin'
 
197
            if 'bzrlib.plugins.plugin' in sys.modules:
 
198
                del sys.modules['bzrlib.plugins.plugin']
137
199
            if getattr(bzrlib.plugins, 'plugin', None):
138
200
                del bzrlib.plugins.plugin
139
201
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
202
 
 
203
 
 
204
class TestPluginHelp(TestCaseInTempDir):
 
205
 
 
206
    def split_help_commands(self):
 
207
        help = {}
 
208
        current = None
 
209
        for line in self.run_bzr('help commands')[0].splitlines():
 
210
            if not line.startswith(' '):
 
211
                current = line.split()[0]
 
212
            help[current] = help.get(current, '') + line
 
213
 
 
214
        return help
 
215
 
 
216
    def test_plugin_help_builtins_unaffected(self):
 
217
        # Check we don't get false positives
 
218
        help_commands = self.split_help_commands()
 
219
        for cmd_name in bzrlib.commands.builtin_command_names():
 
220
            if cmd_name in bzrlib.commands.plugin_command_names():
 
221
                continue
 
222
            try:
 
223
                help = bzrlib.commands.get_cmd_object(cmd_name).get_help_text()
 
224
            except NotImplementedError:
 
225
                # some commands have no help
 
226
                pass
 
227
            else:
 
228
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
 
229
 
 
230
            if cmd_name in help_commands.keys():
 
231
                # some commands are hidden
 
232
                help = help_commands[cmd_name]
 
233
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
 
234
 
 
235
    def test_plugin_help_shows_plugin(self):
 
236
        # Create a test plugin
 
237
        os.mkdir('plugin_test')
 
238
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
 
239
        f.write(PLUGIN_TEXT)
 
240
        f.close()
 
241
 
 
242
        try:
 
243
            # Check its help
 
244
            bzrlib.plugin.load_from_path(['plugin_test'])
 
245
            bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
 
246
            help = self.run_bzr('help myplug')[0]
 
247
            self.assertContainsRe(help, 'plugin "myplug"')
 
248
            help = self.split_help_commands()['myplug']
 
249
            self.assertContainsRe(help, '\[myplug\]')
 
250
        finally:
 
251
            # unregister command
 
252
            if bzrlib.commands.plugin_cmds.get('myplug', None):
 
253
                del bzrlib.commands.plugin_cmds['myplug']
 
254
            # remove the plugin 'myplug'
 
255
            if getattr(bzrlib.plugins, 'myplug', None):
 
256
                delattr(bzrlib.plugins, 'myplug')
 
257
 
 
258
 
 
259
class TestPluginFromZip(TestCaseInTempDir):
 
260
 
 
261
    def make_zipped_plugin(self, zip_name, filename):
 
262
        z = zipfile.ZipFile(zip_name, 'w')
 
263
        z.writestr(filename, PLUGIN_TEXT)
 
264
        z.close()
 
265
 
 
266
    def check_plugin_load(self, zip_name, plugin_name):
 
267
        self.assertFalse(plugin_name in dir(bzrlib.plugins),
 
268
                         'Plugin already loaded')
 
269
        old_path = bzrlib.plugins.__path__
 
270
        try:
 
271
            # this is normally done by load_plugins -> set_plugins_path
 
272
            bzrlib.plugins.__path__ = [zip_name]
 
273
            bzrlib.plugin.load_from_zip(zip_name)
 
274
            self.assertTrue(plugin_name in dir(bzrlib.plugins),
 
275
                            'Plugin is not loaded')
 
276
        finally:
 
277
            # unregister plugin
 
278
            if getattr(bzrlib.plugins, plugin_name, None):
 
279
                delattr(bzrlib.plugins, plugin_name)
 
280
                del sys.modules['bzrlib.plugins.' + plugin_name]
 
281
            bzrlib.plugins.__path__ = old_path
 
282
 
 
283
    def test_load_module(self):
 
284
        self.make_zipped_plugin('./test.zip', 'ziplug.py')
 
285
        self.check_plugin_load('./test.zip', 'ziplug')
 
286
 
 
287
    def test_load_package(self):
 
288
        self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
 
289
        self.check_plugin_load('./test.zip', 'ziplug')
 
290
 
 
291
 
 
292
class TestSetPluginsPath(TestCase):
 
293
    
 
294
    def test_set_plugins_path(self):
 
295
        """set_plugins_path should set the module __path__ correctly."""
 
296
        old_path = bzrlib.plugins.__path__
 
297
        try:
 
298
            bzrlib.plugins.__path__ = []
 
299
            expected_path = bzrlib.plugin.set_plugins_path()
 
300
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
 
301
        finally:
 
302
            bzrlib.plugins.__path__ = old_path
 
303
 
 
304
    def test_set_plugins_path_with_trailing_slashes(self):
 
305
        """set_plugins_path should set the module __path__ based on
 
306
        BZR_PLUGIN_PATH."""
 
307
        old_path = bzrlib.plugins.__path__
 
308
        old_env = os.environ.get('BZR_PLUGIN_PATH')
 
309
        try:
 
310
            bzrlib.plugins.__path__ = []
 
311
            os.environ['BZR_PLUGIN_PATH'] = "first\\//\\" + os.pathsep + \
 
312
                "second/\\/\\/"
 
313
            bzrlib.plugin.set_plugins_path()
 
314
            expected_path = ['first', 'second',
 
315
                os.path.dirname(bzrlib.plugins.__file__)]
 
316
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
 
317
        finally:
 
318
            bzrlib.plugins.__path__ = old_path
 
319
            if old_env != None:
 
320
                os.environ['BZR_PLUGIN_PATH'] = old_env
 
321
            else:
 
322
                del os.environ['BZR_PLUGIN_PATH']
 
323
 
 
324
class TestHelpIndex(tests.TestCase):
 
325
    """Tests for the PluginsHelpIndex class."""
 
326
 
 
327
    def test_default_constructable(self):
 
328
        index = plugin.PluginsHelpIndex()
 
329
 
 
330
    def test_get_topics_None(self):
 
331
        """Searching for None returns an empty list."""
 
332
        index = plugin.PluginsHelpIndex()
 
333
        self.assertEqual([], index.get_topics(None))
 
334
 
 
335
    def test_get_topics_for_plugin(self):
 
336
        """Searching for plugin name gets its docstring."""
 
337
        index = plugin.PluginsHelpIndex()
 
338
        # make a new plugin here for this test, even if we're run with
 
339
        # --no-plugins
 
340
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
 
341
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
 
342
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
343
        try:
 
344
            topics = index.get_topics('demo_module')
 
345
            self.assertEqual(1, len(topics))
 
346
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
 
347
            self.assertEqual(demo_module, topics[0].module)
 
348
        finally:
 
349
            del sys.modules['bzrlib.plugins.demo_module']
 
350
 
 
351
    def test_get_topics_no_topic(self):
 
352
        """Searching for something that is not a plugin returns []."""
 
353
        # test this by using a name that cannot be a plugin - its not
 
354
        # a valid python identifier.
 
355
        index = plugin.PluginsHelpIndex()
 
356
        self.assertEqual([], index.get_topics('nothing by this name'))
 
357
 
 
358
    def test_prefix(self):
 
359
        """PluginsHelpIndex has a prefix of 'plugins/'."""
 
360
        index = plugin.PluginsHelpIndex()
 
361
        self.assertEqual('plugins/', index.prefix)
 
362
 
 
363
    def test_get_plugin_topic_with_prefix(self):
 
364
        """Searching for plugins/demo_module returns help."""
 
365
        index = plugin.PluginsHelpIndex()
 
366
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
 
367
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
 
368
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
369
        try:
 
370
            topics = index.get_topics('plugins/demo_module')
 
371
            self.assertEqual(1, len(topics))
 
372
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
 
373
            self.assertEqual(demo_module, topics[0].module)
 
374
        finally:
 
375
            del sys.modules['bzrlib.plugins.demo_module']
 
376
 
 
377
 
 
378
class FakeModule(object):
 
379
    """A fake module to test with."""
 
380
 
 
381
    def __init__(self, doc, name):
 
382
        self.__doc__ = doc
 
383
        self.__name__ = name
 
384
 
 
385
 
 
386
class TestModuleHelpTopic(tests.TestCase):
 
387
    """Tests for the ModuleHelpTopic class."""
 
388
 
 
389
    def test_contruct(self):
 
390
        """Construction takes the module to document."""
 
391
        mod = FakeModule('foo', 'foo')
 
392
        topic = plugin.ModuleHelpTopic(mod)
 
393
        self.assertEqual(mod, topic.module)
 
394
 
 
395
    def test_get_help_text_None(self):
 
396
        """A ModuleHelpTopic returns the docstring for get_help_text."""
 
397
        mod = FakeModule(None, 'demo')
 
398
        topic = plugin.ModuleHelpTopic(mod)
 
399
        self.assertEqual("Plugin 'demo' has no docstring.\n",
 
400
            topic.get_help_text())
 
401
 
 
402
    def test_get_help_text_no_carriage_return(self):
 
403
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
 
404
        mod = FakeModule('one line of help', 'demo')
 
405
        topic = plugin.ModuleHelpTopic(mod)
 
406
        self.assertEqual("one line of help\n",
 
407
            topic.get_help_text())
 
408
 
 
409
    def test_get_help_text_carriage_return(self):
 
410
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
 
411
        mod = FakeModule('two lines of help\nand more\n', 'demo')
 
412
        topic = plugin.ModuleHelpTopic(mod)
 
413
        self.assertEqual("two lines of help\nand more\n",
 
414
            topic.get_help_text())
 
415
 
 
416
    def test_get_help_text_with_additional_see_also(self):
 
417
        mod = FakeModule('two lines of help\nand more', 'demo')
 
418
        topic = plugin.ModuleHelpTopic(mod)
 
419
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
 
420
            topic.get_help_text(['foo', 'bar']))
 
421
 
 
422
    def test_get_help_topic(self):
 
423
        """The help topic for a plugin is its module name."""
 
424
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
 
425
        topic = plugin.ModuleHelpTopic(mod)
 
426
        self.assertEqual('demo', topic.get_help_topic())
 
427
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
 
428
        topic = plugin.ModuleHelpTopic(mod)
 
429
        self.assertEqual('foo_bar', topic.get_help_topic())