/brz/remove-bazaar

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