~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-11 06:47:30 UTC
  • mto: This revision was merged to the branch mainline in revision 2612.
  • Revision ID: mbp@sourcefrog.net-20070711064730-pwnhisgp2caf7nar
Don't show dots progress indicatiors in noninteractive mode

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_get_short_name(self):
 
78
        file_opt = option.Option.OPTIONS['file']
 
79
        self.assertEquals(file_opt.short_name(), 'F')
 
80
        force_opt = option.Option.OPTIONS['force']
 
81
        self.assertEquals(force_opt.short_name(), None)
 
82
 
 
83
    def test_set_short_name(self):
 
84
        o = option.Option('wiggle')
 
85
        o.set_short_name('w')
 
86
        self.assertEqual(o.short_name(), 'w')
 
87
 
 
88
    def test_old_short_names(self):
 
89
        # test the deprecated method for getting and setting short option
 
90
        # names
 
91
        expected_warning = (
 
92
            "access to SHORT_OPTIONS was deprecated in version 0.14."
 
93
            " Set the short option name when constructing the Option.",
 
94
            DeprecationWarning, 2)
 
95
        _warnings = []
 
96
        def capture_warning(message, category, stacklevel=None):
 
97
            _warnings.append((message, category, stacklevel))
 
98
        old_warning_method = symbol_versioning.warn
 
99
        try:
 
100
            # an example of the kind of thing plugins might want to do through
 
101
            # the old interface - make a new option and then give it a short
 
102
            # name.
 
103
            symbol_versioning.set_warning_method(capture_warning)
 
104
            example_opt = option.Option('example', help='example option')
 
105
            option.Option.SHORT_OPTIONS['w'] = example_opt
 
106
            self.assertEqual(example_opt.short_name(), 'w')
 
107
            self.assertEqual([expected_warning], _warnings)
 
108
            # now check that it can actually be parsed with the registered
 
109
            # value
 
110
            opts, args = parse([example_opt], ['-w', 'foo'])
 
111
            self.assertEqual(opts.example, True)
 
112
            self.assertEqual(args, ['foo'])
 
113
        finally:
 
114
            symbol_versioning.set_warning_method(old_warning_method)
 
115
 
 
116
    def test_allow_dash(self):
 
117
        """Test that we can pass a plain '-' as an argument."""
 
118
        self.assertEqual(
 
119
            (['-'], {'fixes': []}), parse_args(cmd_commit(), ['-']))
 
120
 
 
121
    def parse(self, options, args):
 
122
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
123
        return parser.parse_args(args)
 
124
 
 
125
    def test_conversion(self):
 
126
        options = [option.Option('hello')]
 
127
        opts, args = self.parse(options, ['--no-hello', '--hello'])
 
128
        self.assertEqual(True, opts.hello)
 
129
        opts, args = self.parse(options, [])
 
130
        self.assertEqual(option.OptionParser.DEFAULT_VALUE, opts.hello)
 
131
        opts, args = self.parse(options, ['--hello', '--no-hello'])
 
132
        self.assertEqual(False, opts.hello)
 
133
        options = [option.Option('number', type=int)]
 
134
        opts, args = self.parse(options, ['--number', '6'])
 
135
        self.assertEqual(6, opts.number)
 
136
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
137
                          ['--number'])
 
138
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
139
                          ['--no-number'])
 
140
 
 
141
    def test_registry_conversion(self):
 
142
        registry = bzrdir.BzrDirFormatRegistry()
 
143
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
144
        registry.register_metadir('two', 'RepositoryFormatKnit1', 'two help')
 
145
        registry.register_metadir('hidden', 'RepositoryFormatKnit1',
 
146
            'two help', hidden=True)
 
147
        registry.set_default('one')
 
148
        options = [option.RegistryOption('format', '', registry, str)]
 
149
        opts, args = self.parse(options, ['--format', 'one'])
 
150
        self.assertEqual({'format':'one'}, opts)
 
151
        opts, args = self.parse(options, ['--format', 'two'])
 
