41
11
def test_parse_args(self):
42
12
"""Option parser"""
43
# XXX: Using cmd_commit makes these tests overly sensitive to changes
44
# to cmd_commit, when they are meant to be about option parsing in
47
([], {'author': [], 'exclude': [], 'fixes': [], 'help': True,
49
parse_args(cmd_commit(), ['--help']))
51
([], {'author': [], 'exclude': [], 'fixes': [], 'message': 'biter',
53
parse_args(cmd_commit(), ['--message=biter']))
13
eq = self.assertEquals
14
eq(parse_args(cmd_commit(), ['--help']),
16
eq(parse_args(cmd_status(), ['--all']),
18
eq(parse_args(cmd_commit(), ['--message=biter']),
19
([], {'message': 'biter'}))
20
## eq(parse_args(cmd_log(), '-r 500'.split()),
21
## ([], {'revision': RevisionSpec_int(500)}))
55
23
def test_no_more_opts(self):
56
24
"""Terminated options"""
58
(['-file-with-dashes'], {
59
'author': [], 'exclude': [], 'fixes': [], 'bugs': []}),
60
parse_args(cmd_commit(), ['--', '-file-with-dashes']))
25
self.assertEquals(parse_args(cmd_commit(), ['--', '-file-with-dashes']),
26
(['-file-with-dashes'], {}))
62
28
def test_option_help(self):
63
29
"""Options have help strings."""
64
out, err = self.run_bzr('commit --help')
65
self.assertContainsRe(out,
66
r'--file(.|\n)*Take commit message from this file\.')
67
self.assertContainsRe(out, r'-h.*--help')
30
out, err = self.run_bzr_captured(['commit', '--help'])
31
self.assertContainsRe(out, r'--file.*file containing commit message')
32
self.assertContainsRe(out, r'--help.*-h')
69
34
def test_option_help_global(self):
70
35
"""Global options have help strings."""
71
out, err = self.run_bzr('help status')
72
self.assertContainsRe(out, r'--show-ids.*Show internal object.')
74
def test_option_help_global_hidden(self):
75
"""Hidden global options have no help strings."""
76
out, err = self.run_bzr('help log')
77
self.assertNotContainsRe(out, r'--message')
36
out, err = self.run_bzr_captured(['help', 'status'])
37
self.assertContainsRe(out, r'--show-ids.*show internal object')
79
39
def test_option_arg_help(self):
80
40
"""Help message shows option arguments."""
81
out, err = self.run_bzr('help commit')
82
self.assertEqual(err, '')
41
out, err = self.run_bzr_captured(['help', 'commit'])
42
self.assertEquals(err, '')
83
43
self.assertContainsRe(out, r'--file[ =]MSGFILE')
85
45
def test_unknown_short_opt(self):
86
out, err = self.run_bzr('help -r', retcode=3)
87
self.assertContainsRe(err, r'no such option')
89
def test_set_short_name(self):
90
o = option.Option('wiggle')
92
self.assertEqual(o.short_name(), 'w')
94
def test_allow_dash(self):
95
"""Test that we can pass a plain '-' as an argument."""
96
self.assertEqual((['-']), parse_args(cmd_commit(), ['-'])[0])
98
def parse(self, options, args):
99
parser = option.get_optparser(options)
100
return parser.parse_args(args)
102
def test_conversion(self):
103
options = [option.Option('hello')]
104
opts, args = self.parse(options, ['--no-hello', '--hello'])
105
self.assertEqual(True, opts.hello)
106
opts, args = self.parse(options, [])
107
self.assertFalse(hasattr(opts, 'hello'))
108
opts, args = self.parse(options, ['--hello', '--no-hello'])
109
self.assertEqual(False, opts.hello)
110
options = [option.Option('number', type=int)]
111
opts, args = self.parse(options, ['--number', '6'])
112
self.assertEqual(6, opts.number)
113
self.assertRaises(errors.BzrCommandError, self.parse, options,
115
self.assertRaises(errors.BzrCommandError, self.parse, options,
117
self.assertRaises(errors.BzrCommandError, self.parse, options,
120
def test_is_hidden(self):
121
self.assertTrue(option.Option('foo', hidden=True).is_hidden('foo'))
122
self.assertFalse(option.Option('foo', hidden=False).is_hidden('foo'))
124
def test_registry_conversion(self):
125
registry = controldir.ControlDirFormatRegistry()
126
bzr.register_metadir(registry, 'one', 'RepositoryFormat7', 'one help')
127
bzr.register_metadir(
128
registry, 'two', 'RepositoryFormatKnit1', 'two help')
129
bzr.register_metadir(registry, 'hidden', 'RepositoryFormatKnit1',
130
'two help', hidden=True)
131
registry.set_default('one')
132
options = [option.RegistryOption('format', '', registry, str)]
133
opts, args = self.parse(options, ['--format', 'one'])
134
self.assertEqual({'format': 'one'}, opts)
135
opts, args = self.parse(options, ['--format', 'two'])
136
self.assertEqual({'format': 'two'}, opts)
137
self.assertRaises(option.BadOptionValue, self.parse, options,
138
['--format', 'three'])
139
self.assertRaises(errors.BzrCommandError, self.parse, options,
141
options = [option.RegistryOption('format', '', registry, str,
142
value_switches=True)]
143
opts, args = self.parse(options, ['--two'])
144
self.assertEqual({'format': 'two'}, opts)
145
opts, args = self.parse(options, ['--two', '--one'])
146
self.assertEqual({'format': 'one'}, opts)
147
opts, args = self.parse(options, ['--two', '--one',
149
self.assertEqual({'format': 'two'}, opts)
150
options = [option.RegistryOption('format', '', registry, str,
152
self.assertRaises(errors.BzrCommandError, self.parse, options,
155
def test_override(self):
156
options = [option.Option('hello', type=str),
157
option.Option('hi', type=str, param_name='hello')]
158
opts, args = self.parse(options, ['--hello', 'a', '--hello', 'b'])
159
self.assertEqual('b', opts.hello)
160
opts, args = self.parse(options, ['--hello', 'b', '--hello', 'a'])
161
self.assertEqual('a', opts.hello)
162
opts, args = self.parse(options, ['--hello', 'a', '--hi', 'b'])
163
self.assertEqual('b', opts.hello)
164
opts, args = self.parse(options, ['--hi', 'b', '--hello', 'a'])
165
self.assertEqual('a', opts.hello)
167
def test_registry_converter(self):
168
options = [option.RegistryOption('format', '',
169
controldir.format_registry, controldir.format_registry.make_controldir)]
170
opts, args = self.parse(options, ['--format', 'knit'])
171
self.assertIsInstance(opts.format.repository_format,
172
knitrepo.RepositoryFormatKnit1)
174
def test_lazy_registry(self):
175
options = [option.RegistryOption('format', '',
177
'breezy.controldir', 'format_registry'),
179
opts, args = self.parse(options, ['--format', 'knit'])
180
self.assertEqual({'format': 'knit'}, opts)
182
option.BadOptionValue, self.parse, options, ['--format', 'BAD'])
184
def test_from_kwargs(self):
185
my_option = option.RegistryOption.from_kwargs('my-option',
186
help='test option', short='be short', be_long='go long')
187
self.assertEqual(['my-option'],
188
[x[0] for x in my_option.iter_switches()])
189
my_option = option.RegistryOption.from_kwargs('my-option',
190
help='test option', title="My option", short='be short',
191
be_long='go long', value_switches=True)
192
self.assertEqual(['my-option', 'be-long', 'short'],
193
[x[0] for x in my_option.iter_switches()])
194
self.assertEqual('test option', my_option.help)
197
registry = controldir.ControlDirFormatRegistry()
198
bzr.register_metadir(registry, 'one', 'RepositoryFormat7', 'one help')
199
bzr.register_metadir(registry, 'two',
200
'breezy.bzr.knitrepo.RepositoryFormatKnit1',
203
bzr.register_metadir(registry, 'hidden', 'RepositoryFormat7', 'hidden help',
205
registry.set_default('one')
206
options = [option.RegistryOption('format', 'format help', registry,
207
str, value_switches=True, title='Formats')]
208
parser = option.get_optparser(options)
209
value = parser.format_option_help()
210
self.assertContainsRe(value, 'format.*format help')
211
self.assertContainsRe(value, 'one.*one help')
212
self.assertContainsRe(value, 'Formats:\n *--format')
213
self.assertNotContainsRe(value, 'hidden help')
215
def test_iter_switches(self):
216
opt = option.Option('hello', help='fg')
217
self.assertEqual(list(opt.iter_switches()),
218
[('hello', None, None, 'fg')])
219
opt = option.Option('hello', help='fg', type=int)
220
self.assertEqual(list(opt.iter_switches()),
221
[('hello', None, 'ARG', 'fg')])
222
opt = option.Option('hello', help='fg', type=int, argname='gar')
223
self.assertEqual(list(opt.iter_switches()),
224
[('hello', None, 'GAR', 'fg')])
225
registry = controldir.ControlDirFormatRegistry()
226
bzr.register_metadir(registry, 'one', 'RepositoryFormat7', 'one help')
227
bzr.register_metadir(registry, 'two',
228
'breezy.bzr.knitrepo.RepositoryFormatKnit1',
231
registry.set_default('one')
232
opt = option.RegistryOption('format', 'format help', registry,
233
value_switches=False)
234
self.assertEqual(list(opt.iter_switches()),
235
[('format', None, 'ARG', 'format help')])
236
opt = option.RegistryOption('format', 'format help', registry,
238
self.assertEqual(list(opt.iter_switches()),
239
[('format', None, 'ARG', 'format help'),
240
('default', None, None, 'one help'),
241
('one', None, None, 'one help'),
242
('two', None, None, 'two help'),
245
def test_option_callback_bool(self):
246
"Test booleans get True and False passed correctly to a callback."""
249
def cb(option, name, value, parser):
250
cb_calls.append((option, name, value, parser))
251
options = [option.Option('hello', custom_callback=cb)]
252
opts, args = self.parse(options, ['--hello', '--no-hello'])
253
self.assertEqual(2, len(cb_calls))
254
opt, name, value, parser = cb_calls[0]
255
self.assertEqual('hello', name)
256
self.assertTrue(value)
257
opt, name, value, parser = cb_calls[1]
258
self.assertEqual('hello', name)
259
self.assertFalse(value)
261
def test_option_callback_str(self):
262
"""Test callbacks work for string options both long and short."""
265
def cb(option, name, value, parser):
266
cb_calls.append((option, name, value, parser))
267
options = [option.Option('hello', type=str, custom_callback=cb,
269
opts, args = self.parse(options, ['--hello', 'world', '-h', 'mars'])
270
self.assertEqual(2, len(cb_calls))
271
opt, name, value, parser = cb_calls[0]
272
self.assertEqual('hello', name)
273
self.assertEqual('world', value)
274
opt, name, value, parser = cb_calls[1]
275
self.assertEqual('hello', name)
276
self.assertEqual('mars', value)
279
class TestListOptions(TestCase):
280
"""Tests for ListOption, used to specify lists on the command-line."""
282
def parse(self, options, args):
283
parser = option.get_optparser(options)
284
return parser.parse_args(args)
286
def test_list_option(self):
287
options = [option.ListOption('hello', type=str)]
288
opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
289
self.assertEqual(['world', 'sailor'], opts.hello)
291
def test_list_option_with_dash(self):
292
options = [option.ListOption('with-dash', type=str)]
293
opts, args = self.parse(options, ['--with-dash=world',
294
'--with-dash=sailor'])
295
self.assertEqual(['world', 'sailor'], opts.with_dash)
297
def test_list_option_no_arguments(self):
298
options = [option.ListOption('hello', type=str)]
299
opts, args = self.parse(options, [])
300
self.assertEqual([], opts.hello)
302
def test_list_option_with_int_type(self):
303
options = [option.ListOption('hello', type=int)]
304
opts, args = self.parse(options, ['--hello=2', '--hello=3'])
305
self.assertEqual([2, 3], opts.hello)
307
def test_list_option_with_int_type_can_be_reset(self):
308
options = [option.ListOption('hello', type=int)]
309
opts, args = self.parse(options, ['--hello=2', '--hello=3',
310
'--hello=-', '--hello=5'])
311
self.assertEqual([5], opts.hello)
313
def test_list_option_can_be_reset(self):
314
"""Passing an option of '-' to a list option should reset the list."""
315
options = [option.ListOption('hello', type=str)]
316
opts, args = self.parse(
317
options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
318
self.assertEqual(['c'], opts.hello)
320
def test_option_callback_list(self):
321
"""Test callbacks work for list options."""
324
def cb(option, name, value, parser):
325
# Note that the value is a reference so copy to keep it
326
cb_calls.append((option, name, value[:], parser))
327
options = [option.ListOption('hello', type=str, custom_callback=cb)]
328
opts, args = self.parse(options, ['--hello=world', '--hello=mars',
330
self.assertEqual(3, len(cb_calls))
331
opt, name, value, parser = cb_calls[0]
332
self.assertEqual('hello', name)
333
self.assertEqual(['world'], value)
334
opt, name, value, parser = cb_calls[1]
335
self.assertEqual('hello', name)
336
self.assertEqual(['world', 'mars'], value)
337
opt, name, value, parser = cb_calls[2]
338
self.assertEqual('hello', name)
339
self.assertEqual([], value)
341
def test_list_option_param_name(self):
342
"""Test list options can have their param_name set."""
343
options = [option.ListOption('hello', type=str, param_name='greeting')]
344
opts, args = self.parse(
345
options, ['--hello=world', '--hello=sailor'])
346
self.assertEqual(['world', 'sailor'], opts.greeting)
349
class TestOptionDefinitions(TestCase):
350
"""Tests for options in the Bazaar codebase."""
352
def get_builtin_command_options(self):
354
commands.install_bzr_command_hooks()
355
for cmd_name in sorted(commands.builtin_command_names()):
356
cmd = commands.get_cmd_object(cmd_name)
357
for opt_name, opt in sorted(cmd.options().items()):
358
g.append((cmd_name, opt))
362
def test_option_grammar(self):
364
# Option help should be written in sentence form, and have a final
365
# period with an optional bracketed suffix. All the text should be on
366
# one line, because the display code will wrap it.
367
option_re = re.compile(r'^[A-Z][^\n]+\.(?: \([^\n]+\))?$')
368
for scope, opt in self.get_builtin_command_options():
369
for name, _, _, helptxt in opt.iter_switches():
371
name = "/".join([opt.name, name])
373
msgs.append('%-16s %-16s %s' %
374
((scope or 'GLOBAL'), name, 'NO HELP'))
375
elif not option_re.match(helptxt):
376
if name.startswith("format/"):
377
# Don't complain about the odd format registry help
379
msgs.append('%-16s %-16s %s' %
380
((scope or 'GLOBAL'), name, helptxt))
382
self.fail("The following options don't match the style guide:\n"
386
class TestOptionMisc(TestCase):
388
def test_is_hidden(self):
389
registry = controldir.ControlDirFormatRegistry()
390
bzr.register_metadir(registry, 'hidden', 'HiddenFormat',
391
'hidden help text', hidden=True)
392
bzr.register_metadir(registry, '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'))
398
def test_short_name(self):
399
registry = controldir.ControlDirFormatRegistry()
400
opt = option.RegistryOption('format', help='', registry=registry)
401
self.assertEqual(None, opt.short_name())
402
opt = option.RegistryOption('format', short_name='F', help='',
404
self.assertEqual('F', opt.short_name())
406
def test_option_custom_help(self):
407
the_opt = option.Option.OPTIONS['help']
408
orig_help = the_opt.help[:]
409
my_opt = option.custom_help('help', 'suggest lottery numbers')
410
# Confirm that my_opt has my help and the original is unchanged
411
self.assertEqual('suggest lottery numbers', my_opt.help)
412
self.assertEqual(orig_help, the_opt.help)
414
def test_short_value_switches(self):
415
reg = registry.Registry()
416
reg.register('short', 'ShortChoice')
417
reg.register('long', 'LongChoice')
418
ropt = option.RegistryOption('choice', '', reg, value_switches=True,
419
short_value_switches={'short': 's'})
420
opts, args = parse([ropt], ['--short'])
421
self.assertEqual('ShortChoice', opts.choice)
422
opts, args = parse([ropt], ['-s'])
423
self.assertEqual('ShortChoice', opts.choice)
426
class TestVerboseQuietLinkage(TestCase):
428
def check(self, parser, level, args):
429
option._verbosity_level = 0
430
opts, args = parser.parse_args(args)
431
self.assertEqual(level, option._verbosity_level)
433
def test_verbose_quiet_linkage(self):
434
parser = option.get_optparser(
435
[v for k, v in sorted(option.Option.STD_OPTIONS.items())])
436
self.check(parser, 0, [])
437
self.check(parser, 1, ['-v'])
438
self.check(parser, 2, ['-v', '-v'])
439
self.check(parser, -1, ['-q'])
440
self.check(parser, -2, ['-qq'])
441
self.check(parser, -1, ['-v', '-v', '-q'])
442
self.check(parser, 2, ['-q', '-v', '-v'])
443
self.check(parser, 0, ['--no-verbose'])
444
self.check(parser, 0, ['-v', '-q', '--no-quiet'])
46
out, err = self.run_bzr_captured(['help', '-r'], retcode=3)
47
self.assertContainsRe(err, r'unknown short option')
50
# >>> parse_args('log -r 500'.split())
51
# (['log'], {'revision': [<RevisionSpec_int 500>]})
52
# >>> parse_args('log -r500..600'.split())
53
# (['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
54
# >>> parse_args('log -vr500..600'.split())
55
# (['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
56
# >>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
57
# (['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})