/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: Martin Pool
  • Date: 2005-08-24 08:59:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050824085932-c61f1f1f1c930e13
- Add a simple UIFactory 

  The idea of this is to let a client of bzrlib set some 
  policy about how output is displayed.

  In this revision all that's done is that progress bars
  are constructed by a policy established by the application
  rather than being randomly constructed in the library 
  or passed down the calls.  This avoids progress bars
  popping up while running the test suite and cleans up
  some code.

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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
 
           ([], {'author': [], 'exclude': [], 'fixes': [], 'help': True}))
46
 
        self.assertEqual(parse_args(cmd_commit(), ['--message=biter']),
47
 
           ([], {'author': [], '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'], {'author': [], '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_is_hidden(self):
106
 
        self.assertTrue(option.Option('foo', hidden=True).is_hidden('foo'))
107
 
        self.assertFalse(option.Option('foo', hidden=False).is_hidden('foo'))
108
 
 
109
 
    def test_registry_conversion(self):
110
 
        registry = bzrdir.BzrDirFormatRegistry()
111
 
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
112
 
        registry.register_metadir('two', 'RepositoryFormatKnit1', 'two help')
113
 
        registry.register_metadir('hidden', 'RepositoryFormatKnit1',
114
 
            'two help', hidden=True)
115
 
        registry.set_default('one')
116
 
        options = [option.RegistryOption('format', '', registry, str)]
117
 
        opts, args = self.parse(options, ['--format', 'one'])
118
 
        self.assertEqual({'format':'one'}, opts)
119
 
        opts, args = self.parse(options, ['--format', 'two'])
120
 
        self.assertEqual({'format':'two'}, opts)
121
 
        self.assertRaises(errors.BadOptionValue, self.parse, options,
122
 
                          ['--format', 'three'])
123
 
        self.assertRaises(errors.BzrCommandError, self.parse, options,
124
 
                          ['--two'])
125
 
        options = [option.RegistryOption('format', '', registry, str,
126
 
                   value_switches=True)]
127
 
        opts, args = self.parse(options, ['--two'])
128
 
        self.assertEqual({'format':'two'}, opts)
129
 
        opts, args = self.parse(options, ['--two', '--one'])
130
 
        self.assertEqual({'format':'one'}, opts)
131
 
        opts, args = self.parse(options, ['--two', '--one',
132
 
                                          '--format', 'two'])
133
 
        self.assertEqual({'format':'two'}, opts)
134
 
        options = [option.RegistryOption('format', '', registry, str,
135
 
                   enum_switch=False)]
136
 
        self.assertRaises(errors.BzrCommandError, self.parse, options,
137
 
                          ['--format', 'two'])
138
 
 
139
 
    def test_override(self):
140
 
        options = [option.Option('hello', type=str),
141
 
                   option.Option('hi', type=str, param_name='hello')]
142
 
        opts, args = self.parse(options, ['--hello', 'a', '--hello', 'b'])
143
 
        self.assertEqual('b', opts.hello)
144
 
        opts, args = self.parse(options, ['--hello', 'b', '--hello', 'a'])
145
 
        self.assertEqual('a', opts.hello)
146
 
        opts, args = self.parse(options, ['--hello', 'a', '--hi', 'b'])
147
 
        self.assertEqual('b', opts.hello)
148
 
        opts, args = self.parse(options, ['--hi', 'b', '--hello', 'a'])
149
 
        self.assertEqual('a', opts.hello)
150
 
 
151
 
    def test_registry_converter(self):
152
 
        options = [option.RegistryOption('format', '',
153
 
                   bzrdir.format_registry, bzrdir.format_registry.make_bzrdir)]
154
 
        opts, args = self.parse(options, ['--format', 'knit'])
155
 
        self.assertIsInstance(opts.format.repository_format,
156
 
                              knitrepo.RepositoryFormatKnit1)
157
 
 
158
 
    def test_lazy_registry(self):
159
 
        options = [option.RegistryOption('format', '',
160
 
                   lazy_registry=('bzrlib.bzrdir','format_registry'),
161
 
                   converter=str)]
162
 
        opts, args = self.parse(options, ['--format', 'knit'])
163
 
        self.assertEqual({'format': 'knit'}, opts)
164
 
        self.assertRaises(
165
 
            errors.BadOptionValue, self.parse, options, ['--format', 'BAD'])
166
 
 
167
 
    def test_from_kwargs(self):
168
 
        my_option = option.RegistryOption.from_kwargs('my-option',
169
 
            help='test option', short='be short', be_long='go long')
170
 
        self.assertEqual(['my-option'],
171
 
            [x[0] for x in my_option.iter_switches()])
172
 
        my_option = option.RegistryOption.from_kwargs('my-option',
173
 
            help='test option', title="My option", short='be short',
174
 
            be_long='go long', value_switches=True)
175
 
        self.assertEqual(['my-option', 'be-long', 'short'],
176
 
            [x[0] for x in my_option.iter_switches()])
177
 
        self.assertEqual('test option', my_option.help)
178
 
 
179
 
    def test_help(self):
180
 
        registry = bzrdir.BzrDirFormatRegistry()
181
 
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
182
 
        registry.register_metadir('two',
183
 
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
184
 
            'two help',
185
 
            )
186
 
        registry.register_metadir('hidden', 'RepositoryFormat7', 'hidden help',
187
 
            hidden=True)
188
 
        registry.set_default('one')
189
 
        options = [option.RegistryOption('format', 'format help', registry,
190
 
                   str, value_switches=True, title='Formats')]
191
 
        parser = option.get_optparser(dict((o.name, o) for o in options))
192
 
        value = parser.format_option_help()
193
 
        self.assertContainsRe(value, 'format.*format help')
194
 
        self.assertContainsRe(value, 'one.*one help')
195
 
        self.assertContainsRe(value, 'Formats:\n *--format')
196
 
        self.assertNotContainsRe(value, 'hidden help')
197
 
 
198
 
    def test_iter_switches(self):
199
 
        opt = option.Option('hello', help='fg')
200
 
        self.assertEqual(list(opt.iter_switches()),
201
 
                         [('hello', None, None, 'fg')])
202
 
        opt = option.Option('hello', help='fg', type=int)
203
 
        self.assertEqual(list(opt.iter_switches()),
204
 
                         [('hello', None, 'ARG', 'fg')])
205
 
        opt = option.Option('hello', help='fg', type=int, argname='gar')
206
 
        self.assertEqual(list(opt.iter_switches()),
207
 
                         [('hello', None, 'GAR', 'fg')])
208
 
        registry = bzrdir.BzrDirFormatRegistry()
209
 
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
210
 
        registry.register_metadir('two',
211
 
                'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
212
 
                'two help',
213
 
                )
214
 
        registry.set_default('one')
215
 
        opt = option.RegistryOption('format', 'format help', registry,
216
 
                                    value_switches=False)
217
 
        self.assertEqual(list(opt.iter_switches()),
218
 
                         [('format', None, 'ARG', 'format help')])
219
 
        opt = option.RegistryOption('format', 'format help', registry,
220
 
                                    value_switches=True)
221
 
        self.assertEqual(list(opt.iter_switches()),
222
 
                         [('format', None, 'ARG', 'format help'),
223
 
                          ('default', None, None, 'one help'),
224
 
                          ('one', None, None, 'one help'),
225
 
                          ('two', None, None, 'two help'),
226
 
                          ])
227
 
 
228
 
    def test_option_callback_bool(self):
229
 
        "Test booleans get True and False passed correctly to a callback."""
230
 
        cb_calls = []
231
 
        def cb(option, name, value, parser):
232
 
            cb_calls.append((option,name,value,parser))
233
 
        options = [option.Option('hello', custom_callback=cb)]
234
 
        opts, args = self.parse(options, ['--hello', '--no-hello'])
235
 
        self.assertEqual(2, len(cb_calls))
236
 
        opt,name,value,parser = cb_calls[0]
237
 
        self.assertEqual('hello', name)
238
 
        self.assertTrue(value)
239
 
        opt,name,value,parser = cb_calls[1]
240
 
        self.assertEqual('hello', name)
241
 
        self.assertFalse(value)
242
 
 
243
 
    def test_option_callback_str(self):
244
 
        """Test callbacks work for string options both long and short."""
245
 
        cb_calls = []
246
 
        def cb(option, name, value, parser):
247
 
            cb_calls.append((option,name,value,parser))
248
 
        options = [option.Option('hello', type=str, custom_callback=cb,
249
 
            short_name='h')]
250
 
        opts, args = self.parse(options, ['--hello', 'world', '-h', 'mars'])
251
 
        self.assertEqual(2, len(cb_calls))
252
 
        opt,name,value,parser = cb_calls[0]
253
 
        self.assertEqual('hello', name)
254
 
        self.assertEqual('world', value)
255
 
        opt,name,value,parser = cb_calls[1]
256
 
        self.assertEqual('hello', name)
257
 
        self.assertEqual('mars', value)
258
 
 
259
 
 
260
 
class TestListOptions(TestCase):
261
 
    """Tests for ListOption, used to specify lists on the command-line."""
262
 
 
263
 
    def parse(self, options, args):
264
 
        parser = option.get_optparser(dict((o.name, o) for o in options))
265
 
        return parser.parse_args(args)
266
 
 
267
 
    def test_list_option(self):
268
 
        options = [option.ListOption('hello', type=str)]
269
 
        opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
270
 
        self.assertEqual(['world', 'sailor'], opts.hello)
271
 
 
272
 
    def test_list_option_with_dash(self):
273
 
        options = [option.ListOption('with-dash', type=str)]
274
 
        opts, args = self.parse(options, ['--with-dash=world',
275
 
                                          '--with-dash=sailor'])
276
 
        self.assertEqual(['world', 'sailor'], opts.with_dash)
277
 
 
278
 
    def test_list_option_no_arguments(self):
279
 
        options = [option.ListOption('hello', type=str)]
280
 
        opts, args = self.parse(options, [])
281
 
        self.assertEqual([], opts.hello)
282
 
 
283
 
    def test_list_option_with_int_type(self):
284
 
        options = [option.ListOption('hello', type=int)]
285
 
        opts, args = self.parse(options, ['--hello=2', '--hello=3'])
286
 
        self.assertEqual([2, 3], opts.hello)
287
 
 
288
 
    def test_list_option_with_int_type_can_be_reset(self):
289
 
        options = [option.ListOption('hello', type=int)]
290
 
        opts, args = self.parse(options, ['--hello=2', '--hello=3',
291
 
                                          '--hello=-', '--hello=5'])
292
 
        self.assertEqual([5], opts.hello)
293
 
 
294
 
    def test_list_option_can_be_reset(self):
295
 
        """Passing an option of '-' to a list option should reset the list."""
296
 
        options = [option.ListOption('hello', type=str)]
297
 
        opts, args = self.parse(
298
 
            options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
299
 
        self.assertEqual(['c'], opts.hello)
300
 
 
301
 
    def test_option_callback_list(self):
302
 
        """Test callbacks work for list options."""
303
 
        cb_calls = []
304
 
        def cb(option, name, value, parser):
305
 
            # Note that the value is a reference so copy to keep it
306
 
            cb_calls.append((option,name,value[:],parser))
307
 
        options = [option.ListOption('hello', type=str, custom_callback=cb)]
308
 
        opts, args = self.parse(options, ['--hello=world', '--hello=mars',
309
 
            '--hello=-'])
310
 
        self.assertEqual(3, len(cb_calls))
311
 
        opt,name,value,parser = cb_calls[0]
312
 
        self.assertEqual('hello', name)
313
 
        self.assertEqual(['world'], value)
314
 
        opt,name,value,parser = cb_calls[1]
315
 
        self.assertEqual('hello', name)
316
 
        self.assertEqual(['world', 'mars'], value)
317
 
        opt,name,value,parser = cb_calls[2]
318
 
        self.assertEqual('hello', name)
319
 
        self.assertEqual([], value)
320
 
 
321
 
    def test_list_option_param_name(self):
322
 
        """Test list options can have their param_name set."""
323
 
        options = [option.ListOption('hello', type=str, param_name='greeting')]
324
 
        opts, args = self.parse(
325
 
            options, ['--hello=world', '--hello=sailor'])
326
 
        self.assertEqual(['world', 'sailor'], opts.greeting)
327
 
 
328
 
 
329
 
class TestOptionDefinitions(TestCase):
330
 
    """Tests for options in the Bazaar codebase."""
331
 
 
332
 
    def get_builtin_command_options(self):
333
 
        g = []
334
 
        for cmd_name in sorted(commands.all_command_names()):
335
 
            cmd = commands.get_cmd_object(cmd_name)
336
 
            for opt_name, opt in sorted(cmd.options().items()):
337
 
                g.append((cmd_name, opt))
338
 
        return g
339
 
 
340
 
    def test_global_options_used(self):
341
 
        # In the distant memory, options could only be declared globally.  Now
342
 
        # we prefer to declare them in the command, unless like -r they really
343
 
        # are used very widely with the exact same meaning.  So this checks
344
 
        # for any that should be garbage collected.
345
 
        g = dict(option.Option.OPTIONS.items())
346
 
        used_globals = {}
347
 
        msgs = []
348
 
        for cmd_name in sorted(commands.all_command_names()):
349
 
            cmd = commands.get_cmd_object(cmd_name)
350
 
            for option_or_name in sorted(cmd.takes_options):
351
 
                if not isinstance(option_or_name, basestring):
352
 
                    self.assertIsInstance(option_or_name, option.Option)
353
 
                elif not option_or_name in g:
354
 
                    msgs.append("apparent reference to undefined "
355
 
                        "global option %r from %r"
356
 
                        % (option_or_name, cmd))
357
 
                else:
358
 
                    used_globals.setdefault(option_or_name, []).append(cmd_name)
359
 
        unused_globals = set(g.keys()) - set(used_globals.keys())
360
 
        # not enforced because there might be plugins that use these globals
361
 
        ## for option_name in sorted(unused_globals):
362
 
        ##    msgs.append("unused global option %r" % option_name)
363
 
        ## for option_name, cmds in sorted(used_globals.items()):
364
 
        ##     if len(cmds) <= 1:
365
 
        ##         msgs.append("global option %r is only used by %r"
366
 
        ##                 % (option_name, cmds))
367
 
        if msgs:
368
 
            self.fail("problems with global option definitions:\n"
369
 
                    + '\n'.join(msgs))
370
 
 
371
 
    def test_option_grammar(self):
372
 
        msgs = []
373
 
        # Option help should be written in sentence form, and have a final
374
 
        # period and be all on a single line, because the display code will
375
 
        # wrap it.
376
 
        option_re = re.compile(r'^[A-Z][^\n]+\.$')
377
 
        for scope, opt in self.get_builtin_command_options():
378
 
            if not opt.help:
379
 
                msgs.append('%-16s %-16s %s' %
380
 
                       ((scope or 'GLOBAL'), opt.name, 'NO HELP'))
381
 
            elif not option_re.match(opt.help):
382
 
                msgs.append('%-16s %-16s %s' %
383
 
                        ((scope or 'GLOBAL'), opt.name, opt.help))
384
 
        if msgs:
385
 
            self.fail("The following options don't match the style guide:\n"
386
 
                    + '\n'.join(msgs))
387
 
 
388
 
    def test_is_hidden(self):
389
 
        registry = bzrdir.BzrDirFormatRegistry()
390
 
        registry.register_metadir('hidden', 'HiddenFormat',
391
 
            'hidden help text', hidden=True)
392
 
        registry.register_metadir('visible', 'VisibleFormat',
393
 
            'visible help text', hidden=False)
394
 
        format = option.RegistryOption('format', '', registry, str)
395
 
        self.assertTrue(format.is_hidden('hidden'))
396
 
        self.assertFalse(format.is_hidden('visible'))
397
 
 
398
 
    def test_option_custom_help(self):
399
 
        the_opt = option.Option.OPTIONS['help']
400
 
        orig_help = the_opt.help[:]
401
 
        my_opt = option.custom_help('help', 'suggest lottery numbers')
402
 
        # Confirm that my_opt has my help and the original is unchanged
403
 
        self.assertEqual('suggest lottery numbers', my_opt.help)
404
 
        self.assertEqual(orig_help, the_opt.help)
405
 
 
406
 
 
407
 
class TestVerboseQuietLinkage(TestCase):
408
 
 
409
 
    def check(self, parser, level, args):
410
 
        option._verbosity_level = 0
411
 
        opts, args = parser.parse_args(args)
412
 
        self.assertEqual(level, option._verbosity_level)
413
 
 
414
 
    def test_verbose_quiet_linkage(self):
415
 
        parser = option.get_optparser(option.Option.STD_OPTIONS)
416
 
        self.check(parser, 0, [])
417
 
        self.check(parser, 1, ['-v'])
418
 
        self.check(parser, 2, ['-v', '-v'])
419
 
        self.check(parser, -1, ['-q'])
420
 
        self.check(parser, -2, ['-qq'])
421
 
        self.check(parser, -1, ['-v', '-v', '-q'])
422
 
        self.check(parser, 2, ['-q', '-v', '-v'])
423
 
        self.check(parser, 0, ['--no-verbose'])
424
 
        self.check(parser, 0, ['-v', '-q', '--no-quiet'])