/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commands.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
import errno
 
18
import inspect
 
19
import sys
 
20
 
 
21
from bzrlib import (
 
22
    builtins,
 
23
    commands,
 
24
    config,
 
25
    errors,
 
26
    option,
 
27
    tests,
 
28
    )
 
29
from bzrlib.commands import display_command
 
30
from bzrlib.tests import TestSkipped
 
31
 
 
32
 
 
33
class TestCommands(tests.TestCase):
 
34
 
 
35
    def test_all_commands_have_help(self):
 
36
        commands._register_builtin_commands()
 
37
        commands_without_help = set()
 
38
        base_doc = inspect.getdoc(commands.Command)
 
39
        for cmd_name in commands.all_command_names():
 
40
            cmd = commands.get_cmd_object(cmd_name)
 
41
            cmd_help = cmd.help()
 
42
            if not cmd_help or cmd_help == base_doc:
 
43
                commands_without_help.append(cmd_name)
 
44
        self.assertLength(0, commands_without_help)
 
45
 
 
46
    def test_display_command(self):
 
47
        """EPIPE message is selectively suppressed"""
 
48
        def pipe_thrower():
 
49
            raise IOError(errno.EPIPE, "Bogus pipe error")
 
50
        self.assertRaises(IOError, pipe_thrower)
 
51
        @display_command
 
52
        def non_thrower():
 
53
            pipe_thrower()
 
54
        non_thrower()
 
55
        @display_command
 
56
        def other_thrower():
 
57
            raise IOError(errno.ESPIPE, "Bogus pipe error")
 
58
        self.assertRaises(IOError, other_thrower)
 
59
 
 
60
    def test_unicode_command(self):
 
61
        # This error is thrown when we can't find the command in the
 
62
        # list of available commands
 
63
        self.assertRaises(errors.BzrCommandError,
 
64
                          commands.run_bzr, [u'cmd\xb5'])
 
65
 
 
66
    def test_unicode_option(self):
 
67
        # This error is actually thrown by optparse, when it
 
68
        # can't find the given option
 
69
        import optparse
 
70
        if optparse.__version__ == "1.5.3":
 
71
            raise TestSkipped("optparse 1.5.3 can't handle unicode options")
 
72
        self.assertRaises(errors.BzrCommandError,
 
73
                          commands.run_bzr, ['log', u'--option\xb5'])
 
74
 
 
75
    @staticmethod
 
76
    def get_command(options):
 
77
        class cmd_foo(commands.Command):
 
78
            __doc__ = 'Bar'
 
79
 
 
80
            takes_options = options
 
81
 
 
82
        return cmd_foo()
 
83
 
 
84
    def test_help_hidden(self):
 
85
        c = self.get_command([option.Option('foo', hidden=True)])
 
86
        self.assertNotContainsRe(c.get_help_text(), '--foo')
 
87
 
 
88
    def test_help_not_hidden(self):
 
89
        c = self.get_command([option.Option('foo', hidden=False)])
 
90
        self.assertContainsRe(c.get_help_text(), '--foo')
 
91
 
 
92
 
 
93
class TestInsideCommand(tests.TestCaseInTempDir):
 
94
 
 
95
    def test_command_see_config_overrides(self):
 
96
        def run(cmd):
 
97
            # We override the run() command method so we can observe the
 
98
            # overrides from inside.
 
99
            c = config.GlobalStack()
 
100
            self.assertEquals('12', c.get('xx'))
 
101
            self.assertEquals('foo', c.get('yy'))
 
102
        self.overrideAttr(builtins.cmd_rocks, 'run', run)
 
103
        self.run_bzr(['rocks', '-Oxx=12', '-Oyy=foo'])
 
104
        c = config.GlobalStack()
 
105
        # Ensure that we don't leak outside of the command
 
106
        self.assertEquals(None, c.get('xx'))
 
107
        self.assertEquals(None, c.get('yy'))
 
108
 
 
109
 
 
110
class TestInvokedAs(tests.TestCase):
 
111
 
 
112
    def test_invoked_as(self):
 
113
        """The command object knows the actual name used to invoke it."""
 
114
        commands.install_bzr_command_hooks()
 
115
        commands._register_builtin_commands()
 
116
        # get one from the real get_cmd_object.
 
117
        c = commands.get_cmd_object('ci')
 
