/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_options.py

  • Committer: John Arbash Meinel
  • Date: 2008-11-25 18:51:48 UTC
  • mto: This revision was merged to the branch mainline in revision 3854.
  • Revision ID: john@arbash-meinel.com-20081125185148-jsfkqnzfjjqsleds
It seems we have some direct tests that don't use strings and expect a value error as well.

They would be sanitized later on by Revision. We could use that code, but this test
depends on the serializer, which Revision wouldn't know about.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import re
 
18
 
 
19
from bzrlib import (
 
20
    bzrdir,
 
21
    commands,
 
22
    errors,
 
23
    option,
 
24
    )
 
25
from bzrlib.builtins import cmd_commit
 
26
from bzrlib.commands import Command, parse_args
 
27
from bzrlib.tests import TestCase
 
28
from bzrlib.repofmt import knitrepo
 
29
 
 
30
 
 
31
def parse(options, args):
 
32
    parser = option.get_optparser(dict((o.name, o) for o in options))
 
33
    return parser.parse_args(args)
 
34
 
 
35
 
 
36
class OptionTests(TestCase):
 
37
    """Command-line option tests"""
 
38
 
 
39
    def test_parse_args(self):
 
40
        """Option parser"""
 
41
        # XXX: Using cmd_commit makes these tests overly sensitive to changes
 
42
        # to cmd_commit, when they are meant to be about option parsing in
 
43
        # general.
 
44
        self.assertEqual(parse_args(cmd_commit(), ['--help']),
 
45
           ([], {'exclude': [], 'fixes': [], 'help': True}))
 
46
        self.assertEqual(parse_args(cmd_commit(), ['--message=biter']),
 
47
           ([], {'exclude': [], 'fixes': [], 'message': 'biter'}))
 
48
 
 
49
    def test_no_more_opts(self):
 
50
        """Terminated options"""
 
51
        self.assertEqual(parse_args(cmd_commit(), ['--', '-file-with-dashes']),
 
52
                          (['-file-with-dashes'], {'exclude': [], 'fixes': []}))
 
53
 
 
54
    def test_option_help(self):
 
55
        """Options have help strings."""
 
56
        out, err = self.run_bzr('commit --help')
 
57
        self.assertContainsRe(out,
 
58
                r'--file(.|\n)*Take commit message from this file\.')
 
59
        self.assertContainsRe(out, r'-h.*--help')
 
60
 
 
61
    def test_option_help_global(self):
 
62
        """Global options have help strings."""
 
63
        out, err = self.run_bzr('help status')
 
64
        self.assertContainsRe(out, r'--show-ids.*Show internal object.')
 
65
 
 
66
    def test_option_arg_help(self):
 
67
        """Help message shows option arguments."""
 
68
        out, err = self.run_bzr('help commit')
 
69
        self.assertEqual(err, '')
 
70
        self.assertContainsRe(out, r'--file[ =]MSGFILE')
 
71
 
 
72
    def test_unknown_short_opt(self):
 
73
        out, err = self.run_bzr('help -r', retcode=3)
 
74
        self.assertContainsRe(err, r'no such option')
 
75
 
 
76
    def test_set_short_name(self):
 
77
        o = option.Option('wiggle')
 
78
        o.set_short_name('w')
 
79
        self.assertEqual(o.short_name(), 'w')
 
80
 
 
81
    def test_allow_dash(self):
 
82
        """Test that we can pass a plain '-' as an argument."""
 
83
        self.assertEqual((['-']), parse_args(cmd_commit(), ['-'])[0])
 
84
 
 
85
    def parse(self, options, args):
 
86
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
87
        return parser.parse_args(args)
 
88
 
 
89
    def test_conversion(self):
 
90
        options = [option.Option('hello')]
 
91
        opts, args = self.parse(options, ['--no-hello', '--hello'])
 
92
        self.assertEqual(True, opts.hello)
 
93
        opts, args = self.parse(options, [])
 
94
        self.assertFalse(hasattr(opts, 'hello'))
 
95
        opts, args = self.parse(options, ['--hello', '--no-hello'])
 
