~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_options.py

  • Committer: Martin Pool
  • Date: 2007-07-13 03:37:46 UTC
  • mto: This revision was merged to the branch mainline in revision 2616.
  • Revision ID: mbp@sourcefrog.net-20070713033746-7ujkx3jxbw2gmipl
(Lukas Lalinsky) don't create a duplicate zipimporter, avoiding loading plugins twice

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
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
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import re
18
18
 
19
19
from bzrlib import (
 
20
    builtins,
20
21
    bzrdir,
21
22
    commands,
22
23
    errors,
23
24
    option,
 
25
    repository,
 
26
    symbol_versioning,
24
27
    )
25
 
from bzrlib.builtins import cmd_commit
 
28
from bzrlib.builtins import cmd_commit, cmd_log, cmd_status
26
29
from bzrlib.commands import Command, parse_args
27
30
from bzrlib.tests import TestCase
28
31
from bzrlib.repofmt import knitrepo
38
41
 
39
42
    def test_parse_args(self):
40
43
        """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'}))
 
44
        eq = self.assertEquals
 
45
        eq(parse_args(cmd_commit(), ['--help']),
 
46
           ([], {'fixes': [], 'help': True}))
 
47
        eq(parse_args(cmd_commit(), ['--message=biter']),
 
48
           ([], {'fixes': [], 'message': 'biter'}))
48
49
 
49
50
    def test_no_more_opts(self):
50
51
        """Terminated options"""
51
 
        self.assertEqual(parse_args(cmd_commit(), ['--', '-file-with-dashes']),
52
 
                          (['-file-with-dashes'], {'author': [], 'exclude': [], 'fixes': []}))
 
52
        self.assertEquals(parse_args(cmd_commit(), ['--', '-file-with-dashes']),
 
53
                          (['-file-with-dashes'], {'fixes': []}))
53
54
 
54
55
    def test_option_help(self):
55
56
        """Options have help strings."""
66
67
    def test_option_arg_help(self):
67
68
        """Help message shows option arguments."""
68
69
        out, err = self.run_bzr('help commit')
69
 
        self.assertEqual(err, '')
 
70
        self.assertEquals(err, '')
70
71
        self.assertContainsRe(out, r'--file[ =]MSGFILE')
71
72
 
72
73
    def test_unknown_short_opt(self):
80
81
 
81
82
    def test_allow_dash(self):
82
83
        """Test that we can pass a plain '-' as an argument."""
83
 
        self.assertEqual((['-']), parse_args(cmd_commit(), ['-'])[0])
 
84
        self.assertEqual(
 
85
            (['-'], {'fixes': []}), parse_args(cmd_commit(), ['-']))
84
86
 
85
87
    def parse(self, options, args):
86
88
        parser = option.get_optparser(dict((o.name, o) for o in options))
91
93
        opts, args = self.parse(options, ['--no-hello', '--hello'])
92
94
        self.assertEqual(True, opts.hello)
93
95
        opts, args = self.parse(options, [])
94
 
        self.assertFalse(hasattr(opts, 'hello'))
 
96
        self.assertEqual(option.OptionParser.DEFAULT_VALUE, opts.hello)
95
97
        opts, args = self.parse(options, ['--hello', '--no-hello'])
96
98
        self.assertEqual(False, opts.hello)
97
99
        options = [option.Option('number', type=int)]
102
104
        self.assertRaises(errors.BzrCommandError, self.parse, options,
103
105
                          ['--no-number'])
104
106
 
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
107
    def test_registry_conversion(self):
110
108
        registry = bzrdir.BzrDirFormatRegistry()
111
109
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
136
134
        self.assertRaises(errors.BzrCommandError, self.parse, options,
137
135
                          ['--format', 'two'])
138
136
 
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
137
    def test_registry_converter(self):
152
138
        options = [option.RegistryOption('format', '',
153
139
                   bzrdir.format_registry, bzrdir.format_registry.make_bzrdir)]
155
141
        self.assertIsInstance(opts.format.repository_format,
156
142
                              knitrepo.RepositoryFormatKnit1)
157
143
 
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
144
    def test_from_kwargs(self):
168
145
        my_option = option.RegistryOption.from_kwargs('my-option',
169
146
            help='test option', short='be short', be_long='go long')
174
151
            be_long='go long', value_switches=True)
175
152
        self.assertEqual(['my-option', 'be-long', 'short'],
176
153
            [x[0] for x in my_option.iter_switches()])
177
 
        self.assertEqual('test option', my_option.help)
178
154
 
179
155
    def test_help(self):
180
156
        registry = bzrdir.BzrDirFormatRegistry()
225
201
                          ('two', None, None, 'two help'),
226
202
                          ])
227
203
 
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
204
 
260
205
class TestListOptions(TestCase):
261
206
    """Tests for ListOption, used to specify lists on the command-line."""
269
214
        opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
270
215
        self.assertEqual(['world', 'sailor'], opts.hello)
271
216
 
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
217
    def test_list_option_no_arguments(self):
279
218
        options = [option.ListOption('hello', type=str)]
280
219
        opts, args = self.parse(options, [])
298
237
            options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
299
238
        self.assertEqual(['c'], opts.hello)
300
239
 
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
240
 
329
241
class TestOptionDefinitions(TestCase):
330
242
    """Tests for options in the Bazaar codebase."""
331
243
 
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)
 
244
    def get_all_options(self):
 
245
        """Return a list of all options used by Bazaar, both global and command.
 