118
        self.assertIsInstance(c, builtins.cmd_commit)
 
119
        self.assertEquals(c.invoked_as, 'ci')
 
120
 
 
121
 
 
122
class TestGetAlias(tests.TestCase):
 
123
 
 
124
    def _get_config(self, config_text):
 
125
        my_config = config.GlobalConfig.from_string(config_text)
 
126
        return my_config
 
127
 
 
128
    def test_simple(self):
 
129
        my_config = self._get_config("[ALIASES]\n"
 
130
            "diff=diff -r -2..-1\n")
 
131
        self.assertEqual([u'diff', u'-r', u'-2..-1'],
 
132
            commands.get_alias("diff", config=my_config))
 
133
 
 
134
    def test_single_quotes(self):
 
135
        my_config = self._get_config("[ALIASES]\n"
 
136
            "diff=diff -r -2..-1 --diff-options "
 
137
            "'--strip-trailing-cr -wp'\n")
 
138
        self.assertEqual([u'diff', u'-r', u'-2..-1', u'--diff-options',
 
139
                          u'--strip-trailing-cr -wp'],
 
140
                          commands.get_alias("diff", config=my_config))
 
141
 
 
142
    def test_double_quotes(self):
 
143
        my_config = self._get_config("[ALIASES]\n"
 
144
            "diff=diff -r -2..-1 --diff-options "
 
145
            "\"--strip-trailing-cr -wp\"\n")
 
146
        self.assertEqual([u'diff', u'-r', u'-2..-1', u'--diff-options',
 
147
                          u'--strip-trailing-cr -wp'],
 
148
                          commands.get_alias("diff", config=my_config))
 
149
 
 
150
    def test_unicode(self):
 
151
        my_config = self._get_config("[ALIASES]\n"
 
152
            u'iam=whoami "Erik B\u00e5gfors <erik@bagfors.nu>"\n')
 
153
        self.assertEqual([u'whoami', u'Erik B\u00e5gfors <erik@bagfors.nu>'],
 
154
                          commands.get_alias("iam", config=my_config))
 
155
 
 
156
 
 
157
class TestSeeAlso(tests.TestCase):
 
158
    """Tests for the see also functional of Command."""
 
159
 
 
160
    @staticmethod
 
161
    def _get_command_with_see_also(see_also):
 
162
        class ACommand(commands.Command):
 
163
            __doc__ = """A sample command."""
 
164
            _see_also = see_also
 
165
        return ACommand()
 
166
 
 
167
    def test_default_subclass_no_see_also(self):
 
168
        command = self._get_command_with_see_also([])
 
169
        self.assertEqual([], command.get_see_also())
 
170
 
 
171
    def test__see_also(self):
 
172
        """When _see_also is defined, it sets the result of get_see_also()."""
 
173
        command = self._get_command_with_see_also(['bar', 'foo'])
 
174
        self.assertEqual(['bar', 'foo'], command.get_see_also())
 
175
 
 
176
    def test_deduplication(self):
 
177
        """Duplicates in _see_also are stripped out."""
 
178
        command = self._get_command_with_see_also(['foo', 'foo'])
 
179
        self.assertEqual(['foo'], command.get_see_also())
 
180
 
 
181
    def test_sorted(self):
 
182
        """_see_also is sorted by get_see_also."""
 
183
        command = self._get_command_with_see_also(['foo', 'bar'])
 
184
        self.assertEqual(['bar', 'foo'], command.get_see_also())
 
185
 
 
186
    def test_additional_terms(self):
 
187
        """Additional terms can be supplied and are deduped and sorted."""
 
188
        command = self._get_command_with_see_also(['foo', 'bar'])
 
189
        self.assertEqual(['bar', 'foo', 'gam'],
 
190
            command.get_see_also(['gam', 'bar', 'gam']))
 
191
 
 
192
 
 
193
class TestRegisterLazy(tests.TestCase):
 
194
 
 
195
    def setUp(self):
 
196
        tests.TestCase.setUp(self)
 
197
        import bzrlib.tests.fake_command
 
198
        del sys.modules['bzrlib.tests.fake_command']
 
199
        global lazy_command_imported
 
200
        lazy_command_imported = False
 
201
        commands.install_bzr_command_hooks()
 
202
 
 
203
    @staticmethod
 