96
        self.assertEqual(False, opts.hello)
 
97
        options = [option.Option('number', type=int)]
 
98
        opts, args = self.parse(options, ['--number', '6'])
 
99
        self.assertEqual(6, opts.number)
 
100
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
101
                          ['--number'])
 
102
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
103
                          ['--no-number'])
 
104
 
 
105
    def test_registry_conversion(self):
 
106
        registry = bzrdir.BzrDirFormatRegistry()
 
107
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
108
        registry.register_metadir('two', 'RepositoryFormatKnit1', 'two help')
 
109
        registry.register_metadir('hidden', 'RepositoryFormatKnit1',
 
110
            'two help', hidden=True)
 
111
        registry.set_default('one')
 
112
        options = [option.RegistryOption('format', '', registry, str)]
 
113
        opts, args = self.parse(options, ['--format', 'one'])
 
114
        self.assertEqual({'format':'one'}, opts)
 
115
        opts, args = self.parse(options, ['--format', 'two'])
 
116
        self.assertEqual({'format':'two'}, opts)
 
117
        self.assertRaises(errors.BadOptionValue, self.parse, options,
 
118
                          ['--format', 'three'])
 
119
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
120
                          ['--two'])
 
121
        options = [option.RegistryOption('format', '', registry, str,
 
122
                   value_switches=True)]
 
123
        opts, args = self.parse(options, ['--two'])
 
124
        self.assertEqual({'format':'two'}, opts)
 
125
        opts, args = self.parse(options, ['--two', '--one'])
 
126
        self.assertEqual({'format':'one'}, opts)
 
127
        opts, args = self.parse(options, ['--two', '--one',
 
128
                                          '--format', 'two'])
 
129
        self.assertEqual({'format':'two'}, opts)
 
130
        options = [option.RegistryOption('format', '', registry, str,
 
131
                   enum_switch=False)]
 
132
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
133
                          ['--format', 'two'])
 
134
 
 
135
    def test_override(self):
 
136
        options = [option.Option('hello', type=str),
 
137
                   option.Option('hi', type=str, param_name='hello')]
 
138
        opts, args = self.parse(options, ['--hello', 'a', '--hello', 'b'])
 
139
        self.assertEqual('b', opts.hello)
 
140
        opts, args = self.parse(options, ['--hello', 'b', '--hello', 'a'])
 
141
        self.assertEqual('a', opts.hello)
 
142
        opts, args = self.parse(options, ['--hello', 'a', '--hi', 'b'])
 
143
        self.assertEqual('b', opts.hello)
 
144
        opts, args = self.parse(options, ['--hi', 'b', '--hello', 'a'])
 
145
        self.assertEqual('a', opts.hello)
 
146
 
 
147
    def test_registry_converter(self):
 
148
        options = [option.RegistryOption('format', '',
 
149
                   bzrdir.format_registry, bzrdir.format_registry.make_bzrdir)]
 
150
        opts, args = self.parse(options, ['--format', 'knit'])
 
151
        self.assertIsInstance(opts.format.repository_format,
 
152
                              knitrepo.RepositoryFormatKnit1)
 
153
 
 
154
    def test_lazy_registry(self):
 
155
        options = [option.RegistryOption('format', '',
 
156
                   lazy_registry=('bzrlib.bzrdir','format_registry'),
 
157
                   converter=str)]
 
158
        opts, args = self.parse(options, ['--format', 'knit'])
 
159
        self.assertEqual({'format': 'knit'}, opts)
 
160
        self.assertRaises(
 
161
            errors.BadOptionValue, self.parse, options, ['--format', 'BAD'])
 
162
 
 
163
    def test_from_kwargs(self):
 
164
        my_option = option.RegistryOption.from_kwargs('my-option',
 
165
            help='test option', short='be short', be_long='go long')
 
166
        self.assertEqual(['my-option'],
 
167
            [x[0] for x in my_option.iter_switches()])
 
168
        my_option = option.RegistryOption.from_kwargs('my-option',
 
169
            help='test option', title="My option", short='be short',
 
170
            be_long='go long', value_switches=True)
 
