/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5086.1.2 by Vincent Ladeuil
Cosmetic changes.
1
# Copyright (C) 2005-2010 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
750 by Martin Pool
- stubbed-out tests for python plugins
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
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
23
from cStringIO import StringIO
2967.4.5 by Daniel Watkins
Added test for badly-named plugins.
24
import logging
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
25
import os
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
26
import sys
750 by Martin Pool
- stubbed-out tests for python plugins
27
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
28
import bzrlib
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
29
from bzrlib import (
5268.5.1 by Vincent Ladeuil
Reproduce bug #591215.
30
    errors,
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
31
    osutils,
32
    plugin,
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
33
    plugins,
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
34
    tests,
5086.1.8 by Vincent Ladeuil
Fix warnings during autoload, add doc and a NEWS entry.
35
    trace,
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
36
    )
1141 by Martin Pool
- rename FunctionalTest to TestCaseInTempDir
37
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
38
1492 by Robert Collins
Support decoration of commands.
39
# 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
40
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
41
class TestPluginMixin(object):
42
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
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)
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
48
        if file_name is None:
49
            file_name = name + '.py'
50
        # 'source' must not fail to load
5086.1.7 by Vincent Ladeuil
Cleaner fix for bug #411413.
51
        path = osutils.pathjoin(dir, file_name)
52
        f = open(path, 'w')
53
        self.addCleanup(os.unlink, path)
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
54
        try:
55
            f.write(source + '\n')
56
        finally:
57
            f.close()
58
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
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)
5086.5.9 by Vincent Ladeuil
More tests.
68
        def cleanup():
69
            # Workaround lazy import random? madness
70
            osutils.rmtree(dir)
71
        self.addCleanup(cleanup)
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
72
        self.create_plugin(name, source, dir,
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
73
                           file_name='__init__.py')
74
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
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 assertPluginUnknown(self, name):
5086.1.9 by Vincent Ladeuil
Fix bogus helpers and add a test.
84
        self.failIf(getattr(bzrlib.plugins, name, None) is not None)
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
85
        self.failIf('bzrlib.plugins.%s' % name in sys.modules)
86
87
    def assertPluginKnown(self, name):
5086.1.9 by Vincent Ladeuil
Fix bogus helpers and add a test.
88
        self.failUnless(getattr(bzrlib.plugins, name, None) is not None)
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
89
        self.failUnless('bzrlib.plugins.%s' % name in sys.modules)
90
91
92
class TestLoadingPlugins(tests.TestCaseInTempDir, TestPluginMixin):
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
93
94
    activeattributes = {}
95
96
    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
97
        # This test tests that having two plugins in different directories does
98
        # not result in both being loaded when they have the same name.  get a
99
        # file name we can use which is also a valid attribute for accessing in
100
        # activeattributes. - we cannot give import parameters.
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
101
        tempattribute = "0"
102
        self.failIf(tempattribute in self.activeattributes)
103
        # set a place for the plugins to record their loading, and at the same
104
        # time validate that the location the plugins should record to is
105
        # valid and correct.
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
106
        self.__class__.activeattributes [tempattribute] = []
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
107
        self.failUnless(tempattribute in self.activeattributes)
108
        # create two plugin directories
109
        os.mkdir('first')
110
        os.mkdir('second')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
111
        # write a plugin that will record when its loaded in the
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
112
        # tempattribute list.
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
113
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
114
                    "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.
115
116
        outfile = open(os.path.join('first', 'plugin.py'), 'w')
117
        try:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
118
            outfile.write(template % (tempattribute, 'first'))
119
            outfile.write('\n')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
120
        finally:
121
            outfile.close()
122
123
        outfile = open(os.path.join('second', 'plugin.py'), 'w')
124
        try:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
125
            outfile.write(template % (tempattribute, 'second'))
126
            outfile.write('\n')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
127
        finally:
128
            outfile.close()
129
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
130
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
131
            bzrlib.plugin.load_from_path(['first', 'second'])
132
            self.assertEqual(['first'], self.activeattributes[tempattribute])
133
        finally:
134
            # remove the plugin 'plugin'
135
            del self.activeattributes[tempattribute]
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
136
            self._unregister_plugin('plugin')
137
        self.assertPluginUnknown('plugin')
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
138
139
    def test_plugins_from_different_dirs_can_demand_load(self):
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
140
        self.failIf('bzrlib.plugins.pluginone' in sys.modules)
141
        self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
142
        # This test tests that having two plugins in different
143
        # directories with different names allows them both to be loaded, when
144
        # we do a direct import statement.
145
        # Determine a file name we can use which is also a valid attribute
146
        # for accessing in activeattributes. - we cannot give import parameters.
147
        tempattribute = "different-dirs"
148
        self.failIf(tempattribute in self.activeattributes)
149
        # set a place for the plugins to record their loading, and at the same
150
        # time validate that the location the plugins should record to is
151
        # valid and correct.
152
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
153
            [tempattribute] = []
154
        self.failUnless(tempattribute in self.activeattributes)
155
        # create two plugin directories
156
        os.mkdir('first')
157
        os.mkdir('second')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
158
        # write plugins that will record when they are loaded in the
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
159
        # tempattribute list.
160
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
161
                    "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.
162
163
        outfile = open(os.path.join('first', 'pluginone.py'), 'w')
164
        try:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
165
            outfile.write(template % (tempattribute, 'first'))
166
            outfile.write('\n')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
167
        finally:
168
            outfile.close()
