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