171
        self.assertEqual(['my-option', 'be-long', 'short'],
 
172
            [x[0] for x in my_option.iter_switches()])
 
173
        self.assertEqual('test option', my_option.help)
 
174
 
 
175
    def test_help(self):
 
176
        registry = bzrdir.BzrDirFormatRegistry()
 
177
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
178
        registry.register_metadir('two',
 
179
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
180
            'two help',
 
181
            )
 
182
        registry.register_metadir('hidden', 'RepositoryFormat7', 'hidden help',
 
183
            hidden=True)
 
184
        registry.set_default('one')
 
185
        options = [option.RegistryOption('format', 'format help', registry,
 
186
                   str, value_switches=True, title='Formats')]
 
187
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
188
        value = parser.format_option_help()
 
189
        self.assertContainsRe(value, 'format.*format help')
 
190
        self.assertContainsRe(value, 'one.*one help')
 
191
        self.assertContainsRe(value, 'Formats:\n *--format')
 
192
        self.assertNotContainsRe(value, 'hidden help')
 
193
 
 
194
    def test_iter_switches(self):
 
195
        opt = option.Option('hello', help='fg')
 
196
        self.assertEqual(list(opt.iter_switches()),
 
197
                         [('hello', None, None, 'fg')])
 
198
        opt = option.Option('hello', help='fg', type=int)
 
199
        self.assertEqual(list(opt.iter_switches()),
 
200
                         [('hello', None, 'ARG', 'fg')])
 
201
        opt = option.Option('hello', help='fg', type=int, argname='gar')
 
202
        self.assertEqual(list(opt.iter_switches()),
 
203
                         [('hello', None, 'GAR', 'fg')])
 
204
        registry = bzrdir.BzrDirFormatRegistry()
 
205
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
206
        registry.register_metadir('two',
 
207
                'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
208
                'two help',
 
209
                )
 
210
        registry.set_default('one')
 
211
        opt = option.RegistryOption('format', 'format help', registry,
 
212
                                    value_switches=False)
 
213
        self.assertEqual(list(opt.iter_switches()),
 
214
                         [('format', None, 'ARG', 'format help')])
 
215
        opt = option.RegistryOption('format', 'format help', registry,
 
216
                                    value_switches=True)
 
217
        self.assertEqual(list(opt.iter_switches()),
 
218
                         [('format', None, 'ARG', 'format help'),
 
219
                          ('default', None, None, 'one help'),
 
220
                          ('one', None, None, 'one help'),
 
221
                          ('two', None, None, 'two help'),
 
222
                          ])
 
223
 
 
224
    def test_option_callback_bool(self):
 
225
        "Test booleans get True and False passed correctly to a callback."""
 
226
        cb_calls = []
 
227
        def cb(option, name, value, parser):
 
228
            cb_calls.append((option,name,value,parser))
 
229
        options = [option.Option('hello', custom_callback=cb)]
 
230
        opts, args = self.parse(options, ['--hello', '--no-hello'])
 
231
        self.assertEqual(2, len(cb_calls))
 
232
        opt,name,value,parser = cb_calls[0]
 
233
        self.assertEqual('hello', name)
 
234
        self.assertTrue(value)
 
235
        opt,name,value,parser = cb_calls[1]
 
236
        self.assertEqual('hello', name)
 
237
        self.assertFalse(value)
 
238
 
 
239
    def test_option_callback_str(self):
 
240
        """Test callbacks work for string options both long and short."""
 
241
        cb_calls = []
 
242
        def cb(option, name, value, parser):
 
243
            cb_calls.append((option,name,value,parser))
 
244
        options = [option.Option('hello', type=str, custom_callback=cb,
 
245
            short_name='h')]
 
246
        opts, args = self.parse(options, ['--hello', 'world', '-h', 'mars'])
 
247
        self.assertEqual(2, len(cb_calls))
 
248
        opt,name,value,parser = cb_calls[0]
 
249
        self.assertEqual('hello', name)
 
250
        self.assertEqual('world', value)
 