169
170
        outfile = open(os.path.join('second', 'plugintwo.py'), 'w')
171
        try:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
172
            outfile.write(template % (tempattribute, 'second'))
173
            outfile.write('\n')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
174
        finally:
175
            outfile.close()
176
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
177
        oldpath = bzrlib.plugins.__path__
178
        try:
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
179
            self.failIf('bzrlib.plugins.pluginone' in sys.modules)
180
            self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
181
            bzrlib.plugins.__path__ = ['first', 'second']
182
            exec "import bzrlib.plugins.pluginone"
183
            self.assertEqual(['first'], self.activeattributes[tempattribute])
184
            exec "import bzrlib.plugins.plugintwo"
185
            self.assertEqual(['first', 'second'],
186
                self.activeattributes[tempattribute])
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
187
        finally:
188
            # remove the plugin 'plugin'
189
            del self.activeattributes[tempattribute]
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
190
            self._unregister_plugin('pluginone')
191
            self._unregister_plugin('plugintwo')
192
        self.assertPluginUnknown('pluginone')
193
        self.assertPluginUnknown('plugintwo')
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
194
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.
195
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
196
        # This test tests that a plugin can load from a directory when the
197
        # 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.
198
        # check the plugin is not loaded already
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
199
        self.assertPluginUnknown('ts_plugin')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
200
        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.
201
        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.
202
        # set a place for the plugin to record its loading, and at the same
203
        # 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.
204
        # valid and correct.
205
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
206
            [tempattribute] = []
207
        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.
208
        # create a directory for the plugin
209
        os.mkdir('plugin_test')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
210
        # write a plugin that will record when its loaded in the
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.
211
        # tempattribute list.
212
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
213
                    "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.
214
215
        outfile = open(os.path.join('plugin_test', 'ts_plugin.py'), 'w')
216
        try:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
217
            outfile.write(template % (tempattribute, 'plugin'))
2911.6.4 by Blake Winton
Fix test failures
218
            outfile.write('\n')
2652.2.7 by Blake Winton
fix lines which were wider than 79 chars. Also handle files a little more safely.
219
        finally:
220
            outfile.close()
221
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.
222
        try:
2652.2.3 by Blake Winton
Understand the code and comments of the test, instead of just cargo-culting them.
223
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
224
            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.
225
        finally:
226
            del self.activeattributes[tempattribute]
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
227
            self._unregister_plugin('ts_plugin')
228
        self.assertPluginUnknown('ts_plugin')
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.
229
3766.3.2 by Robert Collins
Fix reporting of incompatible api plugin load errors, fixing bug 279451.
230
    def load_and_capture(self, name):
231
        """Load plugins from '.' capturing the output.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
232
3766.3.2 by Robert Collins
Fix reporting of incompatible api plugin load errors, fixing bug 279451.
233
        :param name: The name of the plugin.
234
        :return: A string with the log from the plugin loading call.
235
        """
2967.4.5 by Daniel Watkins
Added test for badly-named plugins.
236
        # Capture output
237
        stream = StringIO()
3766.3.2 by Robert Collins
Fix reporting of incompatible api plugin load errors, fixing bug 279451.
238
        try:
239
            handler = logging.StreamHandler(stream)
240
            log = logging.getLogger('bzr')
241
            log.addHandler(handler)
242
            try:
243
                try:
244
                    bzrlib.plugin.load_from_path(['.'])
245
                finally:
246
                    if 'bzrlib.plugins.%s' % name in sys.modules:
247
                        del sys.modules['bzrlib.plugins.%s' % name]
248
                    if getattr(bzrlib.plugins, name, None):
249
                        delattr(bzrlib.plugins, name)
250
            finally:
251
                # Stop capturing output
252
                handler.flush()
253
                handler.close()
254
                log.removeHandler(handler)
255
            return stream.getvalue()
256
        finally:
257
            stream.close()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
258
3766.3.2 by Robert Collins
Fix reporting of incompatible api plugin load errors, fixing bug 279451.
259
    def test_plugin_with_bad_api_version_reports(self):
260
        # This plugin asks for bzrlib api version 1.0.0, which is not supported
261
        # anymore.
262
        name = 'wants100.py'
263
        f = file(name, 'w')
264
        try:
265
            f.write("import bzrlib.api\n"
266
                "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n")
267
        finally:
268
            f.close()
269
270
        log = self.load_and_capture(name)
271
        self.assertContainsRe(log,
272
            r"It requested API version")
273
274
    def test_plugin_with_bad_name_does_not_load(self):
275
        # The file name here invalid for a python module.
276
        name = 'bzr-bad plugin-name..py'
277
        file(name, 'w').close()
278
        log = self.load_and_capture(name)
279
        self.assertContainsRe(log,
3290.1.1 by James Westby
Strip "bzr_" from the start of the suggested plugin name.
280
            r"Unable to load 'bzr-bad plugin-name\.' in '\.' as a plugin "
281
            "because the file path isn't a valid module name; try renaming "
282
            "it to 'bad_plugin_name_'\.")
2967.4.5 by Daniel Watkins
Added test for badly-named plugins.
283
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
284
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
285
class TestPlugins(tests.TestCaseInTempDir, TestPluginMixin):
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
286
287
    def setup_plugin(self, source=""):
288
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
289
        # check the plugin is not loaded already
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
290
        self.assertPluginUnknown('plugin')
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
291
        # write a plugin that _cannot_ fail to load.
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
292
        file('plugin.py', 'w').write(source + '\n')
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
293
        self.addCleanup(self.teardown_plugin)
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
294
        plugin.load_from_path(['.'])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
