~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_options.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-16 22:35:21 UTC
  • mto: This revision was merged to the branch mainline in revision 1942.
  • Revision ID: john@arbash-meinel.com-20060816223521-73357694d4b7df0b
One field was incorrect, need text_sha1 not text_size

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
 
    )
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
 
28
3
from bzrlib.builtins import cmd_commit, cmd_log, cmd_status
29
4
from bzrlib.commands import Command, parse_args
 
5
from bzrlib import errors
 
6
from bzrlib import option
30
7
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
 
 
 
8
 
 
9
# TODO: might be nice to just parse them into a structured form and test
 
10
# against that, rather than running the whole command.
38
11
 
39
12
class OptionTests(TestCase):
40
13
    """Command-line option tests"""
43
16
        """Option parser"""
44
17
        eq = self.assertEquals
45
18
        eq(parse_args(cmd_commit(), ['--help']),
46
 
           ([], {'fixes': [], 'help': True}))
 
19
           ([], {'help': True}))
47
20
        eq(parse_args(cmd_commit(), ['--message=biter']),
48
 
           ([], {'fixes': [], 'message': 'biter'}))
 
21
           ([], {'message': 'biter'}))
 
22
        ## eq(parse_args(cmd_log(),  '-r 500'.split()),
 
23
        ##   ([], {'revision': RevisionSpec_int(500)}))
49
24
 
50
25
    def test_no_more_opts(self):
51
26
        """Terminated options"""
52
27
        self.assertEquals(parse_args(cmd_commit(), ['--', '-file-with-dashes']),
53
 
                          (['-file-with-dashes'], {'fixes': []}))
 
28
                          (['-file-with-dashes'], {}))
54
29
 
55
30
    def test_option_help(self):
56
31
        """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\.')
 
32
        out, err = self.run_bzr_captured(['commit', '--help'])
 
33
        self.assertContainsRe(out, r'--file(.|\n)*file containing commit'
 
34
                                   ' message')
60
35
        self.assertContainsRe(out, r'-h.*--help')
61
36
 
62
37
    def test_option_help_global(self):
63
38
        """Global options have help strings."""
64
 
        out, err = self.run_bzr('help status')
65
 
        self.assertContainsRe(out, r'--show-ids.*Show internal object.')
 
39
        out, err = self.run_bzr_captured(['help', 'status'])
 
40
        self.assertContainsRe(out, r'--show-ids.*show internal object')
66
41
 
67
42
    def test_option_arg_help(self):
68
43
        """Help message shows option arguments."""
69
 
        out, err = self.run_bzr('help commit')
 
44
        out, err = self.run_bzr_captured(['help', 'commit'])
70
45
        self.assertEquals(err, '')
71
46
        self.assertContainsRe(out, r'--file[ =]MSGFILE')
72
47
 
73
48
    def test_unknown_short_opt(self):
74
 
        out, err = self.run_bzr('help -r', retcode=3)
 
49
        out, err = self.run_bzr_captured(['help', '-r'], retcode=3)
75
50
        self.assertContainsRe(err, r'no such option')
76
51
 
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
52
    def test_allow_dash(self):
83
53
        """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)
 
54
        self.assertEqual((['-'], {}), parse_args(cmd_commit(), ['-']))
90
55
 
91
56
    def test_conversion(self):
 
57
        def parse(options, args):
 
58
            parser = option.get_optparser(dict((o.name, o) for o in options))
 
59
            return parser.parse_args(args)
92
60
        options = [option.Option('hello')]
93
 
        opts, args = self.parse(options, ['--no-hello', '--hello'])
 
61
        opts, args = parse(options, ['--no-hello', '--hello'])
94
62
        self.assertEqual(True, opts.hello)
95
 
        opts, args = self.parse(options, [])
 
63
        opts, args = parse(options, [])
96
64
        self.assertEqual(option.OptionParser.DEFAULT_VALUE, opts.hello)
97
 
        opts, args = self.parse(options, ['--hello', '--no-hello'])
 
65
        opts, args = parse(options, ['--hello', '--no-hello'])
98
66
        self.assertEqual(False, opts.hello)
99
67
        options = [option.Option('number', type=int)]