251
        opt,name,value,parser = cb_calls[1]
 
252
        self.assertEqual('hello', name)
 
253
        self.assertEqual('mars', value)
 
254
 
 
255
 
 
256
class TestListOptions(TestCase):
 
257
    """Tests for ListOption, used to specify lists on the command-line."""
 
258
 
 
259
    def parse(self, options, args):
 
260
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
261
        return parser.parse_args(args)
 
262
 
 
263
    def test_list_option(self):
 
264
        options = [option.ListOption('hello', type=str)]
 
265
        opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
 
266
        self.assertEqual(['world', 'sailor'], opts.hello)
 
267
 
 
268
    def test_list_option_with_dash(self):
 
269
        options = [option.ListOption('with-dash', type=str)]
 
270
        opts, args = self.parse(options, ['--with-dash=world',
 
271
                                          '--with-dash=sailor'])
 
272
        self.assertEqual(['world', 'sailor'], opts.with_dash)
 
273
 
 
274
    def test_list_option_no_arguments(self):
 
275
        options = [option.ListOption('hello', type=str)]
 
276
        opts, args = self.parse(options, [])
 
277
        self.assertEqual([], opts.hello)
 
278
 
 
279
    def test_list_option_with_int_type(self):
 
280
        options = [option.ListOption('hello', type=int)]
 
281
        opts, args = self.parse(options, ['--hello=2', '--hello=3'])
 
282
        self.assertEqual([2, 3], opts.hello)
 
283
 
 
284
    def test_list_option_with_int_type_can_be_reset(self):
 
285
        options = [option.ListOption('hello', type=int)]
 
286
        opts, args = self.parse(options, ['--hello=2', '--hello=3',
 
287
                                          '--hello=-', '--hello=5'])
 
288
        self.assertEqual([5], opts.hello)
 
289
 
 
290
    def test_list_option_can_be_reset(self):
 
291
        """Passing an option of '-' to a list option should reset the list."""
 
292
        options = [option.ListOption('hello', type=str)]
 