295
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
296
    def teardown_plugin(self):
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
297
        self._unregister_plugin('plugin')
298
        self.assertPluginUnknown('plugin')
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
299
300
    def test_plugin_appears_in_plugins(self):
301
        self.setup_plugin()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
302
        self.assertPluginKnown('plugin')
303
        p = plugin.plugins()['plugin']
304
        self.assertIsInstance(p, bzrlib.plugin.PlugIn)
305
        self.assertEqual(p.module, plugins.plugin)
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
306
307
    def test_trivial_plugin_get_path(self):
308
        self.setup_plugin()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
309
        p = plugin.plugins()['plugin']
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
310
        plugin_path = self.test_dir + '/plugin.py'
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
311
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
312
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
313
    def test_plugin_get_path_py_not_pyc(self):
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
314
        # first import creates plugin.pyc
315
        self.setup_plugin()
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
316
        self.teardown_plugin()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
317
        plugin.load_from_path(['.']) # import plugin.pyc
318
        p = plugin.plugins()['plugin']
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
319
        plugin_path = self.test_dir + '/plugin.py'
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
320
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
321
322
    def test_plugin_get_path_pyc_only(self):
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
323
        # first import creates plugin.pyc (or plugin.pyo depending on __debug__)
324
        self.setup_plugin()
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
325
        self.teardown_plugin()
326
        os.unlink(self.test_dir + '/plugin.py')
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
327
        plugin.load_from_path(['.']) # import plugin.pyc (or .pyo)
328
        p = plugin.plugins()['plugin']
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
329
        if __debug__:
330
            plugin_path = self.test_dir + '/plugin.pyc'
331
        else:
332
            plugin_path = self.test_dir + '/plugin.pyo'
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
333
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
3193.2.1 by Alexander Belchenko
show path to plugin module as *.py instead of *.pyc if python source available
334
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
335
    def test_no_test_suite_gives_None_for_test_suite(self):
336
        self.setup_plugin()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
337
        p = plugin.plugins()['plugin']
338
        self.assertEqual(None, p.test_suite())
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
339
340
    def test_test_suite_gives_test_suite_result(self):
341
        source = """def test_suite(): return 'foo'"""
342
        self.setup_plugin(source)
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
343
        p = plugin.plugins()['plugin']
344
        self.assertEqual('foo', p.test_suite())
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
345
3302.8.21 by Vincent Ladeuil
Fixed as per Robert's review.
346
    def test_no_load_plugin_tests_gives_None_for_load_plugin_tests(self):
3302.8.10 by Vincent Ladeuil
Prepare bzrlib.plugin to use the new test loader.
347
        self.setup_plugin()
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
348
        loader = tests.TestUtil.TestLoader()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
349
        p = plugin.plugins()['plugin']
350
        self.assertEqual(None, p.load_plugin_tests(loader))
3302.8.10 by Vincent Ladeuil
Prepare bzrlib.plugin to use the new test loader.
351
3302.8.21 by Vincent Ladeuil
Fixed as per Robert's review.
352
    def test_load_plugin_tests_gives_load_plugin_tests_result(self):
3302.8.10 by Vincent Ladeuil
Prepare bzrlib.plugin to use the new test loader.
353
        source = """
354
def load_tests(standard_tests, module, loader):
355
    return 'foo'"""
356
        self.setup_plugin(source)
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
357
        loader = tests.TestUtil.TestLoader()
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
358
        p = plugin.plugins()['plugin']
359
        self.assertEqual('foo', p.load_plugin_tests(loader))
360
361
    def check_version_info(self, expected, source='', name='plugin'):
362
        self.setup_plugin(source)
363
        self.assertEqual(expected, plugin.plugins()[name].version_info())
3302.8.10 by Vincent Ladeuil
Prepare bzrlib.plugin to use the new test loader.
364
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
365
    def test_no_version_info(self):
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
366
        self.check_version_info(None)
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
367
368
    def test_with_version_info(self):
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
369
        self.check_version_info((1, 2, 3, 'dev', 4),
370
                                "version_info = (1, 2, 3, 'dev', 4)")
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
371
372
    def test_short_version_info_gets_padded(self):
373
        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
374
        # so we adapt it
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
375
        self.check_version_info((1, 2, 3, 'final', 0),
376
                                "version_info = (1, 2, 3)")
377
378
    def check_version(self, expected, source=None, name='plugin'):
379
        self.setup_plugin(source)
380
        self.assertEqual(expected, plugins[name].__version__)
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
381
382
    def test_no_version_info___version__(self):
383
        self.setup_plugin()
384
        plugin = bzrlib.plugin.plugins()['plugin']
385
        self.assertEqual("unknown", plugin.__version__)
386
3777.6.7 by Marius Kruger
* Can now also handle non-iteratable and string plugin versions.
387
    def test_str__version__with_version_info(self):
388
        self.setup_plugin("version_info = '1.2.3'")
389
        plugin = bzrlib.plugin.plugins()['plugin']
390
        self.assertEqual("1.2.3", plugin.__version__)
391
392
    def test_noniterable__version__with_version_info(self):
393
        self.setup_plugin("version_info = (1)")
394
        plugin = bzrlib.plugin.plugins()['plugin']
395
        self.assertEqual("1", plugin.__version__)
396
397
    def test_1__version__with_version_info(self):
