~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commands.py

Turn completion assertions into separate methods.

Many common assertions used to be expressed as arguments to the complete
method.  This makes the checks more explicit, and the code easier to read.

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