293
        opts, args = self.parse(
 
294
            options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
 
295
        self.assertEqual(['c'], opts.hello)
 
296
 
 
297
    def test_option_callback_list(self):
 
298
        """Test callbacks work for list options."""
 
299
        cb_calls = []
 
300
        def cb(option, name, value, parser):
 
301
            # Note that the value is a reference so copy to keep it
 
302
            cb_calls.append((option,name,value[:],parser))
 
303
        options = [option.ListOption('hello', type=str, custom_callback=cb)]
 
304
        opts, args = self.parse(options, ['--hello=world', '--hello=mars',
 
305
            '--hello=-'])
 
306
        self.assertEqual(3, len(cb_calls))
 
307
        opt,name,value,parser = cb_calls[0]
 
308
        self.assertEqual('hello', name)
 
309
        self.assertEqual(['world'], value)
 
310
        opt,name,value,parser = cb_calls[1]
 
311
        self.assertEqual('hello', name)
 
312
        self.assertEqual(['world', 'mars'], value)
 
313
        opt,name,value,parser = cb_calls[2]
 
314
        self.assertEqual('hello', name)
 
315
        self.assertEqual([], value)
 
316
 
 
317
 
 
318
class TestOptionDefinitions(TestCase):
 
319
    """Tests for options in the Bazaar codebase."""
 
320
 
 
321
    def get_builtin_command_options(self):
 
322
        g = []
 
323
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
 
324
            cmd = cmd_class()
 
325
            for opt_name, opt in sorted(cmd.options().items()):
 
326
                g.append((cmd_name, opt))
 
327
        return g
 
328
 
 
329
    def test_global_options_used(self):
 
330
        # In the distant memory, options could only be declared globally.  Now
 
331
        # we prefer to declare them in the command, unless like -r they really
 
332
        # are used very widely with the exact same meaning.  So this checks
 
333
        # for any that should be garbage collected.
 
334
        g = dict(option.Option.OPTIONS.items())
 
335
        used_globals = {}
 
336
        msgs = []
 
337
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
 
338
            for option_or_name in sorted(cmd_class.takes_options):
 
339
                if not isinstance(option_or_name, basestring):
 
340
                    self.assertIsInstance(option_or_name, option.Option)
 
341
                elif not option_or_name in g:
 
342
                    msgs.append("apparent reference to undefined "
 
343
                        "global option %r from %r"
 
344
                        % (option_or_name, cmd_class))
 
345
                else:
 
346
                    used_globals.setdefault(option_or_name, []).append(cmd_name)
 
347
        unused_globals = set(g.keys()) - set(used_globals.keys())
 
348
        # not enforced because there might be plugins that use these globals
 
349
        ## for option_name in sorted(unused_globals):
 
350
        ##    msgs.append("unused global option %r" % option_name)
 
351
        ## for option_name, cmds in sorted(used_globals.items()):
 
352
        ##     if len(cmds) <= 1:
 
353
        ##         msgs.append("global option %r is only used by %r"
 
354
        ##                 % (option_name, cmds))
 
355
        if msgs:
 
356
            self.fail("problems with global option definitions:\n"
 
357
                    + '\n'.join(msgs))
 
358
 
 
359
    def test_option_grammar(self):
 
360
        msgs = []
 
361
        # Option help should be written in sentence form, and have a final
 
362
        # period and be all on a single line, because the display code will
 
363
        # wrap it.
 
364
        option_re = re.compile(r'^[A-Z][^\n]+\.$')
 
365
        for scope, opt in self.get_builtin_command_options():
 
366
            if not opt.help:
 
367
                msgs.append('%-16s %-16s %s' %
 
368
                       ((scope or 'GLOBAL'), opt.name, 'NO HELP'))
 
369
            elif not option_re.match(opt.help):
 
370
                msgs.append('%-16s %-16s %s' %
 
371
                        ((scope or 'GLOBAL'), opt.name, opt.help))
 
372
        if msgs:
 
373
            self.fail("The following options don't match the style guide:\n"
 
374
                    + '\n'.join(msgs))
 
375
 
 
376
    def test_is_hidden(self):
 
377
        registry = bzrdir.BzrDirFormatRegistry()
 
378
        registry.register_metadir('hidden', 'HiddenFormat',
 
379
            'hidden help text', hidden=True)
 
380
        registry.register_metadir('visible', 'VisibleFormat',
 
381
            'visible help text', hidden=False)
 
382
        format = option.RegistryOption('format', '', registry, str)
 
383
        self.assertTrue(format.is_hidden('hidden'))
 
384
        self.assertFalse(format.is_hidden('visible'))
 
385
 
 
386
    def test_option_custom_help(self):
 
387
        the_opt = option.Option.OPTIONS['help']
 
388
        orig_help = the_opt.help[:]
 
389
        my_opt = option.custom_help('help', 'suggest lottery numbers')
 
390
        # Confirm that my_opt has my help and the original is unchanged
 
391
        self.assertEqual('suggest lottery numbers', my_opt.help)
 
392
        self.assertEqual(orig_help, the_opt.help)
 
393
 
 
394
 
 
395
class TestVerboseQuietLinkage(TestCase):
 
396
 
 
397
    def check(self, parser, level, args):
 
398
        option._verbosity_level = 0
 
399
        opts, args = parser.parse_args(args)
 
400
        self.assertEqual(level, option._verbosity_level)
 
401
 
 
402
    def test_verbose_quiet_linkage(self):
 
403
        parser = option.get_optparser(option.Option.STD_OPTIONS)
 
404
        self.check(parser, 0, [])
 
405
        self.check(parser, 1, ['-v'])
 
406
        self.check(parser, 2, ['-v', '-v'])
 
407
        self.check(parser, -1, ['-q'])
 
408
        self.check(parser, -2, ['-qq'])
 
409
        self.check(parser, -1, ['-v', '-v', '-q'])
 
410
        self.check(parser, 2, ['-q', '-v', '-v'])
 
411
        self.check(parser, 0, ['--no-verbose'])
 
412
        self.check(parser, 0, ['-v', '-q', '--no-quiet'])