/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: 2008-03-28 06:42:20 UTC
  • mfrom: (3287.6.9 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080328064220-ongijg78bfqhvbay
Deprecate a number of VersionedFile method calls,
        and Repository.get_revision_graph. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
 
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 logging
 
24
import os
 
25
from StringIO import StringIO
 
26
import sys
 
27
import zipfile
 
28
 
 
29
from bzrlib import plugin, tests
 
30
import bzrlib.plugin
 
31
import bzrlib.plugins
 
32
import bzrlib.commands
 
33
import bzrlib.help
 
34
from bzrlib.symbol_versioning import one_three
 
35
from bzrlib.tests import TestCase, TestCaseInTempDir
 
36
from bzrlib.osutils import pathjoin, abspath, normpath
 
37
 
 
38
 
 
39
PLUGIN_TEXT = """\
 
40
import bzrlib.commands
 
41
class cmd_myplug(bzrlib.commands.Command):
 
42
    '''Just a simple test plugin.'''
 
43
    aliases = ['mplg']
 
44
    def run(self):
 
45
        print 'Hello from my plugin'
 
46
"""
 
47
 
 
48
# TODO: Write a test for plugin decoration of commands.
 
49
 
 
50
class TestLoadingPlugins(TestCaseInTempDir):
 
51
 
 
52
    activeattributes = {}
 
53
 
 
54
    def test_plugins_with_the_same_name_are_not_loaded(self):
 
55
        # This test tests that having two plugins in different directories does
 
56
        # not result in both being loaded when they have the same name.  get a
 
57
        # file name we can use which is also a valid attribute for accessing in
 
58
        # activeattributes. - we cannot give import parameters.
 
59
        tempattribute = "0"
 
60
        self.failIf(tempattribute in self.activeattributes)
 
61
        # set a place for the plugins to record their loading, and at the same
 
62
        # time validate that the location the plugins should record to is
 
63
        # valid and correct.
 
64
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
65
            [tempattribute] = []
 
66
        self.failUnless(tempattribute in self.activeattributes)
 
67
        # create two plugin directories
 
68
        os.mkdir('first')
 
69
        os.mkdir('second')
 
70
        # write a plugin that will record when its loaded in the 
 
71
        # tempattribute list.
 
72
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
73
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
74
 
 
75
        outfile = open(os.path.join('first', 'plugin.py'), 'w')
 
76
        try:
 
77
            outfile.write(template % (tempattribute, 'first'))
 
78
            outfile.write('\n')
 
79
        finally:
 
80
            outfile.close()
 
81
 
 
82
        outfile = open(os.path.join('second', 'plugin.py'), 'w')
 
83
        try:
 
84
            outfile.write(template % (tempattribute, 'second'))
 
85
            outfile.write('\n')
 
86
        finally:
 
87
            outfile.close()
 
88
 
 
89
        try:
 
90
            bzrlib.plugin.load_from_path(['first', 'second'])
 
91
            self.assertEqual(['first'], self.activeattributes[tempattribute])
 
92
        finally:
 
93
            # remove the plugin 'plugin'
 
94
            del self.activeattributes[tempattribute]
 
95
            if 'bzrlib.plugins.plugin' in sys.modules:
 
96
                del sys.modules['bzrlib.plugins.plugin']
 
97
            if getattr(bzrlib.plugins, 'plugin', None):
 
98
                del bzrlib.plugins.plugin
 
99
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
100
 
 
101
    def test_plugins_from_different_dirs_can_demand_load(self):
 
102
        # This test tests that having two plugins in different
 
103
        # directories with different names allows them both to be loaded, when
 
104
        # we do a direct import statement.
 
105
        # Determine a file name we can use which is also a valid attribute
 
106
        # for accessing in activeattributes. - we cannot give import parameters.
 
107
        tempattribute = "different-dirs"
 
108
        self.failIf(tempattribute in self.activeattributes)
 
109
        # set a place for the plugins to record their loading, and at the same
 
110
        # time validate that the location the plugins should record to is
 
111
        # valid and correct.
 
112
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
113
            [tempattribute] = []
 
114
        self.failUnless(tempattribute in self.activeattributes)
 
115
        # create two plugin directories
 
116
        os.mkdir('first')
 
117
        os.mkdir('second')
 
118
        # write plugins that will record when they are loaded in the 
 
119
        # tempattribute list.
 
120
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
121
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
122
 
 
123
        outfile = open(os.path.join('first', 'pluginone.py'), 'w')
 
124
        try:
 
125
            outfile.write(template % (tempattribute, 'first'))
 
126
            outfile.write('\n')
 
127
        finally:
 
128
            outfile.close()
 
129
 
 
130
        outfile = open(os.path.join('second', 'plugintwo.py'), 'w')
 
131
        try:
 
132
            outfile.write(template % (tempattribute, 'second'))
 
133
            outfile.write('\n')
 
134
        finally:
 
135
            outfile.close()
 
136
 
 
137
        oldpath = bzrlib.plugins.__path__
 
138
        try:
 
139
            bzrlib.plugins.__path__ = ['first', 'second']
 
140
            exec "import bzrlib.plugins.pluginone"
 
141
            self.assertEqual(['first'], self.activeattributes[tempattribute])
 
142
            exec "import bzrlib.plugins.plugintwo"
 
143
            self.assertEqual(['first', 'second'],
 
144
                self.activeattributes[tempattribute])
 
145
        finally:
 
146
            # remove the plugin 'plugin'
 
147
            del self.activeattributes[tempattribute]
 
148
            if getattr(bzrlib.plugins, 'pluginone', None):
 
149
                del bzrlib.plugins.pluginone
 
150
            if getattr(bzrlib.plugins, 'plugintwo', None):
 
151
                del bzrlib.plugins.plugintwo
 
152
        self.failIf(getattr(bzrlib.plugins, 'pluginone', None))
 
153
        self.failIf(getattr(bzrlib.plugins, 'plugintwo', None))
 
154
 
 
155
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
 
156
        # This test tests that a plugin can load from a directory when the
 
157
        # directory in the path has a trailing slash.
 
158
        # check the plugin is not loaded already
 
159
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
160
        tempattribute = "trailing-slash"
 
161
        self.failIf(tempattribute in self.activeattributes)
 
162
        # set a place for the plugin to record its loading, and at the same
 
163
        # time validate that the location the plugin should record to is
 
164
        # valid and correct.
 
165
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
166
            [tempattribute] = []
 
167
        self.failUnless(tempattribute in self.activeattributes)
 
168
        # create a directory for the plugin
 
169
        os.mkdir('plugin_test')
 
170
        # write a plugin that will record when its loaded in the 
 
171
        # tempattribute list.
 
172
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
173
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
 
174
 
 
175
        outfile = open(os.path.join('plugin_test', 'ts_plugin.py'), 'w')
 
176
        try:
 
177
            outfile.write(template % (tempattribute, 'plugin'))
 
178
            outfile.write('\n')
 
179
        finally:
 
180
            outfile.close()
 
181
 
 
182
        try:
 
183
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
 
184
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
 
185
        finally:
 
186
            # remove the plugin 'plugin'
 
187
            del self.activeattributes[tempattribute]
 
188
            if getattr(bzrlib.plugins, 'ts_plugin', None):
 
189
                del bzrlib.plugins.ts_plugin
 
190
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
191
 
 
192
    def test_plugin_with_bad_name_does_not_load(self):
 
193
        # Create badly-named plugin
 
194
        file('bzr-bad plugin-name..py', 'w').close()
 
195
 
 
196
        # Capture output
 
197
        stream = StringIO()
 
198
        handler = logging.StreamHandler(stream)
 
199
        log = logging.getLogger('bzr')
 
200
        log.addHandler(handler)
 
201
 
 
202
        bzrlib.plugin.load_from_dir('.')
 
203
 
 
204
        # Stop capturing output
 
205
        handler.flush()
 
206
        handler.close()
 
207
        log.removeHandler(handler)
 
208
 
 
209
        self.assertContainsRe(stream.getvalue(),
 
210
            r"Unable to load 'bzr-bad plugin-name\.' in '\.' as a plugin "
 
211
            "because the file path isn't a valid module name; try renaming "
 
212
            "it to 'bad_plugin_name_'\.")
 
213
 
 
214
        stream.close()
 
215
 
 
216
 
 
217
class TestPlugins(TestCaseInTempDir):
 
218
 
 
219
    def setup_plugin(self, source=""):
 
220
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
 
221
        # check the plugin is not loaded already
 
222
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
223
        # write a plugin that _cannot_ fail to load.
 
224
        file('plugin.py', 'w').write(source + '\n')
 
225
        self.addCleanup(self.teardown_plugin)
 
226
        bzrlib.plugin.load_from_path(['.'])
 
227
    
 
228
    def teardown_plugin(self):
 
229
        # remove the plugin 'plugin'
 
230
        if 'bzrlib.plugins.plugin' in sys.modules:
 
231
            del sys.modules['bzrlib.plugins.plugin']
 
232
        if getattr(bzrlib.plugins, 'plugin', None):
 
233
            del bzrlib.plugins.plugin
 
234
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
235
 
 
236
    def test_plugin_appears_in_plugins(self):
 
237
        self.setup_plugin()
 
238
        self.failUnless('plugin' in bzrlib.plugin.plugins())
 
239
        self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
 
240
        plugins = bzrlib.plugin.plugins()
 
241
        plugin = plugins['plugin']
 
242
        self.assertIsInstance(plugin, bzrlib.plugin.PlugIn)
 
243
        self.assertEqual(bzrlib.plugins.plugin, plugin.module)
 
244
 
 
245
    def test_trivial_plugin_get_path(self):
 
246
        self.setup_plugin()
 
247
        plugins = bzrlib.plugin.plugins()
 
248
        plugin = plugins['plugin']
 
249
        plugin_path = self.test_dir + '/plugin.py'
 
250
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
251
 
 
252
    def test_plugin_get_path_py_not_pyc(self):
 
253
        self.setup_plugin()         # after first import there will be plugin.pyc
 
254
        self.teardown_plugin()
 
255
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
 
256
        plugins = bzrlib.plugin.plugins()
 
257
        plugin = plugins['plugin']
 
258
        plugin_path = self.test_dir + '/plugin.py'
 
259
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
260
 
 
261
    def test_plugin_get_path_pyc_only(self):
 
262
        self.setup_plugin()         # after first import there will be plugin.pyc
 
263
        self.teardown_plugin()
 
264
        os.unlink(self.test_dir + '/plugin.py')
 
265
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
 
266
        plugins = bzrlib.plugin.plugins()
 
267
        plugin = plugins['plugin']
 
268
        if __debug__:
 
269
            plugin_path = self.test_dir + '/plugin.pyc'
 
270
        else:
 
271
            plugin_path = self.test_dir + '/plugin.pyo'
 
272
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
273
 
 
274
    def test_no_test_suite_gives_None_for_test_suite(self):
 
275
        self.setup_plugin()
 
276
        plugin = bzrlib.plugin.plugins()['plugin']
 
277
        self.assertEqual(None, plugin.test_suite())
 
278
 
 
279
    def test_test_suite_gives_test_suite_result(self):
 
280
        source = """def test_suite(): return 'foo'"""
 
281
        self.setup_plugin(source)
 
282
        plugin = bzrlib.plugin.plugins()['plugin']
 
283
        self.assertEqual('foo', plugin.test_suite())
 
284
 
 
285
    def test_no_version_info(self):
 
286
        self.setup_plugin()
 
287
        plugin = bzrlib.plugin.plugins()['plugin']
 
288
        self.assertEqual(None, plugin.version_info())
 
289
 
 
290
    def test_with_version_info(self):
 
291
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
 
292
        plugin = bzrlib.plugin.plugins()['plugin']
 
293
        self.assertEqual((1, 2, 3, 'dev', 4), plugin.version_info())
 
294
 
 
295
    def test_short_version_info_gets_padded(self):
 
296
        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
 
297
        # so we adapt it
 
298
        self.setup_plugin("version_info = (1, 2, 3)")
 
299
        plugin = bzrlib.plugin.plugins()['plugin']
 
300
        self.assertEqual((1, 2, 3, 'final', 0), plugin.version_info())
 
301
 
 
302
    def test_no_version_info___version__(self):
 
303
        self.setup_plugin()
 
304
        plugin = bzrlib.plugin.plugins()['plugin']
 
305
        self.assertEqual("unknown", plugin.__version__)
 
306
 
 
307
    def test___version__with_version_info(self):
 
308
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
 
309
        plugin = bzrlib.plugin.plugins()['plugin']
 
310
        self.assertEqual("1.2.3dev4", plugin.__version__)
 
311
 
 
312
    def test_final__version__with_version_info(self):
 
313
        self.setup_plugin("version_info = (1, 2, 3, 'final', 4)")
 
314
        plugin = bzrlib.plugin.plugins()['plugin']
 
315
        self.assertEqual("1.2.3", plugin.__version__)
 
316
 
 
317
 
 
318
class TestPluginHelp(TestCaseInTempDir):
 
319
 
 
320
    def split_help_commands(self):
 
321
        help = {}
 
322
        current = None
 
323
        for line in self.run_bzr('help commands')[0].splitlines():
 
324
            if not line.startswith(' '):
 
325
                current = line.split()[0]
 
326
            help[current] = help.get(current, '') + line
 
327
 
 
328
        return help
 
329
 
 
330
    def test_plugin_help_builtins_unaffected(self):
 
331
        # Check we don't get false positives
 
332
        help_commands = self.split_help_commands()
 
333
        for cmd_name in bzrlib.commands.builtin_command_names():
 
334
            if cmd_name in bzrlib.commands.plugin_command_names():
 
335
                continue
 
336
            try:
 
337
                help = bzrlib.commands.get_cmd_object(cmd_name).get_help_text()
 
338
            except NotImplementedError:
 
339
                # some commands have no help
 
340
                pass
 
341
            else:
 
342
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
 
343
 
 
344
            if cmd_name in help_commands.keys():
 
345
                # some commands are hidden
 
346
                help = help_commands[cmd_name]
 
347
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
 
348
 
 
349
    def test_plugin_help_shows_plugin(self):
 
350
        # Create a test plugin
 
351
        os.mkdir('plugin_test')
 
352
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
 
353
        f.write(PLUGIN_TEXT)
 
354
        f.close()
 
355
 
 
356
        try:
 
357
            # Check its help
 
358
            bzrlib.plugin.load_from_path(['plugin_test'])
 
359
            bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
 
360
            help = self.run_bzr('help myplug')[0]
 
361
            self.assertContainsRe(help, 'plugin "myplug"')
 
362
            help = self.split_help_commands()['myplug']
 
363
            self.assertContainsRe(help, '\[myplug\]')
 
364
        finally:
 
365
            # unregister command
 
366
            if bzrlib.commands.plugin_cmds.get('myplug', None):
 
367
                del bzrlib.commands.plugin_cmds['myplug']
 
368
            # remove the plugin 'myplug'
 
369
            if getattr(bzrlib.plugins, 'myplug', None):
 
370
                delattr(bzrlib.plugins, 'myplug')
 
371
 
 
372
 
 
373
class TestPluginFromZip(TestCaseInTempDir):
 
374
 
 
375
    def make_zipped_plugin(self, zip_name, filename):
 
376
        z = zipfile.ZipFile(zip_name, 'w')
 
377
        z.writestr(filename, PLUGIN_TEXT)
 
378
        z.close()
 
379
 
 
380
    def check_plugin_load(self, zip_name, plugin_name):
 
381
        self.assertFalse(plugin_name in dir(bzrlib.plugins),
 
382
                         'Plugin already loaded')
 
383
        old_path = bzrlib.plugins.__path__
 
384
        try:
 
385
            # this is normally done by load_plugins -> set_plugins_path
 
386
            bzrlib.plugins.__path__ = [zip_name]
 
387
            self.applyDeprecated(one_three,
 
388
                bzrlib.plugin.load_from_zip, zip_name)
 
389
            self.assertTrue(plugin_name in dir(bzrlib.plugins),
 
390
                            'Plugin is not loaded')
 
391
        finally:
 
392
            # unregister plugin
 
393
            if getattr(bzrlib.plugins, plugin_name, None):
 
394
                delattr(bzrlib.plugins, plugin_name)
 
395
                del sys.modules['bzrlib.plugins.' + plugin_name]
 
396
            bzrlib.plugins.__path__ = old_path
 
397
 
 
398
    def test_load_module(self):
 
399
        self.make_zipped_plugin('./test.zip', 'ziplug.py')
 
400
        self.check_plugin_load('./test.zip', 'ziplug')
 
401
 
 
402
    def test_load_package(self):
 
403
        self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
 
404
        self.check_plugin_load('./test.zip', 'ziplug')
 
405
 
 
406
 
 
407
class TestSetPluginsPath(TestCase):
 
408
    
 
409
    def test_set_plugins_path(self):
 
410
        """set_plugins_path should set the module __path__ correctly."""
 
411
        old_path = bzrlib.plugins.__path__
 
412
        try:
 
413
            bzrlib.plugins.__path__ = []
 
414
            expected_path = bzrlib.plugin.set_plugins_path()
 
415
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
 
416
        finally:
 
417
            bzrlib.plugins.__path__ = old_path
 
418
 
 
419
    def test_set_plugins_path_with_trailing_slashes(self):
 
420
        """set_plugins_path should set the module __path__ based on
 
421
        BZR_PLUGIN_PATH."""
 
422
        old_path = bzrlib.plugins.__path__
 
423
        old_env = os.environ.get('BZR_PLUGIN_PATH')
 
424
        try:
 
425
            bzrlib.plugins.__path__ = []
 
426
            os.environ['BZR_PLUGIN_PATH'] = "first\\//\\" + os.pathsep + \
 
427
                "second/\\/\\/"
 
428
            bzrlib.plugin.set_plugins_path()
 
429
            expected_path = ['first', 'second',
 
430
                os.path.dirname(bzrlib.plugins.__file__)]
 
431
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
 
432
        finally:
 
433
            bzrlib.plugins.__path__ = old_path
 
434
            if old_env != None:
 
435
                os.environ['BZR_PLUGIN_PATH'] = old_env
 
436
            else:
 
437
                del os.environ['BZR_PLUGIN_PATH']
 
438
 
 
439
class TestHelpIndex(tests.TestCase):
 
440
    """Tests for the PluginsHelpIndex class."""
 
441
 
 
442
    def test_default_constructable(self):
 
443
        index = plugin.PluginsHelpIndex()
 
444
 
 
445
    def test_get_topics_None(self):
 
446
        """Searching for None returns an empty list."""
 
447
        index = plugin.PluginsHelpIndex()
 
448
        self.assertEqual([], index.get_topics(None))
 
449
 
 
450
    def test_get_topics_for_plugin(self):
 
451
        """Searching for plugin name gets its docstring."""
 
452
        index = plugin.PluginsHelpIndex()
 
453
        # make a new plugin here for this test, even if we're run with
 
454
        # --no-plugins
 
455
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
 
456
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
 
457
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
458
        try:
 
459
            topics = index.get_topics('demo_module')
 
460
            self.assertEqual(1, len(topics))
 
461
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
 
462
            self.assertEqual(demo_module, topics[0].module)
 
463
        finally:
 
464
            del sys.modules['bzrlib.plugins.demo_module']
 
465
 
 
466
    def test_get_topics_no_topic(self):
 
467
        """Searching for something that is not a plugin returns []."""
 
468
        # test this by using a name that cannot be a plugin - its not
 
469
        # a valid python identifier.
 
470
        index = plugin.PluginsHelpIndex()
 
471
        self.assertEqual([], index.get_topics('nothing by this name'))
 
472
 
 
473
    def test_prefix(self):
 
474
        """PluginsHelpIndex has a prefix of 'plugins/'."""
 
475
        index = plugin.PluginsHelpIndex()
 
476
        self.assertEqual('plugins/', index.prefix)
 
477
 
 
478
    def test_get_plugin_topic_with_prefix(self):
 
479
        """Searching for plugins/demo_module returns help."""
 
480
        index = plugin.PluginsHelpIndex()
 
481
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
 
482
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
 
483
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
484
        try:
 
485
            topics = index.get_topics('plugins/demo_module')
 
486
            self.assertEqual(1, len(topics))
 
487
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
 
488
            self.assertEqual(demo_module, topics[0].module)
 
489
        finally:
 
490
            del sys.modules['bzrlib.plugins.demo_module']
 
491
 
 
492
 
 
493
class FakeModule(object):
 
494
    """A fake module to test with."""
 
495
 
 
496
    def __init__(self, doc, name):
 
497
        self.__doc__ = doc
 
498
        self.__name__ = name
 
499
 
 
500
 
 
501
class TestModuleHelpTopic(tests.TestCase):
 
502
    """Tests for the ModuleHelpTopic class."""
 
503
 
 
504
    def test_contruct(self):
 
505
        """Construction takes the module to document."""
 
506
        mod = FakeModule('foo', 'foo')
 
507
        topic = plugin.ModuleHelpTopic(mod)
 
508
        self.assertEqual(mod, topic.module)
 
509
 
 
510
    def test_get_help_text_None(self):
 
511
        """A ModuleHelpTopic returns the docstring for get_help_text."""
 
512
        mod = FakeModule(None, 'demo')
 
513
        topic = plugin.ModuleHelpTopic(mod)
 
514
        self.assertEqual("Plugin 'demo' has no docstring.\n",
 
515
            topic.get_help_text())
 
516
 
 
517
    def test_get_help_text_no_carriage_return(self):
 
518
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
 
519
        mod = FakeModule('one line of help', 'demo')
 
520
        topic = plugin.ModuleHelpTopic(mod)
 
521
        self.assertEqual("one line of help\n",
 
522
            topic.get_help_text())
 
523
 
 
524
    def test_get_help_text_carriage_return(self):
 
525
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
 
526
        mod = FakeModule('two lines of help\nand more\n', 'demo')
 
527
        topic = plugin.ModuleHelpTopic(mod)
 
528
        self.assertEqual("two lines of help\nand more\n",
 
529
            topic.get_help_text())
 
530
 
 
531
    def test_get_help_text_with_additional_see_also(self):
 
532
        mod = FakeModule('two lines of help\nand more', 'demo')
 
533
        topic = plugin.ModuleHelpTopic(mod)
 
534
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
 
535
            topic.get_help_text(['foo', 'bar']))
 
536
 
 
537
    def test_get_help_topic(self):
 
538
        """The help topic for a plugin is its module name."""
 
539
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
 
540
        topic = plugin.ModuleHelpTopic(mod)
 
541
        self.assertEqual('demo', topic.get_help_topic())
 
542
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
 
543
        topic = plugin.ModuleHelpTopic(mod)
 
544
        self.assertEqual('foo_bar', topic.get_help_topic())