1# 2# Test suite for Optik. Supplied by Johannes Gijsbers 3# (taradino@softhome.net) -- translated from the original Optik 4# test suite to this PyUnit-based version. 5# 6# $Id$ 7# 8 9import sys 10import os 11import re 12import copy 13import unittest 14 15from io import StringIO 16from test import support 17 18 19import optparse 20from optparse import make_option, Option, \ 21 TitledHelpFormatter, OptionParser, OptionGroup, \ 22 SUPPRESS_USAGE, OptionError, OptionConflictError, \ 23 BadOptionError, OptionValueError, Values 24from optparse import _match_abbrev 25from optparse import _parse_num 26 27class InterceptedError(Exception): 28 def __init__(self, 29 error_message=None, 30 exit_status=None, 31 exit_message=None): 32 self.error_message = error_message 33 self.exit_status = exit_status 34 self.exit_message = exit_message 35 36 def __str__(self): 37 return self.error_message or self.exit_message or "intercepted error" 38 39class InterceptingOptionParser(OptionParser): 40 def exit(self, status=0, msg=None): 41 raise InterceptedError(exit_status=status, exit_message=msg) 42 43 def error(self, msg): 44 raise InterceptedError(error_message=msg) 45 46 47class BaseTest(unittest.TestCase): 48 def assertParseOK(self, args, expected_opts, expected_positional_args): 49 """Assert the options are what we expected when parsing arguments. 50 51 Otherwise, fail with a nicely formatted message. 52 53 Keyword arguments: 54 args -- A list of arguments to parse with OptionParser. 55 expected_opts -- The options expected. 56 expected_positional_args -- The positional arguments expected. 57 58 Returns the options and positional args for further testing. 59 """ 60 61 (options, positional_args) = self.parser.parse_args(args) 62 optdict = vars(options) 63 64 self.assertEqual(optdict, expected_opts, 65 """ 66Options are %(optdict)s. 67Should be %(expected_opts)s. 68Args were %(args)s.""" % locals()) 69 70 self.assertEqual(positional_args, expected_positional_args, 71 """ 72Positional arguments are %(positional_args)s. 73Should be %(expected_positional_args)s. 74Args were %(args)s.""" % locals ()) 75 76 return (options, positional_args) 77 78 def assertRaises(self, 79 func, 80 args, 81 kwargs, 82 expected_exception, 83 expected_message): 84 """ 85 Assert that the expected exception is raised when calling a 86 function, and that the right error message is included with 87 that exception. 88 89 Arguments: 90 func -- the function to call 91 args -- positional arguments to `func` 92 kwargs -- keyword arguments to `func` 93 expected_exception -- exception that should be raised 94 expected_message -- expected exception message (or pattern 95 if a compiled regex object) 96 97 Returns the exception raised for further testing. 98 """ 99 if args is None: 100 args = () 101 if kwargs is None: 102 kwargs = {} 103 104 try: 105 func(*args, **kwargs) 106 except expected_exception as err: 107 actual_message = str(err) 108 if isinstance(expected_message, re.Pattern): 109 self.assertTrue(expected_message.search(actual_message), 110 """\ 111expected exception message pattern: 112/%s/ 113actual exception message: 114'''%s''' 115""" % (expected_message.pattern, actual_message)) 116 else: 117 self.assertEqual(actual_message, 118 expected_message, 119 """\ 120expected exception message: 121'''%s''' 122actual exception message: 123'''%s''' 124""" % (expected_message, actual_message)) 125 126 return err 127 else: 128 self.fail("""expected exception %(expected_exception)s not raised 129called %(func)r 130with args %(args)r 131and kwargs %(kwargs)r 132""" % locals ()) 133 134 135 # -- Assertions used in more than one class -------------------- 136 137 def assertParseFail(self, cmdline_args, expected_output): 138 """ 139 Assert the parser fails with the expected message. Caller 140 must ensure that self.parser is an InterceptingOptionParser. 141 """ 142 try: 143 self.parser.parse_args(cmdline_args) 144 except InterceptedError as err: 145 self.assertEqual(err.error_message, expected_output) 146 else: 147 self.assertFalse("expected parse failure") 148 149 def assertOutput(self, 150 cmdline_args, 151 expected_output, 152 expected_status=0, 153 expected_error=None): 154 """Assert the parser prints the expected output on stdout.""" 155 save_stdout = sys.stdout 156 try: 157 try: 158 sys.stdout = StringIO() 159 self.parser.parse_args(cmdline_args) 160 finally: 161 output = sys.stdout.getvalue() 162 sys.stdout = save_stdout 163 164 except InterceptedError as err: 165 self.assertTrue( 166 isinstance(output, str), 167 "expected output to be an ordinary string, not %r" 168 % type(output)) 169 170 if output != expected_output: 171 self.fail("expected: \n'''\n" + expected_output + 172 "'''\nbut got \n'''\n" + output + "'''") 173 self.assertEqual(err.exit_status, expected_status) 174 self.assertEqual(err.exit_message, expected_error) 175 else: 176 self.assertFalse("expected parser.exit()") 177 178 def assertTypeError(self, func, expected_message, *args): 179 """Assert that TypeError is raised when executing func.""" 180 self.assertRaises(func, args, None, TypeError, expected_message) 181 182 def assertHelp(self, parser, expected_help): 183 actual_help = parser.format_help() 184 if actual_help != expected_help: 185 raise self.failureException( 186 'help text failure; expected:\n"' + 187 expected_help + '"; got:\n"' + 188 actual_help + '"\n') 189 190# -- Test make_option() aka Option ------------------------------------- 191 192# It's not necessary to test correct options here. All the tests in the 193# parser.parse_args() section deal with those, because they're needed 194# there. 195 196class TestOptionChecks(BaseTest): 197 def setUp(self): 198 self.parser = OptionParser(usage=SUPPRESS_USAGE) 199 200 def assertOptionError(self, expected_message, args=[], kwargs={}): 201 self.assertRaises(make_option, args, kwargs, 202 OptionError, expected_message) 203 204 def test_opt_string_empty(self): 205 self.assertTypeError(make_option, 206 "at least one option string must be supplied") 207 208 def test_opt_string_too_short(self): 209 self.assertOptionError( 210 "invalid option string 'b': must be at least two characters long", 211 ["b"]) 212 213 def test_opt_string_short_invalid(self): 214 self.assertOptionError( 215 "invalid short option string '--': must be " 216 "of the form -x, (x any non-dash char)", 217 ["--"]) 218 219 def test_opt_string_long_invalid(self): 220 self.assertOptionError( 221 "invalid long option string '---': " 222 "must start with --, followed by non-dash", 223 ["---"]) 224 225 def test_attr_invalid(self): 226 self.assertOptionError( 227 "option -b: invalid keyword arguments: bar, foo", 228 ["-b"], {'foo': None, 'bar': None}) 229 230 def test_action_invalid(self): 231 self.assertOptionError( 232 "option -b: invalid action: 'foo'", 233 ["-b"], {'action': 'foo'}) 234 235 def test_type_invalid(self): 236 self.assertOptionError( 237 "option -b: invalid option type: 'foo'", 238 ["-b"], {'type': 'foo'}) 239 self.assertOptionError( 240 "option -b: invalid option type: 'tuple'", 241 ["-b"], {'type': tuple}) 242 243 def test_no_type_for_action(self): 244 self.assertOptionError( 245 "option -b: must not supply a type for action 'count'", 246 ["-b"], {'action': 'count', 'type': 'int'}) 247 248 def test_no_choices_list(self): 249 self.assertOptionError( 250 "option -b/--bad: must supply a list of " 251 "choices for type 'choice'", 252 ["-b", "--bad"], {'type': "choice"}) 253 254 def test_bad_choices_list(self): 255 typename = type('').__name__ 256 self.assertOptionError( 257 "option -b/--bad: choices must be a list of " 258 "strings ('%s' supplied)" % typename, 259 ["-b", "--bad"], 260 {'type': "choice", 'choices':"bad choices"}) 261 262 def test_no_choices_for_type(self): 263 self.assertOptionError( 264 "option -b: must not supply choices for type 'int'", 265 ["-b"], {'type': 'int', 'choices':"bad"}) 266 267 def test_no_const_for_action(self): 268 self.assertOptionError( 269 "option -b: 'const' must not be supplied for action 'store'", 270 ["-b"], {'action': 'store', 'const': 1}) 271 272 def test_no_nargs_for_action(self): 273 self.assertOptionError( 274 "option -b: 'nargs' must not be supplied for action 'count'", 275 ["-b"], {'action': 'count', 'nargs': 2}) 276 277 def test_callback_not_callable(self): 278 self.assertOptionError( 279 "option -b: callback not callable: 'foo'", 280 ["-b"], {'action': 'callback', 281 'callback': 'foo'}) 282 283 def dummy(self): 284 pass 285 286 def test_callback_args_no_tuple(self): 287 self.assertOptionError( 288 "option -b: callback_args, if supplied, " 289 "must be a tuple: not 'foo'", 290 ["-b"], {'action': 'callback', 291 'callback': self.dummy, 292 'callback_args': 'foo'}) 293 294 def test_callback_kwargs_no_dict(self): 295 self.assertOptionError( 296 "option -b: callback_kwargs, if supplied, " 297 "must be a dict: not 'foo'", 298 ["-b"], {'action': 'callback', 299 'callback': self.dummy, 300 'callback_kwargs': 'foo'}) 301 302 def test_no_callback_for_action(self): 303 self.assertOptionError( 304 "option -b: callback supplied ('foo') for non-callback option", 305 ["-b"], {'action': 'store', 306 'callback': 'foo'}) 307 308 def test_no_callback_args_for_action(self): 309 self.assertOptionError( 310 "option -b: callback_args supplied for non-callback option", 311 ["-b"], {'action': 'store', 312 'callback_args': 'foo'}) 313 314 def test_no_callback_kwargs_for_action(self): 315 self.assertOptionError( 316 "option -b: callback_kwargs supplied for non-callback option", 317 ["-b"], {'action': 'store', 318 'callback_kwargs': 'foo'}) 319 320 def test_no_single_dash(self): 321 self.assertOptionError( 322 "invalid long option string '-debug': " 323 "must start with --, followed by non-dash", 324 ["-debug"]) 325 326 self.assertOptionError( 327 "option -d: invalid long option string '-debug': must start with" 328 " --, followed by non-dash", 329 ["-d", "-debug"]) 330 331 self.assertOptionError( 332 "invalid long option string '-debug': " 333 "must start with --, followed by non-dash", 334 ["-debug", "--debug"]) 335 336class TestOptionParser(BaseTest): 337 def setUp(self): 338 self.parser = OptionParser() 339 self.parser.add_option("-v", "--verbose", "-n", "--noisy", 340 action="store_true", dest="verbose") 341 self.parser.add_option("-q", "--quiet", "--silent", 342 action="store_false", dest="verbose") 343 344 def test_add_option_no_Option(self): 345 self.assertTypeError(self.parser.add_option, 346 "not an Option instance: None", None) 347 348 def test_add_option_invalid_arguments(self): 349 self.assertTypeError(self.parser.add_option, 350 "invalid arguments", None, None) 351 352 def test_get_option(self): 353 opt1 = self.parser.get_option("-v") 354 self.assertIsInstance(opt1, Option) 355 self.assertEqual(opt1._short_opts, ["-v", "-n"]) 356 self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"]) 357 self.assertEqual(opt1.action, "store_true") 358 self.assertEqual(opt1.dest, "verbose") 359 360 def test_get_option_equals(self): 361 opt1 = self.parser.get_option("-v") 362 opt2 = self.parser.get_option("--verbose") 363 opt3 = self.parser.get_option("-n") 364 opt4 = self.parser.get_option("--noisy") 365 self.assertTrue(opt1 is opt2 is opt3 is opt4) 366 367 def test_has_option(self): 368 self.assertTrue(self.parser.has_option("-v")) 369 self.assertTrue(self.parser.has_option("--verbose")) 370 371 def assertTrueremoved(self): 372 self.assertTrue(self.parser.get_option("-v") is None) 373 self.assertTrue(self.parser.get_option("--verbose") is None) 374 self.assertTrue(self.parser.get_option("-n") is None) 375 self.assertTrue(self.parser.get_option("--noisy") is None) 376 377 self.assertFalse(self.parser.has_option("-v")) 378 self.assertFalse(self.parser.has_option("--verbose")) 379 self.assertFalse(self.parser.has_option("-n")) 380 self.assertFalse(self.parser.has_option("--noisy")) 381 382 self.assertTrue(self.parser.has_option("-q")) 383 self.assertTrue(self.parser.has_option("--silent")) 384 385 def test_remove_short_opt(self): 386 self.parser.remove_option("-n") 387 self.assertTrueremoved() 388 389 def test_remove_long_opt(self): 390 self.parser.remove_option("--verbose") 391 self.assertTrueremoved() 392 393 def test_remove_nonexistent(self): 394 self.assertRaises(self.parser.remove_option, ('foo',), None, 395 ValueError, "no such option 'foo'") 396 397 @support.impl_detail('Relies on sys.getrefcount', cpython=True) 398 def test_refleak(self): 399 # If an OptionParser is carrying around a reference to a large 400 # object, various cycles can prevent it from being GC'd in 401 # a timely fashion. destroy() breaks the cycles to ensure stuff 402 # can be cleaned up. 403 big_thing = [42] 404 refcount = sys.getrefcount(big_thing) 405 parser = OptionParser() 406 parser.add_option("-a", "--aaarggh") 407 parser.big_thing = big_thing 408 409 parser.destroy() 410 #self.assertEqual(refcount, sys.getrefcount(big_thing)) 411 del parser 412 self.assertEqual(refcount, sys.getrefcount(big_thing)) 413 414 415class TestOptionValues(BaseTest): 416 def setUp(self): 417 pass 418 419 def test_basics(self): 420 values = Values() 421 self.assertEqual(vars(values), {}) 422 self.assertEqual(values, {}) 423 self.assertNotEqual(values, {"foo": "bar"}) 424 self.assertNotEqual(values, "") 425 426 dict = {"foo": "bar", "baz": 42} 427 values = Values(defaults=dict) 428 self.assertEqual(vars(values), dict) 429 self.assertEqual(values, dict) 430 self.assertNotEqual(values, {"foo": "bar"}) 431 self.assertNotEqual(values, {}) 432 self.assertNotEqual(values, "") 433 self.assertNotEqual(values, []) 434 435 436class TestTypeAliases(BaseTest): 437 def setUp(self): 438 self.parser = OptionParser() 439 440 def test_str_aliases_string(self): 441 self.parser.add_option("-s", type="str") 442 self.assertEqual(self.parser.get_option("-s").type, "string") 443 444 def test_type_object(self): 445 self.parser.add_option("-s", type=str) 446 self.assertEqual(self.parser.get_option("-s").type, "string") 447 self.parser.add_option("-x", type=int) 448 self.assertEqual(self.parser.get_option("-x").type, "int") 449 450 451# Custom type for testing processing of default values. 452_time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 } 453 454def _check_duration(option, opt, value): 455 try: 456 if value[-1].isdigit(): 457 return int(value) 458 else: 459 return int(value[:-1]) * _time_units[value[-1]] 460 except (ValueError, IndexError): 461 raise OptionValueError( 462 'option %s: invalid duration: %r' % (opt, value)) 463 464class DurationOption(Option): 465 TYPES = Option.TYPES + ('duration',) 466 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER) 467 TYPE_CHECKER['duration'] = _check_duration 468 469class TestDefaultValues(BaseTest): 470 def setUp(self): 471 self.parser = OptionParser() 472 self.parser.add_option("-v", "--verbose", default=True) 473 self.parser.add_option("-q", "--quiet", dest='verbose') 474 self.parser.add_option("-n", type="int", default=37) 475 self.parser.add_option("-m", type="int") 476 self.parser.add_option("-s", default="foo") 477 self.parser.add_option("-t") 478 self.parser.add_option("-u", default=None) 479 self.expected = { 'verbose': True, 480 'n': 37, 481 'm': None, 482 's': "foo", 483 't': None, 484 'u': None } 485 486 def test_basic_defaults(self): 487 self.assertEqual(self.parser.get_default_values(), self.expected) 488 489 def test_mixed_defaults_post(self): 490 self.parser.set_defaults(n=42, m=-100) 491 self.expected.update({'n': 42, 'm': -100}) 492 self.assertEqual(self.parser.get_default_values(), self.expected) 493 494 def test_mixed_defaults_pre(self): 495 self.parser.set_defaults(x="barf", y="blah") 496 self.parser.add_option("-x", default="frob") 497 self.parser.add_option("-y") 498 499 self.expected.update({'x': "frob", 'y': "blah"}) 500 self.assertEqual(self.parser.get_default_values(), self.expected) 501 502 self.parser.remove_option("-y") 503 self.parser.add_option("-y", default=None) 504 self.expected.update({'y': None}) 505 self.assertEqual(self.parser.get_default_values(), self.expected) 506 507 def test_process_default(self): 508 self.parser.option_class = DurationOption 509 self.parser.add_option("-d", type="duration", default=300) 510 self.parser.add_option("-e", type="duration", default="6m") 511 self.parser.set_defaults(n="42") 512 self.expected.update({'d': 300, 'e': 360, 'n': 42}) 513 self.assertEqual(self.parser.get_default_values(), self.expected) 514 515 self.parser.set_process_default_values(False) 516 self.expected.update({'d': 300, 'e': "6m", 'n': "42"}) 517 self.assertEqual(self.parser.get_default_values(), self.expected) 518 519 520class TestProgName(BaseTest): 521 """ 522 Test that %prog expands to the right thing in usage, version, 523 and help strings. 524 """ 525 526 def assertUsage(self, parser, expected_usage): 527 self.assertEqual(parser.get_usage(), expected_usage) 528 529 def assertVersion(self, parser, expected_version): 530 self.assertEqual(parser.get_version(), expected_version) 531 532 533 def test_default_progname(self): 534 # Make sure that program name taken from sys.argv[0] by default. 535 save_argv = sys.argv[:] 536 try: 537 sys.argv[0] = os.path.join("foo", "bar", "baz.py") 538 parser = OptionParser("%prog ...", version="%prog 1.2") 539 expected_usage = "Usage: baz.py ...\n" 540 self.assertUsage(parser, expected_usage) 541 self.assertVersion(parser, "baz.py 1.2") 542 self.assertHelp(parser, 543 expected_usage + "\n" + 544 "Options:\n" 545 " --version show program's version number and exit\n" 546 " -h, --help show this help message and exit\n") 547 finally: 548 sys.argv[:] = save_argv 549 550 def test_custom_progname(self): 551 parser = OptionParser(prog="thingy", 552 version="%prog 0.1", 553 usage="%prog arg arg") 554 parser.remove_option("-h") 555 parser.remove_option("--version") 556 expected_usage = "Usage: thingy arg arg\n" 557 self.assertUsage(parser, expected_usage) 558 self.assertVersion(parser, "thingy 0.1") 559 self.assertHelp(parser, expected_usage + "\n") 560 561 562class TestExpandDefaults(BaseTest): 563 def setUp(self): 564 self.parser = OptionParser(prog="test") 565 self.help_prefix = """\ 566Usage: test [options] 567 568Options: 569 -h, --help show this help message and exit 570""" 571 self.file_help = "read from FILE [default: %default]" 572 self.expected_help_file = self.help_prefix + \ 573 " -f FILE, --file=FILE read from FILE [default: foo.txt]\n" 574 self.expected_help_none = self.help_prefix + \ 575 " -f FILE, --file=FILE read from FILE [default: none]\n" 576 577 def test_option_default(self): 578 self.parser.add_option("-f", "--file", 579 default="foo.txt", 580 help=self.file_help) 581 self.assertHelp(self.parser, self.expected_help_file) 582 583 def test_parser_default_1(self): 584 self.parser.add_option("-f", "--file", 585 help=self.file_help) 586 self.parser.set_default('file', "foo.txt") 587 self.assertHelp(self.parser, self.expected_help_file) 588 589 def test_parser_default_2(self): 590 self.parser.add_option("-f", "--file", 591 help=self.file_help) 592 self.parser.set_defaults(file="foo.txt") 593 self.assertHelp(self.parser, self.expected_help_file) 594 595 def test_no_default(self): 596 self.parser.add_option("-f", "--file", 597 help=self.file_help) 598 self.assertHelp(self.parser, self.expected_help_none) 599 600 def test_default_none_1(self): 601 self.parser.add_option("-f", "--file", 602 default=None, 603 help=self.file_help) 604 self.assertHelp(self.parser, self.expected_help_none) 605 606 def test_default_none_2(self): 607 self.parser.add_option("-f", "--file", 608 help=self.file_help) 609 self.parser.set_defaults(file=None) 610 self.assertHelp(self.parser, self.expected_help_none) 611 612 def test_float_default(self): 613 self.parser.add_option( 614 "-p", "--prob", 615 help="blow up with probability PROB [default: %default]") 616 self.parser.set_defaults(prob=0.43) 617 expected_help = self.help_prefix + \ 618 " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n" 619 self.assertHelp(self.parser, expected_help) 620 621 def test_alt_expand(self): 622 self.parser.add_option("-f", "--file", 623 default="foo.txt", 624 help="read from FILE [default: *DEFAULT*]") 625 self.parser.formatter.default_tag = "*DEFAULT*" 626 self.assertHelp(self.parser, self.expected_help_file) 627 628 def test_no_expand(self): 629 self.parser.add_option("-f", "--file", 630 default="foo.txt", 631 help="read from %default file") 632 self.parser.formatter.default_tag = None 633 expected_help = self.help_prefix + \ 634 " -f FILE, --file=FILE read from %default file\n" 635 self.assertHelp(self.parser, expected_help) 636 637 638# -- Test parser.parse_args() ------------------------------------------ 639 640class TestStandard(BaseTest): 641 def setUp(self): 642 options = [make_option("-a", type="string"), 643 make_option("-b", "--boo", type="int", dest='boo'), 644 make_option("--foo", action="append")] 645 646 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 647 option_list=options) 648 649 def test_required_value(self): 650 self.assertParseFail(["-a"], "-a option requires 1 argument") 651 652 def test_invalid_integer(self): 653 self.assertParseFail(["-b", "5x"], 654 "option -b: invalid integer value: '5x'") 655 656 def test_no_such_option(self): 657 self.assertParseFail(["--boo13"], "no such option: --boo13") 658 659 def test_long_invalid_integer(self): 660 self.assertParseFail(["--boo=x5"], 661 "option --boo: invalid integer value: 'x5'") 662 663 def test_empty(self): 664 self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, []) 665 666 def test_shortopt_empty_longopt_append(self): 667 self.assertParseOK(["-a", "", "--foo=blah", "--foo="], 668 {'a': "", 'boo': None, 'foo': ["blah", ""]}, 669 []) 670 671 def test_long_option_append(self): 672 self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"], 673 {'a': None, 674 'boo': None, 675 'foo': ["bar", "", "x"]}, 676 []) 677 678 def test_option_argument_joined(self): 679 self.assertParseOK(["-abc"], 680 {'a': "bc", 'boo': None, 'foo': None}, 681 []) 682 683 def test_option_argument_split(self): 684 self.assertParseOK(["-a", "34"], 685 {'a': "34", 'boo': None, 'foo': None}, 686 []) 687 688 def test_option_argument_joined_integer(self): 689 self.assertParseOK(["-b34"], 690 {'a': None, 'boo': 34, 'foo': None}, 691 []) 692 693 def test_option_argument_split_negative_integer(self): 694 self.assertParseOK(["-b", "-5"], 695 {'a': None, 'boo': -5, 'foo': None}, 696 []) 697 698 def test_long_option_argument_joined(self): 699 self.assertParseOK(["--boo=13"], 700 {'a': None, 'boo': 13, 'foo': None}, 701 []) 702 703 def test_long_option_argument_split(self): 704 self.assertParseOK(["--boo", "111"], 705 {'a': None, 'boo': 111, 'foo': None}, 706 []) 707 708 def test_long_option_short_option(self): 709 self.assertParseOK(["--foo=bar", "-axyz"], 710 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 711 []) 712 713 def test_abbrev_long_option(self): 714 self.assertParseOK(["--f=bar", "-axyz"], 715 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 716 []) 717 718 def test_defaults(self): 719 (options, args) = self.parser.parse_args([]) 720 defaults = self.parser.get_default_values() 721 self.assertEqual(vars(defaults), vars(options)) 722 723 def test_ambiguous_option(self): 724 self.parser.add_option("--foz", action="store", 725 type="string", dest="foo") 726 self.assertParseFail(["--f=bar"], 727 "ambiguous option: --f (--foo, --foz?)") 728 729 730 def test_short_and_long_option_split(self): 731 self.assertParseOK(["-a", "xyz", "--foo", "bar"], 732 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 733 []) 734 735 def test_short_option_split_long_option_append(self): 736 self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"], 737 {'a': None, 'boo': 123, 'foo': ["bar", "baz"]}, 738 []) 739 740 def test_short_option_split_one_positional_arg(self): 741 self.assertParseOK(["-a", "foo", "bar"], 742 {'a': "foo", 'boo': None, 'foo': None}, 743 ["bar"]) 744 745 def test_short_option_consumes_separator(self): 746 self.assertParseOK(["-a", "--", "foo", "bar"], 747 {'a': "--", 'boo': None, 'foo': None}, 748 ["foo", "bar"]) 749 self.assertParseOK(["-a", "--", "--foo", "bar"], 750 {'a': "--", 'boo': None, 'foo': ["bar"]}, 751 []) 752 753 def test_short_option_joined_and_separator(self): 754 self.assertParseOK(["-ab", "--", "--foo", "bar"], 755 {'a': "b", 'boo': None, 'foo': None}, 756 ["--foo", "bar"]), 757 758 def test_hyphen_becomes_positional_arg(self): 759 self.assertParseOK(["-ab", "-", "--foo", "bar"], 760 {'a': "b", 'boo': None, 'foo': ["bar"]}, 761 ["-"]) 762 763 def test_no_append_versus_append(self): 764 self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"], 765 {'a': None, 'boo': 5, 'foo': ["bar", "baz"]}, 766 []) 767 768 def test_option_consumes_optionlike_string(self): 769 self.assertParseOK(["-a", "-b3"], 770 {'a': "-b3", 'boo': None, 'foo': None}, 771 []) 772 773 def test_combined_single_invalid_option(self): 774 self.parser.add_option("-t", action="store_true") 775 self.assertParseFail(["-test"], 776 "no such option: -e") 777 778class TestBool(BaseTest): 779 def setUp(self): 780 options = [make_option("-v", 781 "--verbose", 782 action="store_true", 783 dest="verbose", 784 default=''), 785 make_option("-q", 786 "--quiet", 787 action="store_false", 788 dest="verbose")] 789 self.parser = OptionParser(option_list = options) 790 791 def test_bool_default(self): 792 self.assertParseOK([], 793 {'verbose': ''}, 794 []) 795 796 def test_bool_false(self): 797 (options, args) = self.assertParseOK(["-q"], 798 {'verbose': 0}, 799 []) 800 self.assertTrue(options.verbose is False) 801 802 def test_bool_true(self): 803 (options, args) = self.assertParseOK(["-v"], 804 {'verbose': 1}, 805 []) 806 self.assertTrue(options.verbose is True) 807 808 def test_bool_flicker_on_and_off(self): 809 self.assertParseOK(["-qvq", "-q", "-v"], 810 {'verbose': 1}, 811 []) 812 813class TestChoice(BaseTest): 814 def setUp(self): 815 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 816 self.parser.add_option("-c", action="store", type="choice", 817 dest="choice", choices=["one", "two", "three"]) 818 819 def test_valid_choice(self): 820 self.assertParseOK(["-c", "one", "xyz"], 821 {'choice': 'one'}, 822 ["xyz"]) 823 824 def test_invalid_choice(self): 825 self.assertParseFail(["-c", "four", "abc"], 826 "option -c: invalid choice: 'four' " 827 "(choose from 'one', 'two', 'three')") 828 829 def test_add_choice_option(self): 830 self.parser.add_option("-d", "--default", 831 choices=["four", "five", "six"]) 832 opt = self.parser.get_option("-d") 833 self.assertEqual(opt.type, "choice") 834 self.assertEqual(opt.action, "store") 835 836class TestCount(BaseTest): 837 def setUp(self): 838 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 839 self.v_opt = make_option("-v", action="count", dest="verbose") 840 self.parser.add_option(self.v_opt) 841 self.parser.add_option("--verbose", type="int", dest="verbose") 842 self.parser.add_option("-q", "--quiet", 843 action="store_const", dest="verbose", const=0) 844 845 def test_empty(self): 846 self.assertParseOK([], {'verbose': None}, []) 847 848 def test_count_one(self): 849 self.assertParseOK(["-v"], {'verbose': 1}, []) 850 851 def test_count_three(self): 852 self.assertParseOK(["-vvv"], {'verbose': 3}, []) 853 854 def test_count_three_apart(self): 855 self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, []) 856 857 def test_count_override_amount(self): 858 self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, []) 859 860 def test_count_override_quiet(self): 861 self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, []) 862 863 def test_count_overriding(self): 864 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], 865 {'verbose': 1}, []) 866 867 def test_count_interspersed_args(self): 868 self.assertParseOK(["--quiet", "3", "-v"], 869 {'verbose': 1}, 870 ["3"]) 871 872 def test_count_no_interspersed_args(self): 873 self.parser.disable_interspersed_args() 874 self.assertParseOK(["--quiet", "3", "-v"], 875 {'verbose': 0}, 876 ["3", "-v"]) 877 878 def test_count_no_such_option(self): 879 self.assertParseFail(["-q3", "-v"], "no such option: -3") 880 881 def test_count_option_no_value(self): 882 self.assertParseFail(["--quiet=3", "-v"], 883 "--quiet option does not take a value") 884 885 def test_count_with_default(self): 886 self.parser.set_default('verbose', 0) 887 self.assertParseOK([], {'verbose':0}, []) 888 889 def test_count_overriding_default(self): 890 self.parser.set_default('verbose', 0) 891 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], 892 {'verbose': 1}, []) 893 894class TestMultipleArgs(BaseTest): 895 def setUp(self): 896 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 897 self.parser.add_option("-p", "--point", 898 action="store", nargs=3, type="float", dest="point") 899 900 def test_nargs_with_positional_args(self): 901 self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"], 902 {'point': (1.0, 2.5, -4.3)}, 903 ["foo", "xyz"]) 904 905 def test_nargs_long_opt(self): 906 self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"], 907 {'point': (-1.0, 2.5, -0.0)}, 908 ["xyz"]) 909 910 def test_nargs_invalid_float_value(self): 911 self.assertParseFail(["-p", "1.0", "2x", "3.5"], 912 "option -p: " 913 "invalid floating-point value: '2x'") 914 915 def test_nargs_required_values(self): 916 self.assertParseFail(["--point", "1.0", "3.5"], 917 "--point option requires 3 arguments") 918 919class TestMultipleArgsAppend(BaseTest): 920 def setUp(self): 921 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 922 self.parser.add_option("-p", "--point", action="store", nargs=3, 923 type="float", dest="point") 924 self.parser.add_option("-f", "--foo", action="append", nargs=2, 925 type="int", dest="foo") 926 self.parser.add_option("-z", "--zero", action="append_const", 927 dest="foo", const=(0, 0)) 928 929 def test_nargs_append(self): 930 self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"], 931 {'point': None, 'foo': [(4, -3), (1, 666)]}, 932 ["blah"]) 933 934 def test_nargs_append_required_values(self): 935 self.assertParseFail(["-f4,3"], 936 "-f option requires 2 arguments") 937 938 def test_nargs_append_simple(self): 939 self.assertParseOK(["--foo=3", "4"], 940 {'point': None, 'foo':[(3, 4)]}, 941 []) 942 943 def test_nargs_append_const(self): 944 self.assertParseOK(["--zero", "--foo", "3", "4", "-z"], 945 {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]}, 946 []) 947 948class TestVersion(BaseTest): 949 def test_version(self): 950 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 951 version="%prog 0.1") 952 save_argv = sys.argv[:] 953 try: 954 sys.argv[0] = os.path.join(os.curdir, "foo", "bar") 955 self.assertOutput(["--version"], "bar 0.1\n") 956 finally: 957 sys.argv[:] = save_argv 958 959 def test_no_version(self): 960 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 961 self.assertParseFail(["--version"], 962 "no such option: --version") 963 964# -- Test conflicting default values and parser.parse_args() ----------- 965 966class TestConflictingDefaults(BaseTest): 967 """Conflicting default values: the last one should win.""" 968 def setUp(self): 969 self.parser = OptionParser(option_list=[ 970 make_option("-v", action="store_true", dest="verbose", default=1)]) 971 972 def test_conflict_default(self): 973 self.parser.add_option("-q", action="store_false", dest="verbose", 974 default=0) 975 self.assertParseOK([], {'verbose': 0}, []) 976 977 def test_conflict_default_none(self): 978 self.parser.add_option("-q", action="store_false", dest="verbose", 979 default=None) 980 self.assertParseOK([], {'verbose': None}, []) 981 982class TestOptionGroup(BaseTest): 983 def setUp(self): 984 self.parser = OptionParser(usage=SUPPRESS_USAGE) 985 986 def test_option_group_create_instance(self): 987 group = OptionGroup(self.parser, "Spam") 988 self.parser.add_option_group(group) 989 group.add_option("--spam", action="store_true", 990 help="spam spam spam spam") 991 self.assertParseOK(["--spam"], {'spam': 1}, []) 992 993 def test_add_group_no_group(self): 994 self.assertTypeError(self.parser.add_option_group, 995 "not an OptionGroup instance: None", None) 996 997 def test_add_group_invalid_arguments(self): 998 self.assertTypeError(self.parser.add_option_group, 999 "invalid arguments", None, None) 1000 1001 def test_add_group_wrong_parser(self): 1002 group = OptionGroup(self.parser, "Spam") 1003 group.parser = OptionParser() 1004 self.assertRaises(self.parser.add_option_group, (group,), None, 1005 ValueError, "invalid OptionGroup (wrong parser)") 1006 1007 def test_group_manipulate(self): 1008 group = self.parser.add_option_group("Group 2", 1009 description="Some more options") 1010 group.set_title("Bacon") 1011 group.add_option("--bacon", type="int") 1012 self.assertTrue(self.parser.get_option_group("--bacon"), group) 1013 1014# -- Test extending and parser.parse_args() ---------------------------- 1015 1016class TestExtendAddTypes(BaseTest): 1017 def setUp(self): 1018 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1019 option_class=self.MyOption) 1020 self.parser.add_option("-a", None, type="string", dest="a") 1021 self.parser.add_option("-f", "--file", type="file", dest="file") 1022 1023 def tearDown(self): 1024 if os.path.isdir(support.TESTFN): 1025 os.rmdir(support.TESTFN) 1026 elif os.path.isfile(support.TESTFN): 1027 os.unlink(support.TESTFN) 1028 1029 class MyOption (Option): 1030 def check_file(option, opt, value): 1031 if not os.path.exists(value): 1032 raise OptionValueError("%s: file does not exist" % value) 1033 elif not os.path.isfile(value): 1034 raise OptionValueError("%s: not a regular file" % value) 1035 return value 1036 1037 TYPES = Option.TYPES + ("file",) 1038 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER) 1039 TYPE_CHECKER["file"] = check_file 1040 1041 def test_filetype_ok(self): 1042 support.create_empty_file(support.TESTFN) 1043 self.assertParseOK(["--file", support.TESTFN, "-afoo"], 1044 {'file': support.TESTFN, 'a': 'foo'}, 1045 []) 1046 1047 def test_filetype_noexist(self): 1048 self.assertParseFail(["--file", support.TESTFN, "-afoo"], 1049 "%s: file does not exist" % 1050 support.TESTFN) 1051 1052 def test_filetype_notfile(self): 1053 os.mkdir(support.TESTFN) 1054 self.assertParseFail(["--file", support.TESTFN, "-afoo"], 1055 "%s: not a regular file" % 1056 support.TESTFN) 1057 1058 1059class TestExtendAddActions(BaseTest): 1060 def setUp(self): 1061 options = [self.MyOption("-a", "--apple", action="extend", 1062 type="string", dest="apple")] 1063 self.parser = OptionParser(option_list=options) 1064 1065 class MyOption (Option): 1066 ACTIONS = Option.ACTIONS + ("extend",) 1067 STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) 1068 TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) 1069 1070 def take_action(self, action, dest, opt, value, values, parser): 1071 if action == "extend": 1072 lvalue = value.split(",") 1073 values.ensure_value(dest, []).extend(lvalue) 1074 else: 1075 Option.take_action(self, action, dest, opt, parser, value, 1076 values) 1077 1078 def test_extend_add_action(self): 1079 self.assertParseOK(["-afoo,bar", "--apple=blah"], 1080 {'apple': ["foo", "bar", "blah"]}, 1081 []) 1082 1083 def test_extend_add_action_normal(self): 1084 self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"], 1085 {'apple': ["foo", "bar", "x", "y"]}, 1086 []) 1087 1088# -- Test callbacks and parser.parse_args() ---------------------------- 1089 1090class TestCallback(BaseTest): 1091 def setUp(self): 1092 options = [make_option("-x", 1093 None, 1094 action="callback", 1095 callback=self.process_opt), 1096 make_option("-f", 1097 "--file", 1098 action="callback", 1099 callback=self.process_opt, 1100 type="string", 1101 dest="filename")] 1102 self.parser = OptionParser(option_list=options) 1103 1104 def process_opt(self, option, opt, value, parser_): 1105 if opt == "-x": 1106 self.assertEqual(option._short_opts, ["-x"]) 1107 self.assertEqual(option._long_opts, []) 1108 self.assertTrue(parser_ is self.parser) 1109 self.assertTrue(value is None) 1110 self.assertEqual(vars(parser_.values), {'filename': None}) 1111 1112 parser_.values.x = 42 1113 elif opt == "--file": 1114 self.assertEqual(option._short_opts, ["-f"]) 1115 self.assertEqual(option._long_opts, ["--file"]) 1116 self.assertTrue(parser_ is self.parser) 1117 self.assertEqual(value, "foo") 1118 self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42}) 1119 1120 setattr(parser_.values, option.dest, value) 1121 else: 1122 self.fail("Unknown option %r in process_opt." % opt) 1123 1124 def test_callback(self): 1125 self.assertParseOK(["-x", "--file=foo"], 1126 {'filename': "foo", 'x': 42}, 1127 []) 1128 1129 def test_callback_help(self): 1130 # This test was prompted by SF bug #960515 -- the point is 1131 # not to inspect the help text, just to make sure that 1132 # format_help() doesn't crash. 1133 parser = OptionParser(usage=SUPPRESS_USAGE) 1134 parser.remove_option("-h") 1135 parser.add_option("-t", "--test", action="callback", 1136 callback=lambda: None, type="string", 1137 help="foo") 1138 1139 expected_help = ("Options:\n" 1140 " -t TEST, --test=TEST foo\n") 1141 self.assertHelp(parser, expected_help) 1142 1143 1144class TestCallbackExtraArgs(BaseTest): 1145 def setUp(self): 1146 options = [make_option("-p", "--point", action="callback", 1147 callback=self.process_tuple, 1148 callback_args=(3, int), type="string", 1149 dest="points", default=[])] 1150 self.parser = OptionParser(option_list=options) 1151 1152 def process_tuple(self, option, opt, value, parser_, len, type): 1153 self.assertEqual(len, 3) 1154 self.assertTrue(type is int) 1155 1156 if opt == "-p": 1157 self.assertEqual(value, "1,2,3") 1158 elif opt == "--point": 1159 self.assertEqual(value, "4,5,6") 1160 1161 value = tuple(map(type, value.split(","))) 1162 getattr(parser_.values, option.dest).append(value) 1163 1164 def test_callback_extra_args(self): 1165 self.assertParseOK(["-p1,2,3", "--point", "4,5,6"], 1166 {'points': [(1,2,3), (4,5,6)]}, 1167 []) 1168 1169class TestCallbackMeddleArgs(BaseTest): 1170 def setUp(self): 1171 options = [make_option(str(x), action="callback", 1172 callback=self.process_n, dest='things') 1173 for x in range(-1, -6, -1)] 1174 self.parser = OptionParser(option_list=options) 1175 1176 # Callback that meddles in rargs, largs 1177 def process_n(self, option, opt, value, parser_): 1178 # option is -3, -5, etc. 1179 nargs = int(opt[1:]) 1180 rargs = parser_.rargs 1181 if len(rargs) < nargs: 1182 self.fail("Expected %d arguments for %s option." % (nargs, opt)) 1183 dest = parser_.values.ensure_value(option.dest, []) 1184 dest.append(tuple(rargs[0:nargs])) 1185 parser_.largs.append(nargs) 1186 del rargs[0:nargs] 1187 1188 def test_callback_meddle_args(self): 1189 self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"], 1190 {'things': [("foo",), ("bar", "baz", "qux")]}, 1191 [1, 3]) 1192 1193 def test_callback_meddle_args_separator(self): 1194 self.assertParseOK(["-2", "foo", "--"], 1195 {'things': [('foo', '--')]}, 1196 [2]) 1197 1198class TestCallbackManyArgs(BaseTest): 1199 def setUp(self): 1200 options = [make_option("-a", "--apple", action="callback", nargs=2, 1201 callback=self.process_many, type="string"), 1202 make_option("-b", "--bob", action="callback", nargs=3, 1203 callback=self.process_many, type="int")] 1204 self.parser = OptionParser(option_list=options) 1205 1206 def process_many(self, option, opt, value, parser_): 1207 if opt == "-a": 1208 self.assertEqual(value, ("foo", "bar")) 1209 elif opt == "--apple": 1210 self.assertEqual(value, ("ding", "dong")) 1211 elif opt == "-b": 1212 self.assertEqual(value, (1, 2, 3)) 1213 elif opt == "--bob": 1214 self.assertEqual(value, (-666, 42, 0)) 1215 1216 def test_many_args(self): 1217 self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong", 1218 "-b", "1", "2", "3", "--bob", "-666", "42", 1219 "0"], 1220 {"apple": None, "bob": None}, 1221 []) 1222 1223class TestCallbackCheckAbbrev(BaseTest): 1224 def setUp(self): 1225 self.parser = OptionParser() 1226 self.parser.add_option("--foo-bar", action="callback", 1227 callback=self.check_abbrev) 1228 1229 def check_abbrev(self, option, opt, value, parser): 1230 self.assertEqual(opt, "--foo-bar") 1231 1232 def test_abbrev_callback_expansion(self): 1233 self.assertParseOK(["--foo"], {}, []) 1234 1235class TestCallbackVarArgs(BaseTest): 1236 def setUp(self): 1237 options = [make_option("-a", type="int", nargs=2, dest="a"), 1238 make_option("-b", action="store_true", dest="b"), 1239 make_option("-c", "--callback", action="callback", 1240 callback=self.variable_args, dest="c")] 1241 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1242 option_list=options) 1243 1244 def variable_args(self, option, opt, value, parser): 1245 self.assertTrue(value is None) 1246 value = [] 1247 rargs = parser.rargs 1248 while rargs: 1249 arg = rargs[0] 1250 if ((arg[:2] == "--" and len(arg) > 2) or 1251 (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): 1252 break 1253 else: 1254 value.append(arg) 1255 del rargs[0] 1256 setattr(parser.values, option.dest, value) 1257 1258 def test_variable_args(self): 1259 self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"], 1260 {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]}, 1261 []) 1262 1263 def test_consume_separator_stop_at_option(self): 1264 self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"], 1265 {'a': None, 1266 'b': True, 1267 'c': ["37", "--", "xxx"]}, 1268 ["hello"]) 1269 1270 def test_positional_arg_and_variable_args(self): 1271 self.assertParseOK(["hello", "-c", "foo", "-", "bar"], 1272 {'a': None, 1273 'b': None, 1274 'c':["foo", "-", "bar"]}, 1275 ["hello"]) 1276 1277 def test_stop_at_option(self): 1278 self.assertParseOK(["-c", "foo", "-b"], 1279 {'a': None, 'b': True, 'c': ["foo"]}, 1280 []) 1281 1282 def test_stop_at_invalid_option(self): 1283 self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5") 1284 1285 1286# -- Test conflict handling and parser.parse_args() -------------------- 1287 1288class ConflictBase(BaseTest): 1289 def setUp(self): 1290 options = [make_option("-v", "--verbose", action="count", 1291 dest="verbose", help="increment verbosity")] 1292 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1293 option_list=options) 1294 1295 def show_version(self, option, opt, value, parser): 1296 parser.values.show_version = 1 1297 1298class TestConflict(ConflictBase): 1299 """Use the default conflict resolution for Optik 1.2: error.""" 1300 def assertTrueconflict_error(self, func): 1301 err = self.assertRaises( 1302 func, ("-v", "--version"), {'action' : "callback", 1303 'callback' : self.show_version, 1304 'help' : "show version"}, 1305 OptionConflictError, 1306 "option -v/--version: conflicting option string(s): -v") 1307 1308 self.assertEqual(err.msg, "conflicting option string(s): -v") 1309 self.assertEqual(err.option_id, "-v/--version") 1310 1311 def test_conflict_error(self): 1312 self.assertTrueconflict_error(self.parser.add_option) 1313 1314 def test_conflict_error_group(self): 1315 group = OptionGroup(self.parser, "Group 1") 1316 self.assertTrueconflict_error(group.add_option) 1317 1318 def test_no_such_conflict_handler(self): 1319 self.assertRaises( 1320 self.parser.set_conflict_handler, ('foo',), None, 1321 ValueError, "invalid conflict_resolution value 'foo'") 1322 1323 1324class TestConflictResolve(ConflictBase): 1325 def setUp(self): 1326 ConflictBase.setUp(self) 1327 self.parser.set_conflict_handler("resolve") 1328 self.parser.add_option("-v", "--version", action="callback", 1329 callback=self.show_version, help="show version") 1330 1331 def test_conflict_resolve(self): 1332 v_opt = self.parser.get_option("-v") 1333 verbose_opt = self.parser.get_option("--verbose") 1334 version_opt = self.parser.get_option("--version") 1335 1336 self.assertTrue(v_opt is version_opt) 1337 self.assertTrue(v_opt is not verbose_opt) 1338 self.assertEqual(v_opt._long_opts, ["--version"]) 1339 self.assertEqual(version_opt._short_opts, ["-v"]) 1340 self.assertEqual(version_opt._long_opts, ["--version"]) 1341 self.assertEqual(verbose_opt._short_opts, []) 1342 self.assertEqual(verbose_opt._long_opts, ["--verbose"]) 1343 1344 def test_conflict_resolve_help(self): 1345 self.assertOutput(["-h"], """\ 1346Options: 1347 --verbose increment verbosity 1348 -h, --help show this help message and exit 1349 -v, --version show version 1350""") 1351 1352 def test_conflict_resolve_short_opt(self): 1353 self.assertParseOK(["-v"], 1354 {'verbose': None, 'show_version': 1}, 1355 []) 1356 1357 def test_conflict_resolve_long_opt(self): 1358 self.assertParseOK(["--verbose"], 1359 {'verbose': 1}, 1360 []) 1361 1362 def test_conflict_resolve_long_opts(self): 1363 self.assertParseOK(["--verbose", "--version"], 1364 {'verbose': 1, 'show_version': 1}, 1365 []) 1366 1367class TestConflictOverride(BaseTest): 1368 def setUp(self): 1369 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 1370 self.parser.set_conflict_handler("resolve") 1371 self.parser.add_option("-n", "--dry-run", 1372 action="store_true", dest="dry_run", 1373 help="don't do anything") 1374 self.parser.add_option("--dry-run", "-n", 1375 action="store_const", const=42, dest="dry_run", 1376 help="dry run mode") 1377 1378 def test_conflict_override_opts(self): 1379 opt = self.parser.get_option("--dry-run") 1380 self.assertEqual(opt._short_opts, ["-n"]) 1381 self.assertEqual(opt._long_opts, ["--dry-run"]) 1382 1383 def test_conflict_override_help(self): 1384 self.assertOutput(["-h"], """\ 1385Options: 1386 -h, --help show this help message and exit 1387 -n, --dry-run dry run mode 1388""") 1389 1390 def test_conflict_override_args(self): 1391 self.assertParseOK(["-n"], 1392 {'dry_run': 42}, 1393 []) 1394 1395# -- Other testing. ---------------------------------------------------- 1396 1397_expected_help_basic = """\ 1398Usage: bar.py [options] 1399 1400Options: 1401 -a APPLE throw APPLEs at basket 1402 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the 1403 evil spirits that cause trouble and mayhem) 1404 --foo=FOO store FOO in the foo list for later fooing 1405 -h, --help show this help message and exit 1406""" 1407 1408_expected_help_long_opts_first = """\ 1409Usage: bar.py [options] 1410 1411Options: 1412 -a APPLE throw APPLEs at basket 1413 --boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the 1414 evil spirits that cause trouble and mayhem) 1415 --foo=FOO store FOO in the foo list for later fooing 1416 --help, -h show this help message and exit 1417""" 1418 1419_expected_help_title_formatter = """\ 1420Usage 1421===== 1422 bar.py [options] 1423 1424Options 1425======= 1426-a APPLE throw APPLEs at basket 1427--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the 1428 evil spirits that cause trouble and mayhem) 1429--foo=FOO store FOO in the foo list for later fooing 1430--help, -h show this help message and exit 1431""" 1432 1433_expected_help_short_lines = """\ 1434Usage: bar.py [options] 1435 1436Options: 1437 -a APPLE throw APPLEs at basket 1438 -b NUM, --boo=NUM shout "boo!" NUM times (in order to 1439 frighten away all the evil spirits 1440 that cause trouble and mayhem) 1441 --foo=FOO store FOO in the foo list for later 1442 fooing 1443 -h, --help show this help message and exit 1444""" 1445 1446_expected_very_help_short_lines = """\ 1447Usage: bar.py [options] 1448 1449Options: 1450 -a APPLE 1451 throw 1452 APPLEs at 1453 basket 1454 -b NUM, --boo=NUM 1455 shout 1456 "boo!" NUM 1457 times (in 1458 order to 1459 frighten 1460 away all 1461 the evil 1462 spirits 1463 that cause 1464 trouble and 1465 mayhem) 1466 --foo=FOO 1467 store FOO 1468 in the foo 1469 list for 1470 later 1471 fooing 1472 -h, --help 1473 show this 1474 help 1475 message and 1476 exit 1477""" 1478 1479class TestHelp(BaseTest): 1480 def setUp(self): 1481 self.parser = self.make_parser(80) 1482 1483 def make_parser(self, columns): 1484 options = [ 1485 make_option("-a", type="string", dest='a', 1486 metavar="APPLE", help="throw APPLEs at basket"), 1487 make_option("-b", "--boo", type="int", dest='boo', 1488 metavar="NUM", 1489 help= 1490 "shout \"boo!\" NUM times (in order to frighten away " 1491 "all the evil spirits that cause trouble and mayhem)"), 1492 make_option("--foo", action="append", type="string", dest='foo', 1493 help="store FOO in the foo list for later fooing"), 1494 ] 1495 1496 # We need to set COLUMNS for the OptionParser constructor, but 1497 # we must restore its original value -- otherwise, this test 1498 # screws things up for other tests when it's part of the Python 1499 # test suite. 1500 with support.EnvironmentVarGuard() as env: 1501 env['COLUMNS'] = str(columns) 1502 return InterceptingOptionParser(option_list=options) 1503 1504 def assertHelpEquals(self, expected_output): 1505 save_argv = sys.argv[:] 1506 try: 1507 # Make optparse believe bar.py is being executed. 1508 sys.argv[0] = os.path.join("foo", "bar.py") 1509 self.assertOutput(["-h"], expected_output) 1510 finally: 1511 sys.argv[:] = save_argv 1512 1513 def test_help(self): 1514 self.assertHelpEquals(_expected_help_basic) 1515 1516 def test_help_old_usage(self): 1517 self.parser.set_usage("Usage: %prog [options]") 1518 self.assertHelpEquals(_expected_help_basic) 1519 1520 def test_help_long_opts_first(self): 1521 self.parser.formatter.short_first = 0 1522 self.assertHelpEquals(_expected_help_long_opts_first) 1523 1524 def test_help_title_formatter(self): 1525 with support.EnvironmentVarGuard() as env: 1526 env["COLUMNS"] = "80" 1527 self.parser.formatter = TitledHelpFormatter() 1528 self.assertHelpEquals(_expected_help_title_formatter) 1529 1530 def test_wrap_columns(self): 1531 # Ensure that wrapping respects $COLUMNS environment variable. 1532 # Need to reconstruct the parser, since that's the only time 1533 # we look at $COLUMNS. 1534 self.parser = self.make_parser(60) 1535 self.assertHelpEquals(_expected_help_short_lines) 1536 self.parser = self.make_parser(0) 1537 self.assertHelpEquals(_expected_very_help_short_lines) 1538 1539 def test_help_unicode(self): 1540 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 1541 self.parser.add_option("-a", action="store_true", help="ol\u00E9!") 1542 expect = """\ 1543Options: 1544 -h, --help show this help message and exit 1545 -a ol\u00E9! 1546""" 1547 self.assertHelpEquals(expect) 1548 1549 def test_help_unicode_description(self): 1550 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1551 description="ol\u00E9!") 1552 expect = """\ 1553ol\u00E9! 1554 1555Options: 1556 -h, --help show this help message and exit 1557""" 1558 self.assertHelpEquals(expect) 1559 1560 def test_help_description_groups(self): 1561 self.parser.set_description( 1562 "This is the program description for %prog. %prog has " 1563 "an option group as well as single options.") 1564 1565 group = OptionGroup( 1566 self.parser, "Dangerous Options", 1567 "Caution: use of these options is at your own risk. " 1568 "It is believed that some of them bite.") 1569 group.add_option("-g", action="store_true", help="Group option.") 1570 self.parser.add_option_group(group) 1571 1572 expect = """\ 1573Usage: bar.py [options] 1574 1575This is the program description for bar.py. bar.py has an option group as 1576well as single options. 1577 1578Options: 1579 -a APPLE throw APPLEs at basket 1580 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the 1581 evil spirits that cause trouble and mayhem) 1582 --foo=FOO store FOO in the foo list for later fooing 1583 -h, --help show this help message and exit 1584 1585 Dangerous Options: 1586 Caution: use of these options is at your own risk. It is believed 1587 that some of them bite. 1588 1589 -g Group option. 1590""" 1591 1592 self.assertHelpEquals(expect) 1593 1594 self.parser.epilog = "Please report bugs to /dev/null." 1595 self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n") 1596 1597 1598class TestMatchAbbrev(BaseTest): 1599 def test_match_abbrev(self): 1600 self.assertEqual(_match_abbrev("--f", 1601 {"--foz": None, 1602 "--foo": None, 1603 "--fie": None, 1604 "--f": None}), 1605 "--f") 1606 1607 def test_match_abbrev_error(self): 1608 s = "--f" 1609 wordmap = {"--foz": None, "--foo": None, "--fie": None} 1610 self.assertRaises( 1611 _match_abbrev, (s, wordmap), None, 1612 BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)") 1613 1614 1615class TestParseNumber(BaseTest): 1616 def setUp(self): 1617 self.parser = InterceptingOptionParser() 1618 self.parser.add_option("-n", type=int) 1619 self.parser.add_option("-l", type=int) 1620 1621 def test_parse_num_fail(self): 1622 self.assertRaises( 1623 _parse_num, ("", int), {}, 1624 ValueError, 1625 re.compile(r"invalid literal for int().*: '?'?")) 1626 self.assertRaises( 1627 _parse_num, ("0xOoops", int), {}, 1628 ValueError, 1629 re.compile(r"invalid literal for int().*: s?'?0xOoops'?")) 1630 1631 def test_parse_num_ok(self): 1632 self.assertEqual(_parse_num("0", int), 0) 1633 self.assertEqual(_parse_num("0x10", int), 16) 1634 self.assertEqual(_parse_num("0XA", int), 10) 1635 self.assertEqual(_parse_num("010", int), 8) 1636 self.assertEqual(_parse_num("0b11", int), 3) 1637 self.assertEqual(_parse_num("0b", int), 0) 1638 1639 def test_numeric_options(self): 1640 self.assertParseOK(["-n", "42", "-l", "0x20"], 1641 { "n": 42, "l": 0x20 }, []) 1642 self.assertParseOK(["-n", "0b0101", "-l010"], 1643 { "n": 5, "l": 8 }, []) 1644 self.assertParseFail(["-n008"], 1645 "option -n: invalid integer value: '008'") 1646 self.assertParseFail(["-l0b0123"], 1647 "option -l: invalid integer value: '0b0123'") 1648 self.assertParseFail(["-l", "0x12x"], 1649 "option -l: invalid integer value: '0x12x'") 1650 1651 1652class MiscTestCase(unittest.TestCase): 1653 def test__all__(self): 1654 blacklist = {'check_builtin', 'AmbiguousOptionError', 'NO_DEFAULT'} 1655 support.check__all__(self, optparse, blacklist=blacklist) 1656 1657 1658def test_main(): 1659 support.run_unittest(__name__) 1660 1661if __name__ == '__main__': 1662 test_main() 1663