398
        self.setup_plugin("version_info = (1,)")
399
        plugin = bzrlib.plugin.plugins()['plugin']
400
        self.assertEqual("1", plugin.__version__)
401
402
    def test_1_2__version__with_version_info(self):
3777.6.5 by Marius Kruger
add 2 more tests for plugin version numbers
403
        self.setup_plugin("version_info = (1, 2)")
404
        plugin = bzrlib.plugin.plugins()['plugin']
405
        self.assertEqual("1.2", plugin.__version__)
406
3777.6.7 by Marius Kruger
* Can now also handle non-iteratable and string plugin versions.
407
    def test_1_2_3__version__with_version_info(self):
3777.6.5 by Marius Kruger
add 2 more tests for plugin version numbers
408
        self.setup_plugin("version_info = (1, 2, 3)")
409
        plugin = bzrlib.plugin.plugins()['plugin']
410
        self.assertEqual("1.2.3", plugin.__version__)
411
412
    def test_candidate__version__with_version_info(self):
3777.6.4 by Marius Kruger
fix tests
413
        self.setup_plugin("version_info = (1, 2, 3, 'candidate', 1)")
414
        plugin = bzrlib.plugin.plugins()['plugin']
415
        self.assertEqual("1.2.3rc1", plugin.__version__)
416
417
    def test_dev__version__with_version_info(self):
418
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 0)")
419
        plugin = bzrlib.plugin.plugins()['plugin']
420
        self.assertEqual("1.2.3dev", plugin.__version__)
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
421
3777.6.7 by Marius Kruger
* Can now also handle non-iteratable and string plugin versions.
422
    def test_dev_fallback__version__with_version_info(self):
423
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
424
        plugin = bzrlib.plugin.plugins()['plugin']
4634.50.6 by John Arbash Meinel
Handle a plugin fallback versioning issue.
425
        self.assertEqual("1.2.3dev4", plugin.__version__)
3777.6.7 by Marius Kruger
* Can now also handle non-iteratable and string plugin versions.
426
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
427
    def test_final__version__with_version_info(self):
3777.6.4 by Marius Kruger
fix tests
428
        self.setup_plugin("version_info = (1, 2, 3, 'final', 0)")
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
429
        plugin = bzrlib.plugin.plugins()['plugin']
430
        self.assertEqual("1.2.3", plugin.__version__)
431
4634.50.6 by John Arbash Meinel
Handle a plugin fallback versioning issue.
432
    def test_final_fallback__version__with_version_info(self):
433
        self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
434
        plugin = bzrlib.plugin.plugins()['plugin']
435
        self.assertEqual("1.2.3.final.2", plugin.__version__)
436
2762.2.1 by Robert Collins
* ``bzr plugins`` now lists the version number for each plugin in square
437
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
438
class TestPluginHelp(tests.TestCaseInTempDir):
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
439
440
    def split_help_commands(self):
441
        help = {}
442
        current = None
3908.1.1 by Andrew Bennetts
Try harder to avoid loading plugins during the test suite.
443
        out, err = self.run_bzr('--no-plugins help commands')
444
        for line in out.splitlines():
2034.1.2 by Aaron Bentley
Fix testcase
445
            if not line.startswith(' '):
446
                current = line.split()[0]
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
447
            help[current] = help.get(current, '') + line
448
449
        return help
450
451
    def test_plugin_help_builtins_unaffected(self):
452
        # Check we don't get false positives
453
        help_commands = self.split_help_commands()
454
        for cmd_name in bzrlib.commands.builtin_command_names():
455
            if cmd_name in bzrlib.commands.plugin_command_names():
456
                continue
457
            try:
2432.1.12 by Robert Collins
Relocate command help onto Command.
458
                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.
459
            except NotImplementedError:
460
                # some commands have no help
461
                pass
462
            else:
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
463
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
464
2432.1.12 by Robert Collins
Relocate command help onto Command.
465
            if cmd_name in help_commands.keys():
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
466
                # some commands are hidden
467
                help = help_commands[cmd_name]
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
468
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
469
470
    def test_plugin_help_shows_plugin(self):
471
        # Create a test plugin
472
        os.mkdir('plugin_test')
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
473
        f = open(osutils.pathjoin('plugin_test', 'myplug.py'), 'w')
5086.1.2 by Vincent Ladeuil
Cosmetic changes.
474
        f.write("""\
5086.1.3 by Vincent Ladeuil
Fix imports in test_plugins.
475
from bzrlib import commands
476
class cmd_myplug(commands.Command):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
477
    __doc__ = '''Just a simple test plugin.'''
5086.1.2 by Vincent Ladeuil
Cosmetic changes.
478
    aliases = ['mplg']
479
    def run(self):
480
        print 'Hello from my plugin'
481
482
"""
483
)
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
484
        f.close()
485
486
        try:
487
            # Check its help
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
488
            bzrlib.plugin.load_from_path(['plugin_test'])
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
489
            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
490
            help = self.run_bzr('help myplug')[0]
2666.1.1 by Ian Clatworthy
Bazaar User Reference generated from online help
491
            self.assertContainsRe(help, 'plugin "myplug"')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
492
            help = self.split_help_commands()['myplug']
2034.1.4 by Aaron Bentley
Change angle brackets to square brackets
493
            self.assertContainsRe(help, '\[myplug\]')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
494
        finally:
2204.3.2 by Alexander Belchenko
cherrypicking: test_plugin_help_shows_plugin: fix cleanup after test
495
            # unregister command
