/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: Robert Collins
  • Date: 2007-09-19 05:14:14 UTC
  • mto: (2835.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2836.
  • Revision ID: robertc@robertcollins.net-20070919051414-2tgjqteg7k3ps4h0
* ``pull``, ``merge`` and ``push`` will no longer silently correct some
  repository index errors that occured as a result of the Weave disk format.
  Instead the ``reconcile`` command needs to be run to correct those
  problems if they exist (and it has been able to fix most such problems
  since bzr 0.8). Some new problems have been identified during this release
  and you should run ``bzr check`` once on every repository to see if you
  need to reconcile. If you cannot ``pull`` or ``merge`` from a remote
  repository due to mismatched parent errors - a symptom of index errors -
  you should simply take a full copy of that remote repository to a clean
  directory outside any local repositories, then run reconcile on it, and
  finally pull from it locally. (And naturally email the repositories owner
  to ask them to upgrade and run reconcile).
  (Robert Collins)

* ``VersionedFile.fix_parents`` has been removed as a harmful API.
  ``VersionedFile.join`` will no longer accept different parents on either
  side of a join - it will either ignore them, or error, depending on the
  implementation. See notes when upgrading for more information.
  (Robert Collins)

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