blob: 254d1b4dc4b12502049a79dc70fa9ccedd09153a [file] [log] [blame]
Greg Ward55493222003-04-21 02:41:25 +00001#!/usr/bin/python
2
3#
4# Test suite for Optik. Supplied by Johannes Gijsbers
5# (taradino@softhome.net) -- translated from the original Optik
6# test suite to this PyUnit-based version.
7#
8# $Id$
9#
10
11import sys
12import os
13import copy
14import unittest
15
16from cStringIO import StringIO
17from pprint import pprint
18from test import test_support
19
20from optparse import make_option, Option, IndentedHelpFormatter, \
21 TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
22 SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
Greg Wardeba20e62004-07-31 16:15:44 +000023 BadOptionError, OptionValueError, _match_abbrev
Greg Ward55493222003-04-21 02:41:25 +000024
25class BaseTest(unittest.TestCase):
26 def assertParseOK(self, args, expected_opts, expected_positional_args):
27 """Assert the options are what we expected when parsing arguments.
28
29 Otherwise, fail with a nicely formatted message.
30
31 Keyword arguments:
32 args -- A list of arguments to parse with OptionParser.
33 expected_opts -- The options expected.
34 expected_positional_args -- The positional arguments expected.
35
36 Returns the options and positional args for further testing.
37 """
38
39 (options, positional_args) = self.parser.parse_args(args)
40 optdict = vars(options)
41
42 self.assertEqual(optdict, expected_opts,
43 """
44Options are %(optdict)s.
45Should be %(expected_opts)s.
46Args were %(args)s.""" % locals())
47
48 self.assertEqual(positional_args, expected_positional_args,
49 """
50Positional arguments are %(positional_args)s.
51Should be %(expected_positional_args)s.
52Args were %(args)s.""" % locals ())
53
54 return (options, positional_args)
55
Greg Wardeba20e62004-07-31 16:15:44 +000056 def assertRaises(self,
57 func,
58 args,
59 kwargs,
60 expected_exception,
61 expected_output,
Tim Petersc0cbc862004-07-31 21:17:37 +000062 get_output=None,
Greg Wardeba20e62004-07-31 16:15:44 +000063 exact_match=False):
Greg Ward55493222003-04-21 02:41:25 +000064 """Assert the expected exception is raised when calling a function.
65
66 Also check whether the right error message is given for a given error.
67
Greg Wardeba20e62004-07-31 16:15:44 +000068 Arguments:
69 func -- the function to call
70 args -- positional arguments to `func`
71 kwargs -- keyword arguments to `func`
72 expected_exception -- exception that should be raised
73 expected_output -- output we expect to see
74 get_output -- function to call to get the output
75 exact_match -- whether output must exactly match expected output,
76 or merely contain it
Greg Ward55493222003-04-21 02:41:25 +000077
78 Returns the exception raised for further testing.
79 """
Greg Wardeba20e62004-07-31 16:15:44 +000080 if args is None:
81 args = ()
82 if kwargs is None:
83 kwargs = {}
Greg Ward55493222003-04-21 02:41:25 +000084 if get_output is None:
85 get_output = self.exception
86
87 try:
Greg Wardeba20e62004-07-31 16:15:44 +000088 out = func(*args, **kwargs)
Greg Ward55493222003-04-21 02:41:25 +000089 except expected_exception, err:
Greg Wardeba20e62004-07-31 16:15:44 +000090 actual_output = get_output(err)
Greg Ward55493222003-04-21 02:41:25 +000091
Greg Wardeba20e62004-07-31 16:15:44 +000092 if exact_match:
93 match = actual_output == expected_exception
94 else:
95 match = actual_output.find(expected_output) != -1
96
97 self.assert_(match,
98 """mismatched output
99expected output:
100'''%(expected_output)s'''
101actual output:
102'''%(actual_output)s'''
103""" % locals())
Greg Ward55493222003-04-21 02:41:25 +0000104
105 return err
106 else:
Greg Wardeba20e62004-07-31 16:15:44 +0000107 self.fail("""expected exception %(expected_exception)s not raised
108called %(func)r
109with args %(args)r
110and kwargs %(kwargs)r
111""" % locals ())
Greg Ward55493222003-04-21 02:41:25 +0000112
113 # -- Functions to be used as the get_output argument to assertRaises ------
114
115 def exception(self, err):
116 return str(err)
117
118 def redirected_stdout(self, err):
119 return sys.stdout.getvalue()
120
Greg Wardeba20e62004-07-31 16:15:44 +0000121 def redirected_stderr(self, err):
122 return sys.stderr.getvalue()
123
Greg Ward55493222003-04-21 02:41:25 +0000124 # -- Assertions used in more than one class --------------------
125
126 def assertParseFail(self, cmdline_args, expected_output):
127 """Assert the parser fails with the expected message."""
Tim Peters579f7352004-07-31 21:14:28 +0000128 save_stderr = sys.stderr
129 try:
130 sys.stderr = StringIO()
131 self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
132 SystemExit, expected_output,
133 self.redirected_stderr)
134 finally:
135 sys.stderr = save_stderr
Greg Ward55493222003-04-21 02:41:25 +0000136
137 def assertStdoutEquals(self, cmdline_args, expected_output):
138 """Assert the parser prints the expected output on stdout."""
Tim Peters579f7352004-07-31 21:14:28 +0000139 save_stdout = sys.stdout
140 try:
141 sys.stdout = StringIO()
142 self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
143 SystemExit, expected_output,
144 self.redirected_stdout)
145 finally:
146 sys.stdout = save_stdout
Greg Ward55493222003-04-21 02:41:25 +0000147
148 def assertTypeError(self, func, expected_output, *args):
149 """Assert a TypeError is raised when executing func."""
Greg Wardeba20e62004-07-31 16:15:44 +0000150 self.assertRaises(func, args, None, TypeError, expected_output)
151
152 def assertHelp(self, parser, expected_help):
153 actual_help = parser.format_help()
154 if actual_help != expected_help:
155 raise self.failureException(
156 'help text failure; expected:\n"' +
157 expected_help + '"; got:\n"' +
158 actual_help + '"\n')
Greg Ward55493222003-04-21 02:41:25 +0000159
160# -- Test make_option() aka Option -------------------------------------
161
162# It's not necessary to test correct options here. All the tests in the
163# parser.parse_args() section deal with those, because they're needed
164# there. Duplication makes no sense to me.
165
166class TestOptionChecks(BaseTest):
167 def setUp(self):
168 self.parser = OptionParser(usage=SUPPRESS_USAGE)
169
170 def assertOptionError(self, expected_output, args=[], kwargs={}):
Greg Wardeba20e62004-07-31 16:15:44 +0000171 self.assertRaises(make_option, args, kwargs,
172 OptionError, expected_output)
Greg Ward55493222003-04-21 02:41:25 +0000173
174 def test_opt_string_empty(self):
175 self.assertTypeError(make_option,
176 "at least one option string must be supplied")
177
178 def test_opt_string_too_short(self):
179 self.assertOptionError("invalid option string 'b': "
180 "must be at least two characters long",
181 ["b"])
182
183 def test_opt_string_short_invalid(self):
184 self.assertOptionError("invalid short option string '--': must be "
185 "of the form -x, (x any non-dash char)",
186 ["--"])
187
188 def test_opt_string_long_invalid(self):
189 self.assertOptionError("invalid long option string '---': "
190 "must start with --, followed by non-dash",
191 ["---"])
192
193 def test_attr_invalid(self):
194 self.assertOptionError("invalid keyword arguments: foo, bar",
195 ["-b"], {'foo': None, 'bar': None})
196
197 def test_action_invalid(self):
198 self.assertOptionError("invalid action: 'foo'",
199 ["-b"], {'action': 'foo'})
200
201 def test_type_invalid(self):
202 self.assertOptionError("invalid option type: 'foo'",
203 ["-b"], {'type': 'foo'})
Greg Wardeba20e62004-07-31 16:15:44 +0000204 self.assertOptionError("invalid option type: 'tuple'",
205 ["-b"], {'type': tuple})
Greg Ward55493222003-04-21 02:41:25 +0000206
207 def test_no_type_for_action(self):
208 self.assertOptionError("must not supply a type for action 'count'",
209 ["-b"], {'action': 'count', 'type': 'int'})
210
211 def test_no_choices_list(self):
212 self.assertOptionError("must supply a list of "
213 "choices for type 'choice'",
214 ["-b", "--bad"], {'type': "choice"})
215
216 def test_bad_choices_list(self):
217 typename = type('').__name__
218 self.assertOptionError("choices must be a list of "
219 "strings ('%s' supplied)" % typename,
220 ["-b", "--bad"],
221 {'type': "choice", 'choices':"bad choices"})
222
223 def test_no_choices_for_type(self):
224 self.assertOptionError("must not supply choices for type 'int'",
225 ["-b"], {'type': 'int', 'choices':"bad"})
226
227 def test_no_const_for_action(self):
228 self.assertOptionError("'const' must not be supplied for action "
229 "'store'",
230 ["-b"], {'action': 'store', 'const': 1})
231
232 def test_no_nargs_for_action(self):
233 self.assertOptionError("'nargs' must not be supplied for action "
234 "'count'",
235 ["-b"], {'action': 'count', 'nargs': 2})
236
237 def test_callback_not_callable(self):
238 self.assertOptionError("callback not callable: 'foo'",
239 ["-b"], {'action': 'callback',
240 'callback': 'foo'})
241
242 def dummy(self):
243 pass
244
245 def test_callback_args_no_tuple(self):
246 self.assertOptionError("callback_args, if supplied, must be a tuple: "
247 "not 'foo'",
248 ["-b"], {'action': 'callback',
249 'callback': self.dummy,
250 'callback_args': 'foo'})
251
252 def test_callback_kwargs_no_dict(self):
253 self.assertOptionError("callback_kwargs, if supplied, must be a dict: "
254 "not 'foo'",
255 ["-b"], {'action': 'callback',
256 'callback': self.dummy,
257 'callback_kwargs': 'foo'})
258
259 def test_no_callback_for_action(self):
260 self.assertOptionError("callback supplied ('foo') for "
261 "non-callback option",
262 ["-b"], {'action': 'store',
263 'callback': 'foo'})
264
265 def test_no_callback_args_for_action(self):
266 self.assertOptionError("callback_args supplied for non-callback "
267 "option",
268 ["-b"], {'action': 'store',
269 'callback_args': 'foo'})
270
271 def test_no_callback_kwargs_for_action(self):
272 self.assertOptionError("callback_kwargs supplied for non-callback "
273 "option",
274 ["-b"], {'action': 'store',
275 'callback_kwargs': 'foo'})
276
277class TestOptionParser(BaseTest):
278 def setUp(self):
279 self.parser = OptionParser()
280 self.parser.add_option("-v", "--verbose", "-n", "--noisy",
281 action="store_true", dest="verbose")
282 self.parser.add_option("-q", "--quiet", "--silent",
283 action="store_false", dest="verbose")
284
285 def test_add_option_no_Option(self):
286 self.assertTypeError(self.parser.add_option,
287 "not an Option instance: None", None)
288
289 def test_add_option_invalid_arguments(self):
290 self.assertTypeError(self.parser.add_option,
291 "invalid arguments", None, None)
292
293 def test_get_option(self):
294 opt1 = self.parser.get_option("-v")
295 self.assert_(isinstance(opt1, Option))
296 self.assertEqual(opt1._short_opts, ["-v", "-n"])
297 self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])
298 self.assertEqual(opt1.action, "store_true")
299 self.assertEqual(opt1.dest, "verbose")
300
301 def test_get_option_equals(self):
302 opt1 = self.parser.get_option("-v")
303 opt2 = self.parser.get_option("--verbose")
304 opt3 = self.parser.get_option("-n")
305 opt4 = self.parser.get_option("--noisy")
306 self.assert_(opt1 is opt2 is opt3 is opt4)
307
308 def test_has_option(self):
309 self.assert_(self.parser.has_option("-v"))
310 self.assert_(self.parser.has_option("--verbose"))
311
312 def assert_removed(self):
313 self.assert_(self.parser.get_option("-v") is None)
314 self.assert_(self.parser.get_option("--verbose") is None)
315 self.assert_(self.parser.get_option("-n") is None)
316 self.assert_(self.parser.get_option("--noisy") is None)
317
318 self.failIf(self.parser.has_option("-v"))
319 self.failIf(self.parser.has_option("--verbose"))
320 self.failIf(self.parser.has_option("-n"))
321 self.failIf(self.parser.has_option("--noisy"))
322
323 self.assert_(self.parser.has_option("-q"))
324 self.assert_(self.parser.has_option("--silent"))
325
326 def test_remove_short_opt(self):
327 self.parser.remove_option("-n")
328 self.assert_removed()
329
330 def test_remove_long_opt(self):
331 self.parser.remove_option("--verbose")
332 self.assert_removed()
333
334 def test_remove_nonexistent(self):
Greg Wardeba20e62004-07-31 16:15:44 +0000335 self.assertRaises(self.parser.remove_option, ('foo',), None,
336 ValueError, "no such option 'foo'")
337
338class TestTypeAliases(BaseTest):
339 def setUp(self):
340 self.parser = OptionParser()
341
342 def test_type_aliases(self):
343 self.parser.add_option("-x", type=int)
344 self.parser.add_option("-s", type=str)
345 self.parser.add_option("-t", type="str")
346 self.assertEquals(self.parser.get_option("-x").type, "int")
347 self.assertEquals(self.parser.get_option("-s").type, "string")
348 self.assertEquals(self.parser.get_option("-t").type, "string")
Tim Petersc0cbc862004-07-31 21:17:37 +0000349
Greg Wardeba20e62004-07-31 16:15:44 +0000350
351# Custom type for testing processing of default values.
352_time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
353
354def _check_duration(option, opt, value):
355 try:
356 if value[-1].isdigit():
357 return int(value)
358 else:
359 return int(value[:-1]) * _time_units[value[-1]]
360 except ValueError, IndexError:
361 raise OptionValueError(
362 'option %s: invalid duration: %r' % (opt, value))
363
364class DurationOption(Option):
365 TYPES = Option.TYPES + ('duration',)
366 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
367 TYPE_CHECKER['duration'] = _check_duration
368
369class TestDefaultValues(BaseTest):
370 def setUp(self):
371 self.parser = OptionParser()
372 self.parser.add_option("-v", "--verbose", default=True)
373 self.parser.add_option("-q", "--quiet", dest='verbose')
374 self.parser.add_option("-n", type="int", default=37)
375 self.parser.add_option("-m", type="int")
376 self.parser.add_option("-s", default="foo")
377 self.parser.add_option("-t")
378 self.parser.add_option("-u", default=None)
379 self.expected = { 'verbose': True,
380 'n': 37,
381 'm': None,
382 's': "foo",
383 't': None,
384 'u': None }
385
386 def test_basic_defaults(self):
387 self.assertEqual(self.parser.get_default_values(), self.expected)
388
389 def test_mixed_defaults_post(self):
390 self.parser.set_defaults(n=42, m=-100)
391 self.expected.update({'n': 42, 'm': -100})
392 self.assertEqual(self.parser.get_default_values(), self.expected)
393
394 def test_mixed_defaults_pre(self):
395 self.parser.set_defaults(x="barf", y="blah")
396 self.parser.add_option("-x", default="frob")
397 self.parser.add_option("-y")
398
399 self.expected.update({'x': "frob", 'y': "blah"})
400 self.assertEqual(self.parser.get_default_values(), self.expected)
401
402 self.parser.remove_option("-y")
403 self.parser.add_option("-y", default=None)
404 self.expected.update({'y': None})
405 self.assertEqual(self.parser.get_default_values(), self.expected)
406
407 def test_process_default(self):
408 self.parser.option_class = DurationOption
409 self.parser.add_option("-d", type="duration", default=300)
410 self.parser.add_option("-e", type="duration", default="6m")
411 self.parser.set_defaults(n="42")
412 self.expected.update({'d': 300, 'e': 360, 'n': 42})
413 self.assertEqual(self.parser.get_default_values(), self.expected)
414
415 self.parser.set_process_default_values(False)
416 self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
417 self.assertEqual(self.parser.get_default_values(), self.expected)
418
419
420class TestProgName(BaseTest):
421 """
422 Test that %prog expands to the right thing in usage, version,
423 and help strings.
424 """
425
426 def assertUsage(self, parser, expected_usage):
427 self.assertEqual(parser.get_usage(), expected_usage)
428
429 def assertVersion(self, parser, expected_version):
430 self.assertEqual(parser.get_version(), expected_version)
431
432
433 def test_default_progname(self):
434 # Make sure that program name taken from sys.argv[0] by default.
Tim Peters579f7352004-07-31 21:14:28 +0000435 save_argv = sys.argv[:]
436 try:
437 # XXX Should the path be hard-coding forward-slashes?
438 sys.argv[0] = "/foo/bar/baz.py"
439 parser = OptionParser("usage: %prog ...", version="%prog 1.2")
440 expected_usage = "usage: baz.py ...\n"
441 self.assertUsage(parser, expected_usage)
442 self.assertVersion(parser, "baz.py 1.2")
443 self.assertHelp(parser,
444 expected_usage + "\n" +
445 "options:\n"
446 " --version show program's version number and exit\n"
447 " -h, --help show this help message and exit\n")
448 finally:
449 sys.argv[:] = save_argv
Greg Wardeba20e62004-07-31 16:15:44 +0000450
451 def test_custom_progname(self):
452 parser = OptionParser(prog="thingy",
453 version="%prog 0.1",
454 usage="%prog arg arg")
455 parser.remove_option("-h")
456 parser.remove_option("--version")
457 expected_usage = "usage: thingy arg arg\n"
458 self.assertUsage(parser, expected_usage)
459 self.assertVersion(parser, "thingy 0.1")
460 self.assertHelp(parser, expected_usage + "\n")
461
462
463class TestExpandDefaults(BaseTest):
464 def setUp(self):
465 self.parser = OptionParser(prog="test")
466 self.help_prefix = """\
467usage: test [options]
468
469options:
470 -h, --help show this help message and exit
471"""
472 self.file_help = "read from FILE [default: %default]"
473 self.expected_help_file = self.help_prefix + \
474 " -f FILE, --file=FILE read from FILE [default: foo.txt]\n"
475 self.expected_help_none = self.help_prefix + \
476 " -f FILE, --file=FILE read from FILE [default: none]\n"
477
478 def test_option_default(self):
479 self.parser.add_option("-f", "--file",
480 default="foo.txt",
481 help=self.file_help)
482 self.assertHelp(self.parser, self.expected_help_file)
483
484 def test_parser_default_1(self):
485 self.parser.add_option("-f", "--file",
486 help=self.file_help)
487 self.parser.set_default('file', "foo.txt")
488 self.assertHelp(self.parser, self.expected_help_file)
489
490 def test_parser_default_2(self):
491 self.parser.add_option("-f", "--file",
492 help=self.file_help)
493 self.parser.set_defaults(file="foo.txt")
494 self.assertHelp(self.parser, self.expected_help_file)
495
496 def test_no_default(self):
497 self.parser.add_option("-f", "--file",
498 help=self.file_help)
499 self.assertHelp(self.parser, self.expected_help_none)
500
501 def test_default_none_1(self):
502 self.parser.add_option("-f", "--file",
503 default=None,
504 help=self.file_help)
505 self.assertHelp(self.parser, self.expected_help_none)
Tim Petersc0cbc862004-07-31 21:17:37 +0000506
Greg Wardeba20e62004-07-31 16:15:44 +0000507 def test_default_none_2(self):
508 self.parser.add_option("-f", "--file",
509 help=self.file_help)
510 self.parser.set_defaults(file=None)
511 self.assertHelp(self.parser, self.expected_help_none)
512
513 def test_float_default(self):
514 self.parser.add_option(
515 "-p", "--prob",
516 help="blow up with probability PROB [default: %default]")
517 self.parser.set_defaults(prob=0.43)
518 expected_help = self.help_prefix + \
519 " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n"
520 self.assertHelp(self.parser, expected_help)
521
522 def test_alt_expand(self):
523 self.parser.add_option("-f", "--file",
524 default="foo.txt",
525 help="read from FILE [default: *DEFAULT*]")
526 self.parser.formatter.default_tag = "*DEFAULT*"
527 self.assertHelp(self.parser, self.expected_help_file)
528
529 def test_no_expand(self):
530 self.parser.add_option("-f", "--file",
531 default="foo.txt",
532 help="read from %default file")
533 self.parser.formatter.default_tag = None
534 expected_help = self.help_prefix + \
535 " -f FILE, --file=FILE read from %default file\n"
536 self.assertHelp(self.parser, expected_help)
537
Greg Ward55493222003-04-21 02:41:25 +0000538
539# -- Test parser.parse_args() ------------------------------------------
540
541class TestStandard(BaseTest):
542 def setUp(self):
543 options = [make_option("-a", type="string"),
544 make_option("-b", "--boo", type="int", dest='boo'),
545 make_option("--foo", action="append")]
546
547 self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
548
549 def test_required_value(self):
Greg Wardeba20e62004-07-31 16:15:44 +0000550 self.assertParseFail(["-a"], "-a option requires an argument")
Greg Ward55493222003-04-21 02:41:25 +0000551
552 def test_invalid_integer(self):
553 self.assertParseFail(["-b", "5x"],
554 "option -b: invalid integer value: '5x'")
555
556 def test_no_such_option(self):
557 self.assertParseFail(["--boo13"], "no such option: --boo13")
558
559 def test_long_invalid_integer(self):
560 self.assertParseFail(["--boo=x5"],
561 "option --boo: invalid integer value: 'x5'")
562
563 def test_empty(self):
564 self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
565
566 def test_shortopt_empty_longopt_append(self):
567 self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
568 {'a': "", 'boo': None, 'foo': ["blah", ""]},
569 [])
570
571 def test_long_option_append(self):
572 self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
573 {'a': None,
574 'boo': None,
575 'foo': ["bar", "", "x"]},
576 [])
577
578 def test_option_argument_joined(self):
579 self.assertParseOK(["-abc"],
580 {'a': "bc", 'boo': None, 'foo': None},
581 [])
582
583 def test_option_argument_split(self):
584 self.assertParseOK(["-a", "34"],
585 {'a': "34", 'boo': None, 'foo': None},
586 [])
587
588 def test_option_argument_joined_integer(self):
589 self.assertParseOK(["-b34"],
590 {'a': None, 'boo': 34, 'foo': None},
591 [])
592
593 def test_option_argument_split_negative_integer(self):
594 self.assertParseOK(["-b", "-5"],
595 {'a': None, 'boo': -5, 'foo': None},
596 [])
597
598 def test_long_option_argument_joined(self):
599 self.assertParseOK(["--boo=13"],
600 {'a': None, 'boo': 13, 'foo': None},
601 [])
602
603 def test_long_option_argument_split(self):
604 self.assertParseOK(["--boo", "111"],
605 {'a': None, 'boo': 111, 'foo': None},
606 [])
607
608 def test_long_option_short_option(self):
609 self.assertParseOK(["--foo=bar", "-axyz"],
610 {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
611 [])
612
613 def test_abbrev_long_option(self):
614 self.assertParseOK(["--f=bar", "-axyz"],
615 {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
616 [])
617
618 def test_defaults(self):
619 (options, args) = self.parser.parse_args([])
620 defaults = self.parser.get_default_values()
621 self.assertEqual(vars(defaults), vars(options))
622
623 def test_ambiguous_option(self):
624 self.parser.add_option("--foz", action="store",
625 type="string", dest="foo")
626 possibilities = ", ".join({"--foz": None, "--foo": None}.keys())
627 self.assertParseFail(["--f=bar"],
628 "ambiguous option: --f (%s?)" % possibilities)
629
630
631 def test_short_and_long_option_split(self):
632 self.assertParseOK(["-a", "xyz", "--foo", "bar"],
633 {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
634 []),
635
636 def test_short_option_split_long_option_append(self):
637 self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
638 {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
639 [])
640
641 def test_short_option_split_one_positional_arg(self):
642 self.assertParseOK(["-a", "foo", "bar"],
643 {'a': "foo", 'boo': None, 'foo': None},
644 ["bar"]),
645
646 def test_short_option_consumes_separator(self):
647 self.assertParseOK(["-a", "--", "foo", "bar"],
648 {'a': "--", 'boo': None, 'foo': None},
649 ["foo", "bar"]),
650
651 def test_short_option_joined_and_separator(self):
652 self.assertParseOK(["-ab", "--", "--foo", "bar"],
653 {'a': "b", 'boo': None, 'foo': None},
654 ["--foo", "bar"]),
655
656 def test_invalid_option_becomes_positional_arg(self):
657 self.assertParseOK(["-ab", "-", "--foo", "bar"],
658 {'a': "b", 'boo': None, 'foo': ["bar"]},
659 ["-"])
660
661 def test_no_append_versus_append(self):
662 self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
663 {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
664 [])
665
666 def test_option_consumes_optionlike_string(self):
667 self.assertParseOK(["-a", "-b3"],
668 {'a': "-b3", 'boo': None, 'foo': None},
669 [])
670
671class TestBool(BaseTest):
672 def setUp(self):
673 options = [make_option("-v",
674 "--verbose",
675 action="store_true",
676 dest="verbose",
677 default=''),
678 make_option("-q",
679 "--quiet",
680 action="store_false",
681 dest="verbose")]
682 self.parser = OptionParser(option_list = options)
683
684 def test_bool_default(self):
685 self.assertParseOK([],
686 {'verbose': ''},
687 [])
688
689 def test_bool_false(self):
690 (options, args) = self.assertParseOK(["-q"],
691 {'verbose': 0},
692 [])
693 if hasattr(__builtins__, 'False'):
694 self.failUnless(options.verbose is False)
695
696 def test_bool_true(self):
697 (options, args) = self.assertParseOK(["-v"],
698 {'verbose': 1},
699 [])
700 if hasattr(__builtins__, 'True'):
701 self.failUnless(options.verbose is True)
702
703 def test_bool_flicker_on_and_off(self):
704 self.assertParseOK(["-qvq", "-q", "-v"],
705 {'verbose': 1},
706 [])
707
708class TestChoice(BaseTest):
709 def setUp(self):
710 self.parser = OptionParser(usage=SUPPRESS_USAGE)
711 self.parser.add_option("-c", action="store", type="choice",
712 dest="choice", choices=["one", "two", "three"])
713
714 def test_valid_choice(self):
715 self.assertParseOK(["-c", "one", "xyz"],
716 {'choice': 'one'},
717 ["xyz"])
718
719 def test_invalid_choice(self):
720 self.assertParseFail(["-c", "four", "abc"],
721 "option -c: invalid choice: 'four' "
722 "(choose from 'one', 'two', 'three')")
723
724 def test_add_choice_option(self):
725 self.parser.add_option("-d", "--default",
726 choices=["four", "five", "six"])
727 opt = self.parser.get_option("-d")
728 self.assertEqual(opt.type, "choice")
729 self.assertEqual(opt.action, "store")
730
731class TestCount(BaseTest):
732 def setUp(self):
733 self.parser = OptionParser(usage=SUPPRESS_USAGE)
734 self.v_opt = make_option("-v", action="count", dest="verbose")
735 self.parser.add_option(self.v_opt)
736 self.parser.add_option("--verbose", type="int", dest="verbose")
737 self.parser.add_option("-q", "--quiet",
738 action="store_const", dest="verbose", const=0)
739
740 def test_empty(self):
741 self.assertParseOK([], {'verbose': None}, [])
742
743 def test_count_one(self):
744 self.assertParseOK(["-v"], {'verbose': 1}, [])
745
746 def test_count_three(self):
747 self.assertParseOK(["-vvv"], {'verbose': 3}, [])
748
749 def test_count_three_apart(self):
750 self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, [])
751
752 def test_count_override_amount(self):
753 self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, [])
754
755 def test_count_override_quiet(self):
756 self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, [])
757
758 def test_count_overriding(self):
759 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
760 {'verbose': 1}, [])
761
762 def test_count_interspersed_args(self):
763 self.assertParseOK(["--quiet", "3", "-v"],
764 {'verbose': 1},
765 ["3"])
766
767 def test_count_no_interspersed_args(self):
768 self.parser.disable_interspersed_args()
769 self.assertParseOK(["--quiet", "3", "-v"],
770 {'verbose': 0},
771 ["3", "-v"])
772
773 def test_count_no_such_option(self):
774 self.assertParseFail(["-q3", "-v"], "no such option: -3")
775
776 def test_count_option_no_value(self):
777 self.assertParseFail(["--quiet=3", "-v"],
778 "--quiet option does not take a value")
779
780 def test_count_with_default(self):
781 self.parser.set_default('verbose', 0)
782 self.assertParseOK([], {'verbose':0}, [])
783
784 def test_count_overriding_default(self):
785 self.parser.set_default('verbose', 0)
786 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
787 {'verbose': 1}, [])
788
789class TestNArgs(BaseTest):
790 def setUp(self):
791 self.parser = OptionParser(usage=SUPPRESS_USAGE)
792 self.parser.add_option("-p", "--point",
793 action="store", nargs=3, type="float", dest="point")
794
795 def test_nargs_with_positional_args(self):
796 self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"],
797 {'point': (1.0, 2.5, -4.3)},
798 ["foo", "xyz"])
799
800 def test_nargs_long_opt(self):
801 self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"],
802 {'point': (-1.0, 2.5, -0.0)},
803 ["xyz"])
804
805 def test_nargs_invalid_float_value(self):
806 self.assertParseFail(["-p", "1.0", "2x", "3.5"],
807 "option -p: "
808 "invalid floating-point value: '2x'")
809
810 def test_nargs_required_values(self):
811 self.assertParseFail(["--point", "1.0", "3.5"],
Greg Wardeba20e62004-07-31 16:15:44 +0000812 "--point option requires 3 arguments")
Greg Ward55493222003-04-21 02:41:25 +0000813
814class TestNArgsAppend(BaseTest):
815 def setUp(self):
816 self.parser = OptionParser(usage=SUPPRESS_USAGE)
817 self.parser.add_option("-p", "--point", action="store", nargs=3,
818 type="float", dest="point")
819 self.parser.add_option("-f", "--foo", action="append", nargs=2,
820 type="int", dest="foo")
821
822 def test_nargs_append(self):
823 self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],
824 {'point': None, 'foo': [(4, -3), (1, 666)]},
825 ["blah"])
826
827 def test_nargs_append_required_values(self):
828 self.assertParseFail(["-f4,3"],
Greg Wardeba20e62004-07-31 16:15:44 +0000829 "-f option requires 2 arguments")
Greg Ward55493222003-04-21 02:41:25 +0000830
831 def test_nargs_append_simple(self):
832 self.assertParseOK(["--foo=3", "4"],
833 {'point': None, 'foo':[(3, 4)]},
834 [])
835
836class TestVersion(BaseTest):
837 def test_version(self):
838 oldargv = sys.argv[0]
839 sys.argv[0] = "./foo/bar"
840 self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1")
841 self.assertStdoutEquals(["--version"], "bar 0.1\n")
842 sys.argv[0] = oldargv
843
844 def test_no_version(self):
845 self.parser = OptionParser(usage=SUPPRESS_USAGE)
846 self.assertParseFail(["--version"],
847 "no such option: --version")
848
849# -- Test conflicting default values and parser.parse_args() -----------
850
851class TestConflictingDefaults(BaseTest):
852 """Conflicting default values: the last one should win."""
853 def setUp(self):
854 self.parser = OptionParser(option_list=[
855 make_option("-v", action="store_true", dest="verbose", default=1)])
856
857 def test_conflict_default(self):
858 self.parser.add_option("-q", action="store_false", dest="verbose",
859 default=0)
860 self.assertParseOK([], {'verbose': 0}, [])
861
862 def test_conflict_default_none(self):
863 self.parser.add_option("-q", action="store_false", dest="verbose",
864 default=None)
865 self.assertParseOK([], {'verbose': None}, [])
866
867class TestOptionGroup(BaseTest):
868 def setUp(self):
869 self.parser = OptionParser(usage=SUPPRESS_USAGE)
870
871 def test_option_group_create_instance(self):
872 group = OptionGroup(self.parser, "Spam")
873 self.parser.add_option_group(group)
874 group.add_option("--spam", action="store_true",
875 help="spam spam spam spam")
876 self.assertParseOK(["--spam"], {'spam': 1}, [])
877
878 def test_add_group_no_group(self):
879 self.assertTypeError(self.parser.add_option_group,
880 "not an OptionGroup instance: None", None)
881
882 def test_add_group_invalid_arguments(self):
883 self.assertTypeError(self.parser.add_option_group,
884 "invalid arguments", None, None)
885
886 def test_add_group_wrong_parser(self):
887 group = OptionGroup(self.parser, "Spam")
888 group.parser = OptionParser()
Greg Wardeba20e62004-07-31 16:15:44 +0000889 self.assertRaises(self.parser.add_option_group, (group,), None,
890 ValueError, "invalid OptionGroup (wrong parser)")
Greg Ward55493222003-04-21 02:41:25 +0000891
892 def test_group_manipulate(self):
893 group = self.parser.add_option_group("Group 2",
894 description="Some more options")
895 group.set_title("Bacon")
896 group.add_option("--bacon", type="int")
897 self.assert_(self.parser.get_option_group("--bacon"), group)
898
899# -- Test extending and parser.parse_args() ----------------------------
900
901class TestExtendAddTypes(BaseTest):
902 def setUp(self):
903 self.parser = OptionParser(usage=SUPPRESS_USAGE,
904 option_class=self.MyOption)
905 self.parser.add_option("-a", None, type="string", dest="a")
906 self.parser.add_option("-f", "--file", type="file", dest="file")
907
908 class MyOption (Option):
909 def check_file (option, opt, value):
910 if not os.path.exists(value):
911 raise OptionValueError("%s: file does not exist" % value)
912 elif not os.path.isfile(value):
913 raise OptionValueError("%s: not a regular file" % value)
914 return value
915
916 TYPES = Option.TYPES + ("file",)
917 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
918 TYPE_CHECKER["file"] = check_file
919
920 def test_extend_file(self):
921 open(test_support.TESTFN, "w").close()
922 self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
923 {'file': test_support.TESTFN, 'a': 'foo'},
924 [])
925
926 os.unlink(test_support.TESTFN)
927
928 def test_extend_file_nonexistent(self):
929 self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
930 "%s: file does not exist" %
931 test_support.TESTFN)
932
933 def test_file_irregular(self):
934 os.mkdir(test_support.TESTFN)
935 self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
936 "%s: not a regular file" %
937 test_support.TESTFN)
938 os.rmdir(test_support.TESTFN)
939
940class TestExtendAddActions(BaseTest):
941 def setUp(self):
942 options = [self.MyOption("-a", "--apple", action="extend",
943 type="string", dest="apple")]
944 self.parser = OptionParser(option_list=options)
945
946 class MyOption (Option):
947 ACTIONS = Option.ACTIONS + ("extend",)
948 STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
949 TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
950
951 def take_action (self, action, dest, opt, value, values, parser):
952 if action == "extend":
953 lvalue = value.split(",")
954 values.ensure_value(dest, []).extend(lvalue)
955 else:
956 Option.take_action(self, action, dest, opt, parser, value,
957 values)
958
959 def test_extend_add_action(self):
960 self.assertParseOK(["-afoo,bar", "--apple=blah"],
961 {'apple': ["foo", "bar", "blah"]},
962 [])
963
964 def test_extend_add_action_normal(self):
965 self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"],
966 {'apple': ["foo", "bar", "x", "y"]},
967 [])
968
969# -- Test callbacks and parser.parse_args() ----------------------------
970
971class TestCallback(BaseTest):
972 def setUp(self):
973 options = [make_option("-x",
974 None,
975 action="callback",
976 callback=self.process_opt),
977 make_option("-f",
978 "--file",
979 action="callback",
980 callback=self.process_opt,
981 type="string",
982 dest="filename")]
983 self.parser = OptionParser(option_list=options)
984
985 def process_opt(self, option, opt, value, parser_):
986 if opt == "-x":
987 self.assertEqual(option._short_opts, ["-x"])
988 self.assertEqual(option._long_opts, [])
989 self.assert_(parser_ is self.parser)
990 self.assert_(value is None)
991 self.assertEqual(vars(parser_.values), {'filename': None})
992
993 parser_.values.x = 42
994 elif opt == "--file":
995 self.assertEqual(option._short_opts, ["-f"])
996 self.assertEqual(option._long_opts, ["--file"])
997 self.assert_(parser_ is self.parser)
998 self.assertEqual(value, "foo")
999 self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42})
1000
1001 setattr(parser_.values, option.dest, value)
1002 else:
1003 self.fail("Unknown option %r in process_opt." % opt)
1004
1005 def test_callback(self):
1006 self.assertParseOK(["-x", "--file=foo"],
1007 {'filename': "foo", 'x': 42},
1008 [])
1009
Greg Wardeba20e62004-07-31 16:15:44 +00001010 def test_callback_help(self):
1011 # This test was prompted by SF bug #960515 -- the point is
1012 # not to inspect the help text, just to make sure that
1013 # format_help() doesn't crash.
1014 parser = OptionParser(usage=SUPPRESS_USAGE)
1015 parser.remove_option("-h")
1016 parser.add_option("-t", "--test", action="callback",
1017 callback=lambda: None, type="string",
1018 help="foo")
1019
1020 expected_help = ("options:\n"
1021 " -t TEST, --test=TEST foo\n")
1022 self.assertHelp(parser, expected_help)
1023
1024
1025class TestCallbackExtraArgs(BaseTest):
Greg Ward55493222003-04-21 02:41:25 +00001026 def setUp(self):
1027 options = [make_option("-p", "--point", action="callback",
1028 callback=self.process_tuple,
1029 callback_args=(3, int), type="string",
1030 dest="points", default=[])]
1031 self.parser = OptionParser(option_list=options)
1032
1033 def process_tuple (self, option, opt, value, parser_, len, type):
1034 self.assertEqual(len, 3)
1035 self.assert_(type is int)
1036
1037 if opt == "-p":
1038 self.assertEqual(value, "1,2,3")
1039 elif opt == "--point":
1040 self.assertEqual(value, "4,5,6")
1041
1042 value = tuple(map(type, value.split(",")))
1043 getattr(parser_.values, option.dest).append(value)
1044
1045 def test_callback_extra_args(self):
1046 self.assertParseOK(["-p1,2,3", "--point", "4,5,6"],
1047 {'points': [(1,2,3), (4,5,6)]},
1048 [])
1049
Greg Wardeba20e62004-07-31 16:15:44 +00001050class TestCallbackMeddleArgs(BaseTest):
Greg Ward55493222003-04-21 02:41:25 +00001051 def setUp(self):
1052 options = [make_option(str(x), action="callback",
1053 callback=self.process_n, dest='things')
1054 for x in range(-1, -6, -1)]
1055 self.parser = OptionParser(option_list=options)
1056
1057 # Callback that meddles in rargs, largs
1058 def process_n (self, option, opt, value, parser_):
1059 # option is -3, -5, etc.
1060 nargs = int(opt[1:])
1061 rargs = parser_.rargs
1062 if len(rargs) < nargs:
1063 self.fail("Expected %d arguments for %s option." % (nargs, opt))
1064 dest = parser_.values.ensure_value(option.dest, [])
1065 dest.append(tuple(rargs[0:nargs]))
1066 parser_.largs.append(nargs)
1067 del rargs[0:nargs]
1068
1069 def test_callback_meddle_args(self):
1070 self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"],
1071 {'things': [("foo",), ("bar", "baz", "qux")]},
1072 [1, 3])
1073
1074 def test_callback_meddle_args_separator(self):
1075 self.assertParseOK(["-2", "foo", "--"],
1076 {'things': [('foo', '--')]},
1077 [2])
1078
Greg Wardeba20e62004-07-31 16:15:44 +00001079class TestCallbackManyArgs(BaseTest):
Greg Ward55493222003-04-21 02:41:25 +00001080 def setUp(self):
1081 options = [make_option("-a", "--apple", action="callback", nargs=2,
1082 callback=self.process_many, type="string"),
1083 make_option("-b", "--bob", action="callback", nargs=3,
1084 callback=self.process_many, type="int")]
1085 self.parser = OptionParser(option_list=options)
1086
1087 def process_many (self, option, opt, value, parser_):
1088 if opt == "-a":
1089 self.assertEqual(value, ("foo", "bar"))
1090 elif opt == "--apple":
1091 self.assertEqual(value, ("ding", "dong"))
1092 elif opt == "-b":
1093 self.assertEqual(value, (1, 2, 3))
1094 elif opt == "--bob":
1095 self.assertEqual(value, (-666, 42, 0))
1096
1097 def test_many_args(self):
1098 self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
1099 "-b", "1", "2", "3", "--bob", "-666", "42",
1100 "0"],
Greg Wardeba20e62004-07-31 16:15:44 +00001101 {"apple": None, "bob": None},
Greg Ward55493222003-04-21 02:41:25 +00001102 [])
1103
Greg Wardeba20e62004-07-31 16:15:44 +00001104class TestCallbackCheckAbbrev(BaseTest):
Greg Ward55493222003-04-21 02:41:25 +00001105 def setUp(self):
1106 self.parser = OptionParser()
1107 self.parser.add_option("--foo-bar", action="callback",
1108 callback=self.check_abbrev)
1109
1110 def check_abbrev (self, option, opt, value, parser):
1111 self.assertEqual(opt, "--foo-bar")
1112
1113 def test_abbrev_callback_expansion(self):
1114 self.assertParseOK(["--foo"], {}, [])
1115
Greg Wardeba20e62004-07-31 16:15:44 +00001116class TestCallbackVarArgs(BaseTest):
Greg Ward55493222003-04-21 02:41:25 +00001117 def setUp(self):
1118 options = [make_option("-a", type="int", nargs=2, dest="a"),
1119 make_option("-b", action="store_true", dest="b"),
1120 make_option("-c", "--callback", action="callback",
1121 callback=self.variable_args, dest="c")]
1122 self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
1123
1124 def variable_args (self, option, opt, value, parser):
1125 self.assert_(value is None)
1126 done = 0
1127 value = []
1128 rargs = parser.rargs
1129 while rargs:
1130 arg = rargs[0]
1131 if ((arg[:2] == "--" and len(arg) > 2) or
1132 (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
1133 break
1134 else:
1135 value.append(arg)
1136 del rargs[0]
1137 setattr(parser.values, option.dest, value)
1138
1139 def test_variable_args(self):
1140 self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"],
1141 {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]},
1142 [])
1143
1144 def test_consume_separator_stop_at_option(self):
1145 self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"],
1146 {'a': None,
1147 'b': True,
1148 'c': ["37", "--", "xxx"]},
1149 ["hello"])
1150
1151 def test_positional_arg_and_variable_args(self):
1152 self.assertParseOK(["hello", "-c", "foo", "-", "bar"],
1153 {'a': None,
1154 'b': None,
1155 'c':["foo", "-", "bar"]},
1156 ["hello"])
1157
1158 def test_stop_at_option(self):
1159 self.assertParseOK(["-c", "foo", "-b"],
1160 {'a': None, 'b': True, 'c': ["foo"]},
1161 [])
1162
1163 def test_stop_at_invalid_option(self):
1164 self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5")
1165
1166
1167# -- Test conflict handling and parser.parse_args() --------------------
1168
1169class ConflictBase(BaseTest):
1170 def setUp(self):
1171 options = [make_option("-v", "--verbose", action="count",
1172 dest="verbose", help="increment verbosity")]
1173 self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
1174
1175 def show_version (self, option, opt, value, parser):
1176 parser.values.show_version = 1
1177
1178class TestConflict(ConflictBase):
1179 """Use the default conflict resolution for Optik 1.2: error."""
1180 def assert_conflict_error(self, func):
Greg Wardeba20e62004-07-31 16:15:44 +00001181 err = self.assertRaises(
1182 func, ("-v", "--version"), {'action' : "callback",
1183 'callback' : self.show_version,
1184 'help' : "show version"},
1185 OptionConflictError,
1186 "option -v/--version: conflicting option string(s): -v")
Greg Ward55493222003-04-21 02:41:25 +00001187
1188 self.assertEqual(err.msg, "conflicting option string(s): -v")
1189 self.assertEqual(err.option_id, "-v/--version")
1190
1191 def test_conflict_error(self):
1192 self.assert_conflict_error(self.parser.add_option)
1193
1194 def test_conflict_error_group(self):
1195 group = OptionGroup(self.parser, "Group 1")
1196 self.assert_conflict_error(group.add_option)
1197
1198 def test_no_such_conflict_handler(self):
Greg Wardeba20e62004-07-31 16:15:44 +00001199 self.assertRaises(
1200 self.parser.set_conflict_handler, ('foo',), None,
1201 ValueError, "invalid conflict_resolution value 'foo'")
Greg Ward55493222003-04-21 02:41:25 +00001202
1203
1204class TestConflictIgnore(ConflictBase):
1205 """Test the old (Optik <= 1.1 behaviour) -- arguably broken, but
1206 still available so should be tested.
1207 """
1208
1209 def setUp(self):
1210 ConflictBase.setUp(self)
1211 self.parser.set_conflict_handler("ignore")
1212 self.parser.add_option("-v", "--version", action="callback",
1213 callback=self.show_version, help="show version")
1214
1215 def test_conflict_ignore(self):
1216 v_opt = self.parser.get_option("-v")
1217 verbose_opt = self.parser.get_option("--verbose")
1218 version_opt = self.parser.get_option("--version")
1219
1220 self.assert_(v_opt is version_opt)
1221 self.assert_(v_opt is not verbose_opt)
1222 self.assertEqual(v_opt._long_opts, ["--version"])
1223 self.assertEqual(version_opt._short_opts, ["-v"])
1224 self.assertEqual(verbose_opt._short_opts, ["-v"])
1225
1226 def test_conflict_ignore_help(self):
1227 self.assertStdoutEquals(["-h"], """\
1228options:
1229 -v, --verbose increment verbosity
1230 -h, --help show this help message and exit
1231 -v, --version show version
1232""")
1233
1234 def test_conflict_ignore_short_opt(self):
1235 self.assertParseOK(["-v"],
1236 {'show_version': 1, 'verbose': None},
1237 [])
1238
1239class TestConflictResolve(ConflictBase):
1240 def setUp(self):
1241 ConflictBase.setUp(self)
1242 self.parser.set_conflict_handler("resolve")
1243 self.parser.add_option("-v", "--version", action="callback",
1244 callback=self.show_version, help="show version")
1245
1246 def test_conflict_resolve(self):
1247 v_opt = self.parser.get_option("-v")
1248 verbose_opt = self.parser.get_option("--verbose")
1249 version_opt = self.parser.get_option("--version")
1250
1251 self.assert_(v_opt is version_opt)
1252 self.assert_(v_opt is not verbose_opt)
1253 self.assertEqual(v_opt._long_opts, ["--version"])
1254 self.assertEqual(version_opt._short_opts, ["-v"])
1255 self.assertEqual(version_opt._long_opts, ["--version"])
1256 self.assertEqual(verbose_opt._short_opts, [])
1257 self.assertEqual(verbose_opt._long_opts, ["--verbose"])
1258
1259 def test_conflict_resolve_help(self):
1260 self.assertStdoutEquals(["-h"], """\
1261options:
1262 --verbose increment verbosity
1263 -h, --help show this help message and exit
1264 -v, --version show version
1265""")
1266
1267 def test_conflict_resolve_short_opt(self):
1268 self.assertParseOK(["-v"],
1269 {'verbose': None, 'show_version': 1},
1270 [])
1271
1272 def test_conflict_resolve_long_opt(self):
1273 self.assertParseOK(["--verbose"],
1274 {'verbose': 1},
1275 [])
1276
1277 def test_conflict_resolve_long_opts(self):
1278 self.assertParseOK(["--verbose", "--version"],
1279 {'verbose': 1, 'show_version': 1},
1280 [])
1281
1282class TestConflictOverride(BaseTest):
1283 def setUp(self):
1284 self.parser = OptionParser(usage=SUPPRESS_USAGE)
1285 self.parser.set_conflict_handler("resolve")
1286 self.parser.add_option("-n", "--dry-run",
1287 action="store_true", dest="dry_run",
1288 help="don't do anything")
1289 self.parser.add_option("--dry-run", "-n",
1290 action="store_const", const=42, dest="dry_run",
1291 help="dry run mode")
1292
1293 def test_conflict_override_opts(self):
1294 opt = self.parser.get_option("--dry-run")
1295 self.assertEqual(opt._short_opts, ["-n"])
1296 self.assertEqual(opt._long_opts, ["--dry-run"])
1297
1298 def test_conflict_override_help(self):
1299 self.assertStdoutEquals(["-h"], """\
1300options:
1301 -h, --help show this help message and exit
1302 -n, --dry-run dry run mode
1303""")
1304
1305 def test_conflict_override_args(self):
1306 self.assertParseOK(["-n"],
1307 {'dry_run': 42},
1308 [])
1309
1310# -- Other testing. ----------------------------------------------------
1311
Greg Wardeba20e62004-07-31 16:15:44 +00001312_expected_help_basic = """\
1313usage: bar.py [options]
1314
1315options:
1316 -a APPLE throw APPLEs at basket
1317 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
1318 evil spirits that cause trouble and mayhem)
1319 --foo=FOO store FOO in the foo list for later fooing
1320 -h, --help show this help message and exit
1321"""
1322
1323_expected_help_long_opts_first = """\
1324usage: bar.py [options]
1325
1326options:
1327 -a APPLE throw APPLEs at basket
1328 --boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
1329 evil spirits that cause trouble and mayhem)
1330 --foo=FOO store FOO in the foo list for later fooing
1331 --help, -h show this help message and exit
1332"""
1333
1334_expected_help_title_formatter = """\
1335Usage
1336=====
1337 bar.py [options]
1338
1339options
1340=======
1341-a APPLE throw APPLEs at basket
1342--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
1343 evil spirits that cause trouble and mayhem)
1344--foo=FOO store FOO in the foo list for later fooing
1345--help, -h show this help message and exit
1346"""
1347
1348_expected_help_short_lines = """\
1349usage: bar.py [options]
1350
1351options:
1352 -a APPLE throw APPLEs at basket
1353 -b NUM, --boo=NUM shout "boo!" NUM times (in order to
1354 frighten away all the evil spirits
1355 that cause trouble and mayhem)
1356 --foo=FOO store FOO in the foo list for later
1357 fooing
1358 -h, --help show this help message and exit
1359"""
1360
Greg Ward55493222003-04-21 02:41:25 +00001361class TestHelp(BaseTest):
1362 def setUp(self):
Greg Wardeba20e62004-07-31 16:15:44 +00001363 self.parser = self.make_parser(80)
1364
1365 def make_parser(self, columns):
Greg Ward55493222003-04-21 02:41:25 +00001366 options = [
1367 make_option("-a", type="string", dest='a',
1368 metavar="APPLE", help="throw APPLEs at basket"),
1369 make_option("-b", "--boo", type="int", dest='boo',
1370 metavar="NUM",
1371 help=
1372 "shout \"boo!\" NUM times (in order to frighten away "
1373 "all the evil spirits that cause trouble and mayhem)"),
1374 make_option("--foo", action="append", type="string", dest='foo',
1375 help="store FOO in the foo list for later fooing"),
1376 ]
Greg Wardeba20e62004-07-31 16:15:44 +00001377 os.environ['COLUMNS'] = str(columns)
Tim Petersc0cbc862004-07-31 21:17:37 +00001378 return OptionParser(option_list=options)
Greg Ward55493222003-04-21 02:41:25 +00001379
1380 def assertHelpEquals(self, expected_output):
1381 # This trick is used to make optparse believe bar.py is being executed.
1382 oldargv = sys.argv[0]
1383 sys.argv[0] = "./foo/bar.py"
1384
1385 self.assertStdoutEquals(["-h"], expected_output)
1386
1387 sys.argv[0] = oldargv
1388
1389 def test_help(self):
Greg Wardeba20e62004-07-31 16:15:44 +00001390 self.assertHelpEquals(_expected_help_basic)
Greg Ward55493222003-04-21 02:41:25 +00001391
1392 def test_help_old_usage(self):
1393 self.parser.set_usage("usage: %prog [options]")
Greg Wardeba20e62004-07-31 16:15:44 +00001394 self.assertHelpEquals(_expected_help_basic)
Greg Ward55493222003-04-21 02:41:25 +00001395
1396 def test_help_long_opts_first(self):
1397 self.parser.formatter.short_first = 0
Greg Wardeba20e62004-07-31 16:15:44 +00001398 self.assertHelpEquals(_expected_help_long_opts_first)
Greg Ward55493222003-04-21 02:41:25 +00001399
1400 def test_help_title_formatter(self):
1401 self.parser.formatter = TitledHelpFormatter()
Greg Wardeba20e62004-07-31 16:15:44 +00001402 self.assertHelpEquals(_expected_help_title_formatter)
Greg Ward55493222003-04-21 02:41:25 +00001403
Greg Wardeba20e62004-07-31 16:15:44 +00001404 def test_wrap_columns(self):
1405 # Ensure that wrapping respects $COLUMNS environment variable.
1406 # Need to reconstruct the parser, since that's the only time
1407 # we look at $COLUMNS.
1408 self.parser = self.make_parser(60)
1409 self.assertHelpEquals(_expected_help_short_lines)
Greg Ward55493222003-04-21 02:41:25 +00001410
1411 def test_help_description_groups(self):
1412 self.parser.set_description(
Greg Wardeba20e62004-07-31 16:15:44 +00001413 "This is the program description for %prog. %prog has "
Greg Ward55493222003-04-21 02:41:25 +00001414 "an option group as well as single options.")
1415
1416 group = OptionGroup(
1417 self.parser, "Dangerous Options",
1418 "Caution: use of these options is at your own risk. "
1419 "It is believed that some of them bite.")
1420 group.add_option("-g", action="store_true", help="Group option.")
1421 self.parser.add_option_group(group)
1422
1423 self.assertHelpEquals("""\
1424usage: bar.py [options]
1425
Greg Wardeba20e62004-07-31 16:15:44 +00001426This is the program description for bar.py. bar.py has an option group as
1427well as single options.
1428
Greg Ward55493222003-04-21 02:41:25 +00001429options:
Greg Wardeba20e62004-07-31 16:15:44 +00001430 -a APPLE throw APPLEs at basket
1431 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
1432 evil spirits that cause trouble and mayhem)
1433 --foo=FOO store FOO in the foo list for later fooing
1434 -h, --help show this help message and exit
Greg Ward55493222003-04-21 02:41:25 +00001435
1436 Dangerous Options:
Greg Wardeba20e62004-07-31 16:15:44 +00001437 Caution: use of these options is at your own risk. It is believed
1438 that some of them bite.
1439
1440 -g Group option.
Greg Ward55493222003-04-21 02:41:25 +00001441""")
1442
Greg Wardeba20e62004-07-31 16:15:44 +00001443
Tim Petersc0cbc862004-07-31 21:17:37 +00001444
Greg Wardeba20e62004-07-31 16:15:44 +00001445
Greg Ward55493222003-04-21 02:41:25 +00001446class TestMatchAbbrev(BaseTest):
1447 def test_match_abbrev(self):
1448 self.assertEqual(_match_abbrev("--f",
1449 {"--foz": None,
1450 "--foo": None,
1451 "--fie": None,
1452 "--f": None}),
1453 "--f")
1454
1455 def test_match_abbrev_error(self):
1456 s = "--f"
1457 wordmap = {"--foz": None, "--foo": None, "--fie": None}
1458 possibilities = ", ".join(wordmap.keys())
Greg Wardeba20e62004-07-31 16:15:44 +00001459 self.assertRaises(
1460 _match_abbrev, (s, wordmap), None,
1461 BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
1462
1463
1464def _testclasses():
1465 mod = sys.modules[__name__]
1466 return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
1467
1468def suite():
1469 suite = unittest.TestSuite()
1470 for testclass in _testclasses():
1471 suite.addTest(unittest.makeSuite(testclass))
1472 return suite
Greg Ward55493222003-04-21 02:41:25 +00001473
Greg Ward55493222003-04-21 02:41:25 +00001474def test_main():
Greg Wardeba20e62004-07-31 16:15:44 +00001475 test_support.run_suite(suite())
Greg Ward55493222003-04-21 02:41:25 +00001476
1477if __name__ == '__main__':
1478 unittest.main()