3785.1.1 by Aaron Bentley
Switch from dict to Registry for plugin_cmds
496
            if 'myplug' in bzrlib.commands.plugin_cmds:
497
                bzrlib.commands.plugin_cmds.remove('myplug')
2204.3.2 by Alexander Belchenko
cherrypicking: test_plugin_help_shows_plugin: fix cleanup after test
498
            # remove the plugin 'myplug'
499
            if getattr(bzrlib.plugins, 'myplug', None):
500
                delattr(bzrlib.plugins, 'myplug')
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
501
502
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
503
class TestHelpIndex(tests.TestCase):
504
    """Tests for the PluginsHelpIndex class."""
505
506
    def test_default_constructable(self):
507
        index = plugin.PluginsHelpIndex()
508
509
    def test_get_topics_None(self):
510
        """Searching for None returns an empty list."""
511
        index = plugin.PluginsHelpIndex()
512
        self.assertEqual([], index.get_topics(None))
513
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
514
    def test_get_topics_for_plugin(self):
515
        """Searching for plugin name gets its docstring."""
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
516
        index = plugin.PluginsHelpIndex()
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
517
        # make a new plugin here for this test, even if we're run with
518
        # --no-plugins
519
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
520
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
521
        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)
522
        try:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
523
            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)
524
            self.assertEqual(1, len(topics))
525
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
526
            self.assertEqual(demo_module, topics[0].module)
527
        finally:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
528
            del sys.modules['bzrlib.plugins.demo_module']
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
529
530
    def test_get_topics_no_topic(self):
531
        """Searching for something that is not a plugin returns []."""
532
        # test this by using a name that cannot be a plugin - its not
533
        # a valid python identifier.
534
        index = plugin.PluginsHelpIndex()
535
        self.assertEqual([], index.get_topics('nothing by this name'))
536
537
    def test_prefix(self):
538
        """PluginsHelpIndex has a prefix of 'plugins/'."""
539
        index = plugin.PluginsHelpIndex()
540
        self.assertEqual('plugins/', index.prefix)
541
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
542
    def test_get_plugin_topic_with_prefix(self):
543
        """Searching for plugins/demo_module returns help."""
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
544
        index = plugin.PluginsHelpIndex()
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
545
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
546
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
547
        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)
548
        try:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
549
            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)
550
            self.assertEqual(1, len(topics))
551
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
552
            self.assertEqual(demo_module, topics[0].module)
553
        finally:
2475.1.1 by Martin Pool
Rename test_plugin tests and the example module used there.
554
            del sys.modules['bzrlib.plugins.demo_module']
2432.1.25 by Robert Collins
Return plugin module docstrings for 'bzr help plugin'.
555
556
557
class FakeModule(object):
558
    """A fake module to test with."""
559
560
    def __init__(self, doc, name):
561
        self.__doc__ = doc
562
        self.__name__ = name
563
564
565
class TestModuleHelpTopic(tests.TestCase):
566
    """Tests for the ModuleHelpTopic class."""
567
568
    def test_contruct(self):
569
        """Construction takes the module to document."""
570
        mod = FakeModule('foo', 'foo')
571
        topic = plugin.ModuleHelpTopic(mod)
572
        self.assertEqual(mod, topic.module)
573
574
    def test_get_help_text_None(self):
575
        """A ModuleHelpTopic returns the docstring for get_help_text."""
576
        mod = FakeModule(None, 'demo')
577
        topic = plugin.ModuleHelpTopic(mod)
578
        self.assertEqual("Plugin 'demo' has no docstring.\n",
579
            topic.get_help_text())
580
581
    def test_get_help_text_no_carriage_return(self):
582
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
583
        mod = FakeModule('one line of help', 'demo')
584
        topic = plugin.ModuleHelpTopic(mod)
585
        self.assertEqual("one line of help\n",
586
            topic.get_help_text())
587
588
    def test_get_help_text_carriage_return(self):
589
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
590
        mod = FakeModule('two lines of help\nand more\n', 'demo')
591
        topic = plugin.ModuleHelpTopic(mod)
592
        self.assertEqual("two lines of help\nand more\n",
593
            topic.get_help_text())
594
595
    def test_get_help_text_with_additional_see_also(self):
596
        mod = FakeModule('two lines of help\nand more', 'demo')
597
        topic = plugin.ModuleHelpTopic(mod)
598
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
599
            topic.get_help_text(['foo', 'bar']))
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
600
601
    def test_get_help_topic(self):