152
        self.assertEqual({'format':'two'}, opts)
 
153
        self.assertRaises(errors.BadOptionValue, self.parse, options,
 
154
                          ['--format', 'three'])
 
155
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
156
                          ['--two'])
 
157
        options = [option.RegistryOption('format', '', registry, str,
 
158
                   value_switches=True)]
 
159
        opts, args = self.parse(options, ['--two'])
 
160
        self.assertEqual({'format':'two'}, opts)
 
161
        opts, args = self.parse(options, ['--two', '--one'])
 
162
        self.assertEqual({'format':'one'}, opts)
 
163
        opts, args = self.parse(options, ['--two', '--one',
 
164
                                          '--format', 'two'])
 
165
        self.assertEqual({'format':'two'}, opts)
 
166
        options = [option.RegistryOption('format', '', registry, str,
 
167
                   enum_switch=False)]
 
168
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
169
                          ['--format', 'two'])
 
170
 
 
171
    def test_registry_converter(self):
 
172
        options = [option.RegistryOption('format', '',
 
173
                   bzrdir.format_registry, bzrdir.format_registry.make_bzrdir)]
 
174
        opts, args = self.parse(options, ['--format', 'knit'])
 
175
        self.assertIsInstance(opts.format.repository_format,
 
176
                              knitrepo.RepositoryFormatKnit1)
 
177
 
 
178
    def test_from_kwargs(self):
 
179
        my_option = option.RegistryOption.from_kwargs('my-option',
 
180
            help='test option', short='be short', be_long='go long')
 
181
        self.assertEqual(['my-option'],
 
182
            [x[0] for x in my_option.iter_switches()])
 
183
        my_option = option.RegistryOption.from_kwargs('my-option',
 
184
            help='test option', title="My option", short='be short',
 
185
            be_long='go long', value_switches=True)
 
186
        self.assertEqual(['my-option', 'be-long', 'short'],
 
187
            [x[0] for x in my_option.iter_switches()])
 
188
 
 
189
    def test_help(self):
 
190
        registry = bzrdir.BzrDirFormatRegistry()
 
191
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
192
        registry.register_metadir('two',
 
193
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
194
            'two help',
 
195
            )
 
196
        registry.register_metadir('hidden', 'RepositoryFormat7', 'hidden help',
 
197
            hidden=True)
 
198
        registry.set_default('one')
 
199
        options = [option.RegistryOption('format', 'format help', registry,
 
200
                   str, value_switches=True, title='Formats')]
 
201
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
202
        value = parser.format_option_help()
 
203
        self.assertContainsRe(value, 'format.*format help')
 
204
        self.assertContainsRe(value, 'one.*one help')
 
205
        self.assertContainsRe(value, 'Formats:\n *--format')
 
206
        self.assertNotContainsRe(value, 'hidden help')
 
207
 
 
208
    def test_iter_switches(self):
 
209
        opt = option.Option('hello', help='fg')
 
210
        self.assertEqual(list(opt.iter_switches()),
 
211
                         [('hello', None, None, 'fg')])
 
212
        opt = option.Option('hello', help='fg', type=int)
 
213
        self.assertEqual(list(opt.iter_switches()),
 
214
                         [('hello', None, 'ARG', 'fg')])
 
215
        opt = option.Option('hello', help='fg', type=int, argname='gar')
 
216
        self.assertEqual(list(opt.iter_switches()),
 
217
                         [('hello', None, 'GAR', 'fg')])
 
218
        registry = bzrdir.BzrDirFormatRegistry()
 
219
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
 
220
        registry.register_metadir('two',
 
221
                'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
222
                'two help',
 
223
                )
 
224
        registry.set_default('one')
 
225
        opt = option.RegistryOption('format', 'format help', registry,
 
226
                                    value_switches=False)
 
227
        self.assertEqual(list(opt.iter_switches()),
 
228
                         [('format', None, 'ARG', 'format help')])
 
229
        opt = option.RegistryOption('format', 'format help', registry,
 
230
                                    value_switches=True)
 