204
    def remove_fake():
 
205
        commands.plugin_cmds.remove('fake')
 
206
 
 
207
    def assertIsFakeCommand(self, cmd_obj):
 
208
        from bzrlib.tests.fake_command import cmd_fake
 
209
        self.assertIsInstance(cmd_obj, cmd_fake)
 
210
 
 
211
    def test_register_lazy(self):
 
212
        """Ensure lazy registration works"""
 
213
        commands.plugin_cmds.register_lazy('cmd_fake', [],
 
214
                                           'bzrlib.tests.fake_command')
 
215
        self.addCleanup(self.remove_fake)
 
216
        self.assertFalse(lazy_command_imported)
 
217
        fake_instance = commands.get_cmd_object('fake')
 
218
        self.assertTrue(lazy_command_imported)
 
219
        self.assertIsFakeCommand(fake_instance)
 
220
 
 
221
    def test_get_unrelated_does_not_import(self):
 
222
        commands.plugin_cmds.register_lazy('cmd_fake', [],
 
223
                                           'bzrlib.tests.fake_command')
 
224
        self.addCleanup(self.remove_fake)
 
225
        commands.get_cmd_object('status')
 
226
        self.assertFalse(lazy_command_imported)
 
227
 
 
228
    def test_aliases(self):
 
229
        commands.plugin_cmds.register_lazy('cmd_fake', ['fake_alias'],
 
230
                                           'bzrlib.tests.fake_command')
 
231
        self.addCleanup(self.remove_fake)
 
232
        fake_instance = commands.get_cmd_object('fake_alias')
 
233
        self.assertIsFakeCommand(fake_instance)
 
234
 
 
235
 
 
236
class TestExtendCommandHook(tests.TestCase):
 
237
 
 
238
    def test_fires_on_get_cmd_object(self):
 
239
        # The extend_command(cmd) hook fires when commands are delivered to the
 
240
        # ui, not simply at registration (because lazy registered plugin
 
241
        # commands are registered).
 
242
        # when they are simply created.
 
243
        hook_calls = []
 
244
        commands.install_bzr_command_hooks()
 
245
        commands.Command.hooks.install_named_hook(
 
246
            "extend_command", hook_calls.append, None)
 
247
        # create a command, should not fire
 
248
        class cmd_test_extend_command_hook(commands.Command):
 
249
            __doc__ = """A sample command."""
 
250
        self.assertEqual([], hook_calls)
 
251
        # -- as a builtin
 
252
        # register the command class, should not fire
 
253
        try:
 
254
            commands.builtin_command_registry.register(cmd_test_extend_command_hook)
 
255
            self.assertEqual([], hook_calls)
 
256
            # and ask for the object, should fire
 
257
            cmd = commands.get_cmd_object('test-extend-command-hook')
 
258
            # For resilience - to ensure all code paths hit it - we
 
259
            # fire on everything returned in the 'cmd_dict', which is currently
 
260
            # all known commands, so assert that cmd is in hook_calls
 
261
            self.assertSubset([cmd], hook_calls)
 
262
            del hook_calls[:]
 
263
        finally:
 
264
            commands.builtin_command_registry.remove('test-extend-command-hook')
 
265
        # -- as a plugin lazy registration
 
266
        try:
 
267
            # register the command class, should not fire
 
268
            commands.plugin_cmds.register_lazy('cmd_fake', [],
 
269
                                               'bzrlib.tests.fake_command')
 
270
            self.assertEqual([], hook_calls)
 
271
            # and ask for the object, should fire
 
272
            cmd = commands.get_cmd_object('fake')
 
273
            self.assertEqual([cmd], hook_calls)
 
274
        finally:
 
275
            commands.plugin_cmds.remove('fake')
 
276
 
 
277
 
 
278
class TestGetCommandHook(tests.TestCase):
 
279
 
 
280
    def test_fires_on_get_cmd_object(self):
 
281
        # The get_command(cmd) hook fires when commands are delivered to the
 
282
        # ui.
 
283
        commands.install_bzr_command_hooks()
 
284
        hook_calls = []
 
285
        class ACommand(commands.Command):
 
286
            __doc__ = """A sample command."""
 
287
        def get_cmd(cmd_or_None, cmd_name):
 