602
        """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.
603
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
604
        topic = plugin.ModuleHelpTopic(mod)
605
        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.
606
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
2432.1.29 by Robert Collins
Add get_help_topic to ModuleHelpTopic.
607
        topic = plugin.ModuleHelpTopic(mod)
608
        self.assertEqual('foo_bar', topic.get_help_topic())
3835.2.7 by Aaron Bentley
Add tests for plugins
609
610
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
611
class TestLoadFromPath(tests.TestCaseInTempDir):
612
613
    def setUp(self):
614
        super(TestLoadFromPath, self).setUp()
615
        # Change bzrlib.plugin to think no plugins have been loaded yet.
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
616
        self.overrideAttr(bzrlib.plugins, '__path__', [])
617
        self.overrideAttr(plugin, '_loaded', False)
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
618
619
        # Monkey-patch load_from_path to stop it from actually loading anything.
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
620
        self.overrideAttr(plugin, 'load_from_path', lambda dirs: None)
3835.2.7 by Aaron Bentley
Add tests for plugins
621
622
    def test_set_plugins_path_with_args(self):
623
        plugin.set_plugins_path(['a', 'b'])
624
        self.assertEqual(['a', 'b'], bzrlib.plugins.__path__)
625
626
    def test_set_plugins_path_defaults(self):
627
        plugin.set_plugins_path()
628
        self.assertEqual(plugin.get_standard_plugins_path(),
629
                         bzrlib.plugins.__path__)
630
631
    def test_get_standard_plugins_path(self):
632
        path = plugin.get_standard_plugins_path()
633
        for directory in path:
4412.2.1 by Vincent Ladeuil
Fix some OSX test regressions (well actual test bugs indeed).
634
            self.assertNotContainsRe(directory, r'\\/$')
3835.2.7 by Aaron Bentley
Add tests for plugins
635
        try:
636
            from distutils.sysconfig import get_python_lib
637
        except ImportError:
638
            pass
639
        else:
640
            if sys.platform != 'win32':
641
                python_lib = get_python_lib()
642
                for directory in path:
643
                    if directory.startswith(python_lib):
644
                        break
645
                else:
646
                    self.fail('No path to global plugins')
647
648
    def test_get_standard_plugins_path_env(self):
649
        os.environ['BZR_PLUGIN_PATH'] = 'foo/'
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
650
        path = plugin.get_standard_plugins_path()
651
        for directory in path:
652
            self.assertNotContainsRe(directory, r'\\/$')
3835.2.7 by Aaron Bentley
Add tests for plugins
653
654
    def test_load_plugins(self):
655
        plugin.load_plugins(['.'])
656
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
657
        # subsequent loads are no-ops
658
        plugin.load_plugins(['foo'])
659
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
660
661
    def test_load_plugins_default(self):
662
        plugin.load_plugins()
663
        path = plugin.get_standard_plugins_path()
664
        self.assertEqual(path, bzrlib.plugins.__path__)
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
665
666
5086.1.2 by Vincent Ladeuil
Cosmetic changes.
667
class TestEnvPluginPath(tests.TestCase):
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
668
669
    def setUp(self):
670
        super(TestEnvPluginPath, self).setUp()
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
671
        self.overrideAttr(plugin, 'DEFAULT_PLUGIN_PATH', None)
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
672
673
        self.user = plugin.get_user_plugin_path()
674
        self.site = plugin.get_site_plugin_path()
675
        self.core = plugin.get_core_plugin_path()
676
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
677
    def _list2paths(self, *args):
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
678
        paths = []
679
        for p in args:
680
            plugin._append_new_path(paths, p)
681
        return paths
682
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
683
    def _set_path(self, *args):
684
        path = os.pathsep.join(self._list2paths(*args))
685
        osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
686
687
    def check_path(self, expected_dirs, setting_dirs):
688
        if setting_dirs:
689
            self._set_path(*setting_dirs)
690
        actual = plugin.get_standard_plugins_path()
691
        self.assertEquals(self._list2paths(*expected_dirs), actual)
692
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
693
    def test_default(self):
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
694
        self.check_path([self.user, self.core, self.site],
695
                        None)
696
697
    def test_adhoc_policy(self):
698
        self.check_path([self.user, self.core, self.site],
699
                        ['+user', '+core', '+site'])
700
701
    def test_fallback_policy(self):
702
        self.check_path([self.core, self.site, self.user],
703
                        ['+core', '+site', '+user'])
704
705
    def test_override_policy(self):
706
        self.check_path([self.user, self.site, self.core],
707
                        ['+user', '+site', '+core'])
708
709
    def test_disable_user(self):
710
        self.check_path([self.core, self.site], ['-user'])
711
712
    def test_disable_user_twice(self):
713
        # Ensures multiple removals don't left cruft
714
        self.check_path([self.core, self.site], ['-user', '-user'])
715
4628.2.5 by Vincent Ladeuil
Fixes prompted by review.
716
    def test_duplicates_are_removed(self):
717
        self.check_path([self.user, self.core, self.site],
718
                        ['+user', '+user'])
719
        # And only the first reference is kept (since the later references will
5086.1.2 by Vincent Ladeuil
Cosmetic changes.
720
        # only produce '<plugin> already loaded' mutters)
4628.2.5 by Vincent Ladeuil
Fixes prompted by review.
721
        self.check_path([self.user, self.core, self.site],
722
                        ['+user', '+user', '+core',
723
                         '+user', '+site', '+site',
724
                         '+core'])
725
5086.1.5 by Vincent Ladeuil
Fix typo in test name.
726
    def test_disable_overrides_enable(self):
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
727
        self.check_path([self.core, self.site], ['-user', '+user'])
728
729
    def test_disable_core(self):
4628.2.3 by Vincent Ladeuil
Update doc and add NEWS entry.
730
        self.check_path([self.site], ['-core'])
731
        self.check_path([self.user, self.site], ['+user', '-core'])
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
732
733
    def test_disable_site(self):
4628.2.3 by Vincent Ladeuil
Update doc and add NEWS entry.
734
        self.check_path([self.core], ['-site'])
735
        self.check_path([self.user, self.core], ['-site', '+user'])
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
736
737
    def test_override_site(self):
4628.2.3 by Vincent Ladeuil
Update doc and add NEWS entry.
738
        self.check_path(['mysite', self.user, self.core],
739
                        ['mysite', '-site', '+user'])
740
        self.check_path(['mysite', self.core],
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
741
                        ['mysite', '-site'])
742
743
    def test_override_core(self):
4628.2.3 by Vincent Ladeuil
Update doc and add NEWS entry.
744
        self.check_path(['mycore', self.user, self.site],
745
                        ['mycore', '-core', '+user', '+site'])
746
        self.check_path(['mycore', self.site],
4628.2.2 by Vincent Ladeuil
Add [+-]{user|core|site} handling in BZR_PLUGIN_PATH.
747
                        ['mycore', '-core'])
748
749
    def test_my_plugin_only(self):
750
        self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
751
752
    def test_my_plugin_first(self):
753
        self.check_path(['myplugin', self.core, self.site, self.user],
754
                        ['myplugin', '+core', '+site', '+user'])
4628.2.1 by Vincent Ladeuil
Start introducing accessors for plugin paths.
755
4628.2.5 by Vincent Ladeuil
Fixes prompted by review.
756
    def test_bogus_references(self):
757
        self.check_path(['+foo', '-bar', self.core, self.site],
758
                        ['+foo', '-bar'])
5086.1.4 by Vincent Ladeuil
Slight plugin tests rewriting.
759
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
760
761
class TestDisablePlugin(tests.TestCaseInTempDir, TestPluginMixin):
762
5086.1.7 by Vincent Ladeuil
Cleaner fix for bug #411413.
763
    def setUp(self):
764
        super(TestDisablePlugin, self).setUp()
765
        self.create_plugin_package('test_foo')
766
        # Make sure we don't pollute the plugins namespace
767
        self.overrideAttr(plugins, '__path__')
768
        # Be paranoid in case a test fail
769
        self.addCleanup(self._unregister_plugin, 'test_foo')
5086.1.8 by Vincent Ladeuil
Fix warnings during autoload, add doc and a NEWS entry.
770
771
    def test_cannot_import(self):
5086.1.10 by Vincent Ladeuil
Fixed as per review comments.
772
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
773
        plugin.set_plugins_path(['.'])
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
774
        try:
775
            import bzrlib.plugins.test_foo
776
        except ImportError:
777
            pass
5086.1.7 by Vincent Ladeuil
Cleaner fix for bug #411413.
778
        self.assertPluginUnknown('test_foo')
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
779
5086.1.9 by Vincent Ladeuil
Fix bogus helpers and add a test.
780
    def test_regular_load(self):
781
        self.overrideAttr(plugin, '_loaded', False)
782
        plugin.load_plugins(['.'])
783
        self.assertPluginKnown('test_foo')
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
784
        self.assertDocstring("This is the doc for test_foo",
785
                             bzrlib.plugins.test_foo)
5086.1.9 by Vincent Ladeuil
Fix bogus helpers and add a test.
786
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
787
    def test_not_loaded(self):
5086.1.8 by Vincent Ladeuil
Fix warnings during autoload, add doc and a NEWS entry.
788
        self.warnings = []
789
        def captured_warning(*args, **kwargs):
790
            self.warnings.append((args, kwargs))
791
        self.overrideAttr(trace, 'warning', captured_warning)
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
792
        # Reset the flag that protect against double loading
5086.1.8 by Vincent Ladeuil
Fix warnings during autoload, add doc and a NEWS entry.
793
        self.overrideAttr(plugin, '_loaded', False)
5086.1.10 by Vincent Ladeuil
Fixed as per review comments.
794
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
5086.5.4 by Vincent Ladeuil
Merge for fixes from 411413-plugin-path
795
        plugin.load_plugins(['.'])
5086.1.6 by Vincent Ladeuil
Crude fix for bug #411413.
796
        self.assertPluginUnknown('test_foo')
5086.1.8 by Vincent Ladeuil
Fix warnings during autoload, add doc and a NEWS entry.
797
        # Make sure we don't warn about the plugin ImportError since this has
798
        # been *requested* by the user.
799
        self.assertLength(0, self.warnings)
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
800
801
5268.5.1 by Vincent Ladeuil
Reproduce bug #591215.
802
class TestLoadPluginAtSyntax(tests.TestCase):
803
804
    def _get_paths(self, paths):
805
        return plugin._get_specific_plugin_paths(paths)
806
807
    def test_empty(self):
808
        self.assertEquals([], self._get_paths(None))
809
        self.assertEquals([], self._get_paths(''))
810
811
    def test_one_path(self):
812
        self.assertEquals([('b', 'man')], self._get_paths('b@man'))
813
814
    def test_bogus_path(self):
5268.5.2 by Vincent Ladeuil
Catch the wrong path descriptions in BZR_PLUGINS_AT.
815
        # We need a '@'
816
        self.assertRaises(errors.BzrCommandError, self._get_paths, 'batman')
817
        # Too much '@' isn't good either
818
        self.assertRaises(errors.BzrCommandError, self._get_paths,
819
                          'batman@mobile@cave')
820
        # An empty description probably indicates a problem
821
        self.assertRaises(errors.BzrCommandError, self._get_paths,
822
                          os.pathsep.join(['batman@cave', '', 'robin@mobile']))
5268.5.1 by Vincent Ladeuil
Reproduce bug #591215.
823
824
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
825
class TestLoadPluginAt(tests.TestCaseInTempDir, TestPluginMixin):
826
827
    def setUp(self):
828
        super(TestLoadPluginAt, self).setUp()
829
        # Make sure we don't pollute the plugins namespace
830
        self.overrideAttr(plugins, '__path__')
831
        # Be paranoid in case a test fail
832
        self.addCleanup(self._unregister_plugin, 'test_foo')
833
        # Reset the flag that protect against double loading
834
        self.overrideAttr(plugin, '_loaded', False)
835
        # Create the same plugin in two directories
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
836
        self.create_plugin_package('test_foo', dir='non-standard-dir')
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
837
        # The "normal" directory, we use 'standard' instead of 'plugins' to
838
        # avoid depending on the precise naming.
839
        self.create_plugin_package('test_foo', dir='standard/test_foo')
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
840
5086.5.14 by Vincent Ladeuil
Fix bug #552922 by controlling which files can be used to load a plugin.
841
    def assertTestFooLoadedFrom(self, path):
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
842
        self.assertPluginKnown('test_foo')
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
843
        self.assertDocstring('This is the doc for test_foo',
844
                             bzrlib.plugins.test_foo)
5086.5.14 by Vincent Ladeuil
Fix bug #552922 by controlling which files can be used to load a plugin.
845
        self.assertEqual(path, bzrlib.plugins.test_foo.dir_source)
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
846
847
    def test_regular_load(self):
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
848
        plugin.load_plugins(['standard'])
849
        self.assertTestFooLoadedFrom('standard/test_foo')
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
850
851
    def test_import(self):
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
852
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
853
        plugin.set_plugins_path(['standard'])
5086.5.3 by Vincent Ladeuil
First shot at loading plugins from a specific directory.
854
        try:
855
            import bzrlib.plugins.test_foo
856
        except ImportError:
857
            pass
5086.5.8 by Vincent Ladeuil
Make sure we can load from a non-standard directory name.
858
        self.assertTestFooLoadedFrom('non-standard-dir')
859
860
    def test_loading(self):
861
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
862
        plugin.load_plugins(['standard'])
5086.5.9 by Vincent Ladeuil
More tests.
863
        self.assertTestFooLoadedFrom('non-standard-dir')
864
865
    def test_compiled_loaded(self):
866
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
867
        plugin.load_plugins(['standard'])
5086.5.9 by Vincent Ladeuil
More tests.
868
        self.assertTestFooLoadedFrom('non-standard-dir')
5235.1.1 by Martin
Make BZR_PLUGINS_AT tests that check filenames use a path-based assertion method rather than just string comparison
869
        self.assertIsSameRealPath('non-standard-dir/__init__.py',
870
                                  bzrlib.plugins.test_foo.__file__)
5086.5.9 by Vincent Ladeuil
More tests.
871
872
        # Try importing again now that the source has been compiled
873
        self._unregister_plugin('test_foo')
874
        plugin._loaded = False
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
875
        plugin.load_plugins(['standard'])
5086.5.9 by Vincent Ladeuil
More tests.
876
        self.assertTestFooLoadedFrom('non-standard-dir')
5086.5.11 by Vincent Ladeuil
Fix pqm failure.
877
        if __debug__:
878
            suffix = 'pyc'
879
        else:
880
            suffix = 'pyo'
5235.1.1 by Martin
Make BZR_PLUGINS_AT tests that check filenames use a path-based assertion method rather than just string comparison
881
        self.assertIsSameRealPath('non-standard-dir/__init__.%s' % suffix,
882
                                  bzrlib.plugins.test_foo.__file__)
5086.5.9 by Vincent Ladeuil
More tests.
883
884
    def test_submodule_loading(self):
885
        # We create an additional directory under the one for test_foo
886
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
887
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
888
        plugin.set_plugins_path(['standard'])
5086.5.9 by Vincent Ladeuil
More tests.
889
        import bzrlib.plugins.test_foo
890
        self.assertEqual('bzrlib.plugins.test_foo',
891
                         bzrlib.plugins.test_foo.__package__)
892
        import bzrlib.plugins.test_foo.test_bar
5235.1.1 by Martin
Make BZR_PLUGINS_AT tests that check filenames use a path-based assertion method rather than just string comparison
893
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
894
                                  bzrlib.plugins.test_foo.test_bar.__file__)
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
895
5086.5.15 by Vincent Ladeuil
Fixed as per Ian's review.
896
    def test_loading_from___init__only(self):
5086.5.13 by Vincent Ladeuil
Reproduce bug #552922.
897
        # We rename the existing __init__.py file to ensure that we don't load
898
        # a random file
899
        init = 'non-standard-dir/__init__.py'
900
        random = 'non-standard-dir/setup.py'
901
        os.rename(init, random)
902
        self.addCleanup(os.rename, random, init)
903
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
904
        plugin.load_plugins(['standard'])
905
        self.assertPluginUnknown('test_foo')
5086.5.14 by Vincent Ladeuil
Fix bug #552922 by controlling which files can be used to load a plugin.
906
907
    def test_loading_from_specific_file(self):
908
        plugin_dir = 'non-standard-dir'
909
        plugin_file_name = 'iamtestfoo.py'
910
        plugin_path = osutils.pathjoin(plugin_dir, plugin_file_name)
911
        source = '''\
912
"""This is the doc for %s"""
913
dir_source = '%s'
914
''' % ('test_foo', plugin_path)
915
        self.create_plugin('test_foo', source=source,
916
                           dir=plugin_dir, file_name=plugin_file_name)
917
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
918
        plugin.load_plugins(['standard'])
919
        self.assertTestFooLoadedFrom(plugin_path)