231
        self.assertEqual(list(opt.iter_switches()),
 
232
                         [('format', None, 'ARG', 'format help'),
 
233
                          ('default', None, None, 'one help'),
 
234
                          ('one', None, None, 'one help'),
 
235
                          ('two', None, None, 'two help'),
 
236
                          ])
 
237
 
 
238
 
 
239
class TestListOptions(TestCase):
 
240
    """Tests for ListOption, used to specify lists on the command-line."""
 
241
 
 
242
    def parse(self, options, args):
 
243
        parser = option.get_optparser(dict((o.name, o) for o in options))
 
244
        return parser.parse_args(args)
 
245
 
 
246
    def test_list_option(self):
 
247
        options = [option.ListOption('hello', type=str)]
 
248
        opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
 
249
        self.assertEqual(['world', 'sailor'], opts.hello)
 
250
 
 
251
    def test_list_option_no_arguments(self):
 
252
        options = [option.ListOption('hello', type=str)]
 
253
        opts, args = self.parse(options, [])
 
254
        self.assertEqual([], opts.hello)
 
255
 
 
256
    def test_list_option_with_int_type(self):
 
257
        options = [option.ListOption('hello', type=int)]
 
258
        opts, args = self.parse(options, ['--hello=2', '--hello=3'])
 
259
        self.assertEqual([2, 3], opts.hello)
 
260
 
 
261
    def test_list_option_with_int_type_can_be_reset(self):
 
262
        options = [option.ListOption('hello', type=int)]
 
263
        opts, args = self.parse(options, ['--hello=2', '--hello=3',
 
264
                                          '--hello=-', '--hello=5'])
 
265
        self.assertEqual([5], opts.hello)
 
266
 
 
267
    def test_list_option_can_be_reset(self):
 
268
        """Passing an option of '-' to a list option should reset the list."""
 
269
        options = [option.ListOption('hello', type=str)]
 
270
        opts, args = self.parse(
 
271
            options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
 
272
        self.assertEqual(['c'], opts.hello)
 
273
 
 
274
 
 
275
class TestOptionDefinitions(TestCase):
 
276
    """Tests for options in the Bazaar codebase."""
 
277
 
 
278
    def get_all_options(self):
 
279
        """Return a list of all options used by Bazaar, both global and command.
 
280
        
 
281
        The list returned contains elements of (scope, option) where 'scope' 
 
282
        is either None for global options, or a command name.
 
283
 
 
284
        This includes options provided by plugins.
 
285
        """
 
286
        g = [(None, opt) for name, opt
 
287
             in sorted(option.Option.OPTIONS.items())]
 
288
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
 
289
            cmd = cmd_class()
 
290
            for opt_name, opt in sorted(cmd.options().items()):
 
291
                g.append((cmd_name, opt))
 
292
        return g
 
293
 
 
294
    def test_get_all_options(self):
 
295
        all = self.get_all_options()
 
296
        self.assertTrue(len(all) > 100,
 
297
                "too few options found: %r" % all)
 
298
 
 
299
    def test_option_grammar(self):
 
300
        msgs = []
 
301
        # Option help should be written in sentence form, and have a final
 
302
        # period and be all on a single line, because the display code will
 
303
        # wrap it.
 
304
        option_re = re.compile(r'^[A-Z][^\n]+\.$')
 
305
        for scope, option in self.get_all_options():
 
306
            if not option.help:
 
307
                # TODO: Also complain about options that have no help message?
 
308
                continue
 
309
            if not option_re.match(option.help):
 
310
                msgs.append('%-16s %-16s %s' %
 
311
                        ((scope or 'GLOBAL'), option.name, option.help))
 
312
        if msgs:
 
313
            self.fail("The following options don't match the style guide:\n"
 
314
                    + '\n'.join(msgs))
 
315
 
 
316
    # TODO: Scan for global options that aren't used by any command?
 
317
    #
 
318
    # TODO: Check that there are two spaces between sentences.