246
        
 
247
        The list returned contains elements of (scope, option) where 'scope' 
 
248
        is either None for global options, or a command name.
 
249
 
 
250
        This includes options provided by plugins.
 
251
        """
 
252
        g = [(None, opt) for name, opt
 
253
             in sorted(option.Option.OPTIONS.items())]
 
254
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
 
255
            cmd = cmd_class()
336
256
            for opt_name, opt in sorted(cmd.options().items()):
337
257
                g.append((cmd_name, opt))
338
258
        return g
339
259
 
 
260
    def test_get_all_options(self):
 
261
        all = self.get_all_options()
 
262
        self.assertTrue(len(all) > 100,
 
263
                "too few options found: %r" % all)
 
264
 
340
265
    def test_global_options_used(self):
341
266
        # In the distant memory, options could only be declared globally.  Now
342
267
        # we prefer to declare them in the command, unless like -r they really
345
270
        g = dict(option.Option.OPTIONS.items())
346
271
        used_globals = {}
347
272
        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):
 
273
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
 
274
            for option_or_name in sorted(cmd_class.takes_options):
351
275
                if not isinstance(option_or_name, basestring):
352
276
                    self.assertIsInstance(option_or_name, option.Option)
353
277
                elif not option_or_name in g:
354
278
                    msgs.append("apparent reference to undefined "
355
279
                        "global option %r from %r"
356
 
                        % (option_or_name, cmd))
 
280
                        % (option_or_name, cmd_class))
357
281
                else:
358
282
                    used_globals.setdefault(option_or_name, []).append(cmd_name)
359
283
        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))
 
284
        for option_name in sorted(unused_globals):
 
285
            msgs.append("unused global option %r" % option_name)
 
286
        for option_name, cmds in sorted(used_globals.items()):
 
287
            if len(cmds) <= 1:
 
288
                msgs.append("global option %r is only used by %r"
 
289
                        % (option_name, cmds))
367
290
        if msgs:
368
291
            self.fail("problems with global option definitions:\n"
369
292
                    + '\n'.join(msgs))
374
297
        # period and be all on a single line, because the display code will
375
298
        # wrap it.
376
299
        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))
 
300
        for scope, option in self.get_all_options():
 
301
            if not option.help:
 
302
                msgs.append('%-16s %-16s %s' %
 
303
                       ((scope or 'GLOBAL'), option.name, 'NO HELP'))
 
304
            elif not option_re.match(option.help):
 
305
                msgs.append('%-16s %-16s %s' %
 
306
                        ((scope or 'GLOBAL'), option.name, option.help))
384
307
        if msgs:
385
308
            self.fail("The following options don't match the style guide:\n"
386
309
                    + '\n'.join(msgs))
387
310
 
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'])
 
311
    # TODO: Scan for global options that aren't used by any command?
 
312
    #
 
313
    # TODO: Check that there are two spaces between sentences.