100
 
        opts, args = self.parse(options, ['--number', '6'])
 
68
        opts, args = parse(options, ['--number', '6'])
101
69
        self.assertEqual(6, opts.number)
102
 
        self.assertRaises(errors.BzrCommandError, self.parse, options,
103
 
                          ['--number'])
104
 
        self.assertRaises(errors.BzrCommandError, self.parse, options,
 
70
        self.assertRaises(errors.BzrCommandError, parse, options, ['--number'])
 
71
        self.assertRaises(errors.BzrCommandError, parse, options, 
105
72
                          ['--no-number'])
106
73
 
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_registry_converter(self):
138
 
        options = [option.RegistryOption('format', '',
139
 
                   bzrdir.format_registry, bzrdir.format_registry.make_bzrdir)]
140
 
        opts, args = self.parse(options, ['--format', 'knit'])
141
 
        self.assertIsInstance(opts.format.repository_format,
142
 
                              knitrepo.RepositoryFormatKnit1)
143
 
 
144
 
    def test_from_kwargs(self):
145
 
        my_option = option.RegistryOption.from_kwargs('my-option',
146
 
            help='test option', short='be short', be_long='go long')
147
 
        self.assertEqual(['my-option'],
148
 
            [x[0] for x in my_option.iter_switches()])
149
 
        my_option = option.RegistryOption.from_kwargs('my-option',
150
 
            help='test option', title="My option", short='be short',
151
 
            be_long='go long', value_switches=True)
152
 
        self.assertEqual(['my-option', 'be-long', 'short'],
153
 
            [x[0] for x in my_option.iter_switches()])
154
 
 
155
 
    def test_help(self):
156
 
        registry = bzrdir.BzrDirFormatRegistry()
157
 
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
158
 
        registry.register_metadir('two',
159
 
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
160
 
            'two help',
161
 
            )
162
 
        registry.register_metadir('hidden', 'RepositoryFormat7', 'hidden help',
163
 
            hidden=True)
164
 
        registry.set_default('one')
165
 
        options = [option.RegistryOption('format', 'format help', registry,
166
 
                   str, value_switches=True, title='Formats')]
167
 
        parser = option.get_optparser(dict((o.name, o) for o in options))
168
 
        value = parser.format_option_help()
169
 
        self.assertContainsRe(value, 'format.*format help')
170
 
        self.assertContainsRe(value, 'one.*one help')
171
 
        self.assertContainsRe(value, 'Formats:\n *--format')
172
 
        self.assertNotContainsRe(value, 'hidden help')
173
 
 
174
74
    def test_iter_switches(self):
175
75
        opt = option.Option('hello', help='fg')
176
76
        self.assertEqual(list(opt.iter_switches()),
181
81
        opt = option.Option('hello', help='fg', type=int, argname='gar')
182
82
        self.assertEqual(list(opt.iter_switches()),
183
83
                         [('hello', None, 'GAR', 'fg')])
184
 
        registry = bzrdir.BzrDirFormatRegistry()
185
 
        registry.register_metadir('one', 'RepositoryFormat7', 'one help')
186
 
        registry.register_metadir('two',
187
 
                'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
188
 
                'two help',
189
 
                )
190
 
        registry.set_default('one')
191
 
        opt = option.RegistryOption('format', 'format help', registry,
192
 
                                    value_switches=False)
193
 
        self.assertEqual(list(opt.iter_switches()),
194
 
                         [('format', None, 'ARG', 'format help')])
195
 
        opt = option.RegistryOption('format', 'format help', registry,
196
 
                                    value_switches=True)
197
 
        self.assertEqual(list(opt.iter_switches()),
198
 
                         [('format', None, 'ARG', 'format help'),
199
 
                          ('default', None, None, 'one help'),
200
 
                          ('one', None, None, 'one help'),
201
 
                          ('two', None, None, 'two help'),
202
 
                          ])
203
 
 
204
 
 
205
 
class TestListOptions(TestCase):
206
 
    """Tests for ListOption, used to specify lists on the command-line."""
207
 
 
208
 
    def parse(self, options, args):
209
 
        parser = option.get_optparser(dict((o.name, o) for o in options))
210
 
        return parser.parse_args(args)
211
 
 
212
 
    def test_list_option(self):
213
 
        options = [option.ListOption('hello', type=str)]
214
 
        opts, args = self.parse(options, ['--hello=world', '--hello=sailor'])
215
 
        self.assertEqual(['world', 'sailor'], opts.hello)
216
 
 
217
 
    def test_list_option_no_arguments(self):
218
 
        options = [option.ListOption('hello', type=str)]
219
 
        opts, args = self.parse(options, [])
220
 
        self.assertEqual([], opts.hello)
221
 
 
222
 
    def test_list_option_with_int_type(self):
223
 
        options = [option.ListOption('hello', type=int)]
224
 
        opts, args = self.parse(options, ['--hello=2', '--hello=3'])
225
 
        self.assertEqual([2, 3], opts.hello)
226
 
 
227
 
    def test_list_option_with_int_type_can_be_reset(self):
228
 
        options = [option.ListOption('hello', type=int)]
229
 
        opts, args = self.parse(options, ['--hello=2', '--hello=3',
230
 
                                          '--hello=-', '--hello=5'])
231
 
        self.assertEqual([5], opts.hello)
232
 
 
233
 
    def test_list_option_can_be_reset(self):
234
 
        """Passing an option of '-' to a list option should reset the list."""
235
 
        options = [option.ListOption('hello', type=str)]
236
 
        opts, args = self.parse(
237
 
            options, ['--hello=a', '--hello=b', '--hello=-', '--hello=c'])
238
 
        self.assertEqual(['c'], opts.hello)
239
 
 
240
 
 
241
 
class TestOptionDefinitions(TestCase):
242
 
    """Tests for options in the Bazaar codebase."""
243
 
 
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()
256
 
            for opt_name, opt in sorted(cmd.options().items()):
257
 
                g.append((cmd_name, opt))
258
 
        return g
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
 
 
265
 
    def test_global_options_used(self):
266
 
        # In the distant memory, options could only be declared globally.  Now
267
 
        # we prefer to declare them in the command, unless like -r they really
268
 
        # are used very widely with the exact same meaning.  So this checks
269
 
        # for any that should be garbage collected.
270
 
        g = dict(option.Option.OPTIONS.items())
271
 
        used_globals = {}
272
 
        msgs = []
273
 
        for cmd_name, cmd_class in sorted(commands.get_all_cmds()):
274
 
            for option_or_name in sorted(cmd_class.takes_options):
275
 
                if not isinstance(option_or_name, basestring):
276
 
                    self.assertIsInstance(option_or_name, option.Option)
277
 
                elif not option_or_name in g:
278
 
                    msgs.append("apparent reference to undefined "
279
 
                        "global option %r from %r"
280
 
                        % (option_or_name, cmd_class))
281
 
                else:
282
 
                    used_globals.setdefault(option_or_name, []).append(cmd_name)
283
 
        unused_globals = set(g.keys()) - set(used_globals.keys())
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))
290
 
        if msgs:
291
 
            self.fail("problems with global option definitions:\n"
292
 
                    + '\n'.join(msgs))
293
 
 
294
 
    def test_option_grammar(self):
295
 
        msgs = []
296
 
        # Option help should be written in sentence form, and have a final
297
 
        # period and be all on a single line, because the display code will
298
 
        # wrap it.
299
 
        option_re = re.compile(r'^[A-Z][^\n]+\.$')
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))
307
 
        if msgs:
308
 
            self.fail("The following options don't match the style guide:\n"
309
 
                    + '\n'.join(msgs))
310
 
 
311
 
    # TODO: Scan for global options that aren't used by any command?
312
 
    #
313
 
    # TODO: Check that there are two spaces between sentences.
 
84
 
 
85
#     >>> parse_args('log -r 500'.split())
 
86
#     (['log'], {'revision': [<RevisionSpec_int 500>]})
 
87
#     >>> parse_args('log -r500..600'.split())
 
88
#     (['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
89
#     >>> parse_args('log -vr500..600'.split())
 
90
#     (['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
91
#     >>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
 
92
#     (['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})