1
# Copyright (C) 2005 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
"""Tests for 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
24
from StringIO import StringIO
30
import bzrlib.commands
32
from bzrlib.tests import TestCase, TestCaseInTempDir
33
from bzrlib.osutils import pathjoin, abspath
37
import bzrlib.commands
28
from bzrlib.selftest import InTempDir
31
def PluginTest(InTempDir):
32
"""Create an external plugin and test loading."""
36
orig_help = self.backtick('bzr help commands') # No plugins yet
37
os.mkdir('plugin_test')
38
f = open(os.path.join('plugin_test', 'myplug.py'), 'wt')
42
newhelp = backtick('bzr help commands')
43
assert newhelp.startswith('You have been overridden\n')
44
# We added a line, but the rest should work
45
assert newhelp[25:] == help
47
assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
49
shutil.rmtree('plugin_test')
55
"""import bzrlib, bzrlib.commands
38
56
class cmd_myplug(bzrlib.commands.Command):
39
57
'''Just a simple test plugin.'''
42
60
print 'Hello from my plugin'
45
# TODO: Write a test for plugin decoration of commands.
47
class TestLoadingPlugins(TestCaseInTempDir):
51
def test_plugins_with_the_same_name_are_not_loaded(self):
52
# This test tests that having two plugins in different directories does
53
# not result in both being loaded when they have the same name. get a
54
# file name we can use which is also a valid attribute for accessing in
55
# activeattributes. - we cannot give import parameters.
57
self.failIf(tempattribute in self.activeattributes)
58
# set a place for the plugins to record their loading, and at the same
59
# time validate that the location the plugins should record to is
61
bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
63
self.failUnless(tempattribute in self.activeattributes)
64
# create two plugin directories
67
# write a plugin that will record when its loaded in the
69
template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
70
"TestLoadingPlugins.activeattributes[%r].append('%s')\n")
71
print >> file(os.path.join('first', 'plugin.py'), 'w'), template % (tempattribute, 'first')
72
print >> file(os.path.join('second', 'plugin.py'), 'w'), template % (tempattribute, 'second')
74
bzrlib.plugin.load_from_path(['first', 'second'])
75
self.assertEqual(['first'], self.activeattributes[tempattribute])
77
# remove the plugin 'plugin'
78
del self.activeattributes[tempattribute]
79
if getattr(bzrlib.plugins, 'plugin', None):
80
del bzrlib.plugins.plugin
81
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
83
def test_plugins_from_different_dirs_can_demand_load(self):
84
# This test tests that having two plugins in different
85
# directories with different names allows them both to be loaded, when
86
# we do a direct import statement.
87
# Determine a file name we can use which is also a valid attribute
88
# for accessing in activeattributes. - we cannot give import parameters.
89
tempattribute = "different-dirs"
90
self.failIf(tempattribute in self.activeattributes)
91
# set a place for the plugins to record their loading, and at the same
92
# time validate that the location the plugins should record to is
94
bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
96
self.failUnless(tempattribute in self.activeattributes)
97
# create two plugin directories
100
# write plugins that will record when they are loaded in the
101
# tempattribute list.
102
template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
103
"TestLoadingPlugins.activeattributes[%r].append('%s')\n")
104
print >> file(os.path.join('first', 'pluginone.py'), 'w'), template % (tempattribute, 'first')
105
print >> file(os.path.join('second', 'plugintwo.py'), 'w'), template % (tempattribute, 'second')
106
oldpath = bzrlib.plugins.__path__
108
bzrlib.plugins.__path__ = ['first', 'second']
109
exec "import bzrlib.plugins.pluginone"
110
self.assertEqual(['first'], self.activeattributes[tempattribute])
111
exec "import bzrlib.plugins.plugintwo"
112
self.assertEqual(['first', 'second'],
113
self.activeattributes[tempattribute])
115
# remove the plugin 'plugin'
116
del self.activeattributes[tempattribute]
117
if getattr(bzrlib.plugins, 'plugin', None):
118
del bzrlib.plugins.plugin
119
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
122
class TestAllPlugins(TestCaseInTempDir):
124
def test_plugin_appears_in_all_plugins(self):
125
# This test tests a new plugin appears in bzrlib.plugin.all_plugins().
126
# check the plugin is not loaded already
127
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
128
# write a plugin that _cannot_ fail to load.
129
print >> file('plugin.py', 'w'), ""
131
bzrlib.plugin.load_from_path(['.'])
132
self.failUnless('plugin' in bzrlib.plugin.all_plugins())
133
self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
134
self.assertEqual(bzrlib.plugin.all_plugins()['plugin'],
135
bzrlib.plugins.plugin)
137
# remove the plugin 'plugin'
138
if 'bzrlib.plugins.plugin' in sys.modules:
139
del sys.modules['bzrlib.plugins.plugin']
140
if getattr(bzrlib.plugins, 'plugin', None):
141
del bzrlib.plugins.plugin
142
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
145
class TestPluginHelp(TestCaseInTempDir):
147
def split_help_commands(self):
150
for line in self.capture('help commands').splitlines():
151
if not line.startswith(' '):
152
current = line.split()[0]
153
help[current] = help.get(current, '') + line
157
def test_plugin_help_builtins_unaffected(self):
158
# Check we don't get false positives
159
help_commands = self.split_help_commands()
160
for cmd_name in bzrlib.commands.builtin_command_names():
161
if cmd_name in bzrlib.commands.plugin_command_names():
165
bzrlib.help.help_on_command(cmd_name, help)
166
except NotImplementedError:
167
# some commands have no help
171
self.assertNotContainsRe(help.read(), 'From plugin "[^"]*"')
173
if help in help_commands.keys():
174
# some commands are hidden
175
help = help_commands[cmd_name]
176
self.assertNotContainsRe(help, 'From plugin "[^"]*"')
178
def test_plugin_help_shows_plugin(self):
179
# Create a test plugin
180
os.mkdir('plugin_test')
181
f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
187
bzrlib.plugin.load_from_path(['plugin_test'])
188
bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
189
help = self.capture('help myplug')
190
self.assertContainsRe(help, 'From plugin "myplug"')
191
help = self.split_help_commands()['myplug']
192
self.assertContainsRe(help, '\[myplug\]')
195
if bzrlib.commands.plugin_cmds.get('myplug', None):
196
del bzrlib.commands.plugin_cmds['myplug']
197
# remove the plugin 'myplug'
198
if getattr(bzrlib.plugins, 'myplug', None):
199
delattr(bzrlib.plugins, 'myplug')
202
class TestPluginFromZip(TestCaseInTempDir):
204
def make_zipped_plugin(self, zip_name, filename):
205
z = zipfile.ZipFile(zip_name, 'w')
206
z.writestr(filename, PLUGIN_TEXT)
209
def check_plugin_load(self, zip_name, plugin_name):
210
self.assertFalse(plugin_name in dir(bzrlib.plugins),
211
'Plugin already loaded')
213
bzrlib.plugin.load_from_zip(zip_name)
214
self.assertTrue(plugin_name in dir(bzrlib.plugins),
215
'Plugin is not loaded')
218
if getattr(bzrlib.plugins, plugin_name, None):
219
delattr(bzrlib.plugins, plugin_name)
221
def test_load_module(self):
222
self.make_zipped_plugin('./test.zip', 'ziplug.py')
223
self.check_plugin_load('./test.zip', 'ziplug')
225
def test_load_package(self):
226
self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
227
self.check_plugin_load('./test.zip', 'ziplug')
230
class TestSetPluginsPath(TestCase):
232
def test_set_plugins_path(self):
233
"""set_plugins_path should set the module __path__ correctly."""
234
old_path = bzrlib.plugins.__path__
236
bzrlib.plugins.__path__ = []
237
expected_path = bzrlib.plugin.set_plugins_path()
238
self.assertEqual(expected_path, bzrlib.plugins.__path__)
240
bzrlib.plugins.__path__ = old_path
64
os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
65
help = backtick('bzr help commands')
66
assert help.find('myplug') != -1
67
assert help.find('Just a simple test plugin.') != -1
70
assert backtick('bzr myplug') == 'Hello from my plugin\n'
71
assert backtick('bzr mplg') == 'Hello from my plugin\n'
73
f = open(os.path.join('plugin_test', 'override.py'), 'wb')
74
f.write("""import bzrlib, bzrlib.commands
75
class cmd_commit(bzrlib.commands.cmd_commit):
76
'''Commit changes into a new revision.'''
77
def run(self, *args, **kwargs):
78
print "I'm sorry dave, you can't do that"
80
class cmd_help(bzrlib.commands.cmd_help):
81
'''Show help on a command or other topic.'''
82
def run(self, *args, **kwargs):
83
print "You have been overridden"
84
bzrlib.commands.cmd_help.run(self, *args, **kwargs)