288
            hook_calls.append(('called', cmd_or_None, cmd_name))
 
289
            if cmd_name in ('foo', 'info'):
 
290
                return ACommand()
 
291
        commands.Command.hooks.install_named_hook(
 
292
            "get_command", get_cmd, None)
 
293
        # create a command directly, should not fire
 
294
        cmd = ACommand()
 
295
        self.assertEqual([], hook_calls)
 
296
        # ask by name, should fire and give us our command
 
297
        cmd = commands.get_cmd_object('foo')
 
298
        self.assertEqual([('called', None, 'foo')], hook_calls)
 
299
        self.assertIsInstance(cmd, ACommand)
 
300
        del hook_calls[:]
 
301
        # ask by a name that is supplied by a builtin - the hook should still
 
302
        # fire and we still get our object, but we should see the builtin
 
303
        # passed to the hook.
 
304
        cmd = commands.get_cmd_object('info')
 
305
        self.assertIsInstance(cmd, ACommand)
 
306
        self.assertEqual(1, len(hook_calls))
 
307
        self.assertEqual('info', hook_calls[0][2])
 
308
        self.assertIsInstance(hook_calls[0][1], builtins.cmd_info)
 
309
 
 
310
 
 
311
class TestGetMissingCommandHook(tests.TestCase):
 
312
 
 
313
    def hook_missing(self):
 
314
        """Hook get_missing_command for testing."""
 
315
        self.hook_calls = []
 
316
        class ACommand(commands.Command):
 
317
            __doc__ = """A sample command."""
 
318
        def get_missing_cmd(cmd_name):
 
319
            self.hook_calls.append(('called', cmd_name))
 
320
            if cmd_name in ('foo', 'info'):
 
321
                return ACommand()
 
322
        commands.Command.hooks.install_named_hook(
 
323
            "get_missing_command", get_missing_cmd, None)
 
324
        self.ACommand = ACommand
 
325
 
 
326
    def test_fires_on_get_cmd_object(self):
 
327
        # The get_missing_command(cmd) hook fires when commands are delivered to the
 
328
        # ui.
 
329
        self.hook_missing()
 
330
        # create a command directly, should not fire
 
331
        self.cmd = self.ACommand()
 
332
        self.assertEqual([], self.hook_calls)
 
333
        # ask by name, should fire and give us our command
 
334
        cmd = commands.get_cmd_object('foo')
 
335
        self.assertEqual([('called', 'foo')], self.hook_calls)
 
336
        self.assertIsInstance(cmd, self.ACommand)
 
337
        del self.hook_calls[:]
 
338
        # ask by a name that is supplied by a builtin - the hook should not
 
339
        # fire and we still get our object.
 
340
        commands.install_bzr_command_hooks()
 
341
        cmd = commands.get_cmd_object('info')
 
342
        self.assertNotEqual(None, cmd)
 
343
        self.assertEqual(0, len(self.hook_calls))
 
344
 
 
345
    def test_skipped_on_HelpCommandIndex_get_topics(self):
 
346
        # The get_missing_command(cmd_name) hook is not fired when
 
347
        # looking up help topics.
 
348
        self.hook_missing()
 
349
        topic = commands.HelpCommandIndex()
 
350
        topics = topic.get_topics('foo')
 
351
        self.assertEqual([], self.hook_calls)
 
352
 
 
353
 
 
354
class TestListCommandHook(tests.TestCase):
 
355
 
 
356
    def test_fires_on_all_command_names(self):
 
357
        # The list_commands() hook fires when all_command_names() is invoked.
 
358
        hook_calls = []
 
359
        commands.install_bzr_command_hooks()
 
360
        def list_my_commands(cmd_names):
 
361
            hook_calls.append('called')
 
362
            cmd_names.update(['foo', 'bar'])
 
363
            return cmd_names
 
364
        commands.Command.hooks.install_named_hook(
 
365
            "list_commands", list_my_commands, None)
 
366
        # Get a command, which should not trigger the hook.
 
367
        cmd = commands.get_cmd_object('info')
 
368
        self.assertEqual([], hook_calls)
 
369
        # Get all command classes (for docs and shell completion).
 
370
        cmds = list(commands.all_command_names())
 
371
        self.assertEqual(['called'], hook_calls)
 
372
        self.assertSubset(['foo', 'bar'], cmds)