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 unittest
     14 
     15 from io import StringIO
     16 from test import support
     17 
     18 
     19 import optparse
     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 as 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 as 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         try:
    159             try:
    160                 sys.stdout = StringIO()
    161                 self.parser.parse_args(cmdline_args)
    162             finally:
    163                 output = sys.stdout.getvalue()
    164                 sys.stdout = save_stdout
    165 
    166         except InterceptedError as err:
    167             self.assertTrue(
    168                 isinstance(output, str),
    169                 "expected output to be an ordinary string, not %r"
    170                 % type(output))
    171 
    172             if output != expected_output:
    173                 self.fail("expected: \n'''\n" + expected_output +
    174                           "'''\nbut got \n'''\n" + output + "'''")
    175             self.assertEqual(err.exit_status, expected_status)
    176             self.assertEqual(err.exit_message, expected_error)
    177         else:
    178             self.assertFalse("expected parser.exit()")
    179 
    180     def assertTypeError(self, func, expected_message, *args):
    181         """Assert that TypeError is raised when executing func."""
    182         self.assertRaises(func, args, None, TypeError, expected_message)
    183 
    184     def assertHelp(self, parser, expected_help):
    185         actual_help = parser.format_help()
    186         if actual_help != expected_help:
    187             raise self.failureException(
    188                 'help text failure; expected:\n"' +
    189                 expected_help + '"; got:\n"' +
    190                 actual_help + '"\n')
    191 
    192 # -- Test make_option() aka Option -------------------------------------
    193 
    194 # It's not necessary to test correct options here.  All the tests in the
    195 # parser.parse_args() section deal with those, because they're needed
    196 # there.
    197 
    198 class TestOptionChecks(BaseTest):
    199     def setUp(self):
    200         self.parser = OptionParser(usage=SUPPRESS_USAGE)
    201 
    202     def assertOptionError(self, expected_message, args=[], kwargs={}):
    203         self.assertRaises(make_option, args, kwargs,
    204                           OptionError, expected_message)
    205 
    206     def test_opt_string_empty(self):
    207         self.assertTypeError(make_option,
    208                              "at least one option string must be supplied")
    209 
    210     def test_opt_string_too_short(self):
    211         self.assertOptionError(
    212             "invalid option string 'b': must be at least two characters long",
    213             ["b"])
    214 
    215     def test_opt_string_short_invalid(self):
    216         self.assertOptionError(
    217             "invalid short option string '--': must be "
    218             "of the form -x, (x any non-dash char)",
    219             ["--"])
    220 
    221     def test_opt_string_long_invalid(self):
    222         self.assertOptionError(
    223             "invalid long option string '---': "
    224             "must start with --, followed by non-dash",
    225             ["---"])
    226 
    227     def test_attr_invalid(self):
    228         self.assertOptionError(
    229             "option -b: invalid keyword arguments: bar, foo",
    230             ["-b"], {'foo': None, 'bar': None})
    231 
    232     def test_action_invalid(self):
    233         self.assertOptionError(
    234             "option -b: invalid action: 'foo'",
    235             ["-b"], {'action': 'foo'})
    236 
    237     def test_type_invalid(self):
    238         self.assertOptionError(
    239             "option -b: invalid option type: 'foo'",
    240             ["-b"], {'type': 'foo'})
    241         self.assertOptionError(
    242             "option -b: invalid option type: 'tuple'",
    243             ["-b"], {'type': tuple})
    244 
    245     def test_no_type_for_action(self):
    246         self.assertOptionError(
    247             "option -b: must not supply a type for action 'count'",
    248             ["-b"], {'action': 'count', 'type': 'int'})
    249 
    250     def test_no_choices_list(self):
    251         self.assertOptionError(
    252             "option -b/--bad: must supply a list of "
    253             "choices for type 'choice'",
    254             ["-b", "--bad"], {'type': "choice"})
    255 
    256     def test_bad_choices_list(self):
    257         typename = type('').__name__
    258         self.assertOptionError(
    259             "option -b/--bad: choices must be a list of "
    260             "strings ('%s' supplied)" % typename,
    261             ["-b", "--bad"],
    262             {'type': "choice", 'choices':"bad choices"})
    263 
    264     def test_no_choices_for_type(self):
    265         self.assertOptionError(
    266             "option -b: must not supply choices for type 'int'",
    267             ["-b"], {'type': 'int', 'choices':"bad"})
    268 
    269     def test_no_const_for_action(self):
    270         self.assertOptionError(
    271             "option -b: 'const' must not be supplied for action 'store'",
    272             ["-b"], {'action': 'store', 'const': 1})
    273 
    274     def test_no_nargs_for_action(self):
    275         self.assertOptionError(
    276             "option -b: 'nargs' must not be supplied for action 'count'",
    277             ["-b"], {'action': 'count', 'nargs': 2})
    278 
    279     def test_callback_not_callable(self):
    280         self.assertOptionError(
    281             "option -b: callback not callable: 'foo'",
    282             ["-b"], {'action': 'callback',
    283                      'callback': 'foo'})
    284 
    285     def dummy(self):
    286         pass
    287 
    288     def test_callback_args_no_tuple(self):
    289         self.assertOptionError(
    290             "option -b: callback_args, if supplied, "
    291             "must be a tuple: not 'foo'",
    292             ["-b"], {'action': 'callback',
    293                      'callback': self.dummy,
    294                      'callback_args': 'foo'})
    295 
    296     def test_callback_kwargs_no_dict(self):
    297         self.assertOptionError(
    298             "option -b: callback_kwargs, if supplied, "
    299             "must be a dict: not 'foo'",
    300             ["-b"], {'action': 'callback',
    301                      'callback': self.dummy,
    302                      'callback_kwargs': 'foo'})
    303 
    304     def test_no_callback_for_action(self):
    305         self.assertOptionError(
    306             "option -b: callback supplied ('foo') for non-callback option",
    307             ["-b"], {'action': 'store',
    308                      'callback': 'foo'})
    309 
    310     def test_no_callback_args_for_action(self):
    311         self.assertOptionError(
    312             "option -b: callback_args supplied for non-callback option",
    313             ["-b"], {'action': 'store',
    314                      'callback_args': 'foo'})
    315 
    316     def test_no_callback_kwargs_for_action(self):
    317         self.assertOptionError(
    318             "option -b: callback_kwargs supplied for non-callback option",
    319             ["-b"], {'action': 'store',
    320                      'callback_kwargs': 'foo'})
    321 
    322     def test_no_single_dash(self):
    323         self.assertOptionError(
    324             "invalid long option string '-debug': "
    325             "must start with --, followed by non-dash",
    326             ["-debug"])
    327 
    328         self.assertOptionError(
    329             "option -d: invalid long option string '-debug': must start with"
    330             " --, followed by non-dash",
    331             ["-d", "-debug"])
    332 
    333         self.assertOptionError(
    334             "invalid long option string '-debug': "
    335             "must start with --, followed by non-dash",
    336             ["-debug", "--debug"])
    337 
    338 class TestOptionParser(BaseTest):
    339     def setUp(self):
    340         self.parser = OptionParser()
    341         self.parser.add_option("-v", "--verbose", "-n", "--noisy",
    342                           action="store_true", dest="verbose")
    343         self.parser.add_option("-q", "--quiet", "--silent",
    344                           action="store_false", dest="verbose")
    345 
    346     def test_add_option_no_Option(self):
    347         self.assertTypeError(self.parser.add_option,
    348                              "not an Option instance: None", None)
    349 
    350     def test_add_option_invalid_arguments(self):
    351         self.assertTypeError(self.parser.add_option,
    352                              "invalid arguments", None, None)
    353 
    354     def test_get_option(self):
    355         opt1 = self.parser.get_option("-v")
    356         self.assertIsInstance(opt1, Option)
    357         self.assertEqual(opt1._short_opts, ["-v", "-n"])
    358         self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])
    359         self.assertEqual(opt1.action, "store_true")
    360         self.assertEqual(opt1.dest, "verbose")
    361 
    362     def test_get_option_equals(self):
    363         opt1 = self.parser.get_option("-v")
    364         opt2 = self.parser.get_option("--verbose")
    365         opt3 = self.parser.get_option("-n")
    366         opt4 = self.parser.get_option("--noisy")
    367         self.assertTrue(opt1 is opt2 is opt3 is opt4)
    368 
    369     def test_has_option(self):
    370         self.assertTrue(self.parser.has_option("-v"))
    371         self.assertTrue(self.parser.has_option("--verbose"))
    372 
    373     def assertTrueremoved(self):
    374         self.assertTrue(self.parser.get_option("-v") is None)
    375         self.assertTrue(self.parser.get_option("--verbose") is None)
    376         self.assertTrue(self.parser.get_option("-n") is None)
    377         self.assertTrue(self.parser.get_option("--noisy") is None)
    378 
    379         self.assertFalse(self.parser.has_option("-v"))
    380         self.assertFalse(self.parser.has_option("--verbose"))
    381         self.assertFalse(self.parser.has_option("-n"))
    382         self.assertFalse(self.parser.has_option("--noisy"))
    383 
    384         self.assertTrue(self.parser.has_option("-q"))
    385         self.assertTrue(self.parser.has_option("--silent"))
    386 
    387     def test_remove_short_opt(self):
    388         self.parser.remove_option("-n")
    389         self.assertTrueremoved()
    390 
    391     def test_remove_long_opt(self):
    392         self.parser.remove_option("--verbose")
    393         self.assertTrueremoved()
    394 
    395     def test_remove_nonexistent(self):
    396         self.assertRaises(self.parser.remove_option, ('foo',), None,
    397                           ValueError, "no such option 'foo'")
    398 
    399     @support.impl_detail('Relies on sys.getrefcount', cpython=True)
    400     def test_refleak(self):
    401         # If an OptionParser is carrying around a reference to a large
    402         # object, various cycles can prevent it from being GC'd in
    403         # a timely fashion.  destroy() breaks the cycles to ensure stuff
    404         # can be cleaned up.
    405         big_thing = [42]
    406         refcount = sys.getrefcount(big_thing)
    407         parser = OptionParser()
    408         parser.add_option("-a", "--aaarggh")
    409         parser.big_thing = big_thing
    410 
    411         parser.destroy()
    412         #self.assertEqual(refcount, sys.getrefcount(big_thing))
    413         del parser
    414         self.assertEqual(refcount, sys.getrefcount(big_thing))
    415 
    416 
    417 class TestOptionValues(BaseTest):
    418     def setUp(self):
    419         pass
    420 
    421     def test_basics(self):
    422         values = Values()
    423         self.assertEqual(vars(values), {})
    424         self.assertEqual(values, {})
    425         self.assertNotEqual(values, {"foo": "bar"})
    426         self.assertNotEqual(values, "")
    427 
    428         dict = {"foo": "bar", "baz": 42}
    429         values = Values(defaults=dict)
    430         self.assertEqual(vars(values), dict)
    431         self.assertEqual(values, dict)
    432         self.assertNotEqual(values, {"foo": "bar"})
    433         self.assertNotEqual(values, {})
    434         self.assertNotEqual(values, "")
    435         self.assertNotEqual(values, [])
    436 
    437 
    438 class TestTypeAliases(BaseTest):
    439     def setUp(self):
    440         self.parser = OptionParser()
    441 
    442     def test_str_aliases_string(self):
    443         self.parser.add_option("-s", type="str")
    444         self.assertEqual(self.parser.get_option("-s").type, "string")
    445 
    446     def test_type_object(self):
    447         self.parser.add_option("-s", type=str)
    448         self.assertEqual(self.parser.get_option("-s").type, "string")
    449         self.parser.add_option("-x", type=int)
    450         self.assertEqual(self.parser.get_option("-x").type, "int")
    451 
    452 
    453 # Custom type for testing processing of default values.
    454 _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
    455 
    456 def _check_duration(option, opt, value):
    457     try:
    458         if value[-1].isdigit():
    459             return int(value)
    460         else:
    461             return int(value[:-1]) * _time_units[value[-1]]
    462     except (ValueError, IndexError):
    463         raise OptionValueError(
    464             'option %s: invalid duration: %r' % (opt, value))
    465 
    466 class DurationOption(Option):
    467     TYPES = Option.TYPES + ('duration',)
    468     TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
    469     TYPE_CHECKER['duration'] = _check_duration
    470 
    471 class TestDefaultValues(BaseTest):
    472     def setUp(self):
    473         self.parser = OptionParser()
    474         self.parser.add_option("-v", "--verbose", default=True)
    475         self.parser.add_option("-q", "--quiet", dest='verbose')
    476         self.parser.add_option("-n", type="int", default=37)
    477         self.parser.add_option("-m", type="int")
    478         self.parser.add_option("-s", default="foo")
    479         self.parser.add_option("-t")
    480         self.parser.add_option("-u", default=None)
    481         self.expected = { 'verbose': True,
    482                           'n': 37,
    483                           'm': None,
    484                           's': "foo",
    485                           't': None,
    486                           'u': None }
    487 
    488     def test_basic_defaults(self):
    489         self.assertEqual(self.parser.get_default_values(), self.expected)
    490 
    491     def test_mixed_defaults_post(self):
    492         self.parser.set_defaults(n=42, m=-100)
    493         self.expected.update({'n': 42, 'm': -100})
    494         self.assertEqual(self.parser.get_default_values(), self.expected)
    495 
    496     def test_mixed_defaults_pre(self):
    497         self.parser.set_defaults(x="barf", y="blah")
    498         self.parser.add_option("-x", default="frob")
    499         self.parser.add_option("-y")
    500 
    501         self.expected.update({'x': "frob", 'y': "blah"})
    502         self.assertEqual(self.parser.get_default_values(), self.expected)
    503 
    504         self.parser.remove_option("-y")
    505         self.parser.add_option("-y", default=None)
    506         self.expected.update({'y': None})
    507         self.assertEqual(self.parser.get_default_values(), self.expected)
    508 
    509     def test_process_default(self):
    510         self.parser.option_class = DurationOption
    511         self.parser.add_option("-d", type="duration", default=300)
    512         self.parser.add_option("-e", type="duration", default="6m")
    513         self.parser.set_defaults(n="42")
    514         self.expected.update({'d': 300, 'e': 360, 'n': 42})
    515         self.assertEqual(self.parser.get_default_values(), self.expected)
    516 
    517         self.parser.set_process_default_values(False)
    518         self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
    519         self.assertEqual(self.parser.get_default_values(), self.expected)
    520 
    521 
    522 class TestProgName(BaseTest):
    523     """
    524     Test that %prog expands to the right thing in usage, version,
    525     and help strings.
    526     """
    527 
    528     def assertUsage(self, parser, expected_usage):
    529         self.assertEqual(parser.get_usage(), expected_usage)
    530 
    531     def assertVersion(self, parser, expected_version):
    532         self.assertEqual(parser.get_version(), expected_version)
    533 
    534 
    535     def test_default_progname(self):
    536         # Make sure that program name taken from sys.argv[0] by default.
    537         save_argv = sys.argv[:]
    538         try:
    539             sys.argv[0] = os.path.join("foo", "bar", "baz.py")
    540             parser = OptionParser("%prog ...", version="%prog 1.2")
    541             expected_usage = "Usage: baz.py ...\n"
    542             self.assertUsage(parser, expected_usage)
    543             self.assertVersion(parser, "baz.py 1.2")
    544             self.assertHelp(parser,
    545                             expected_usage + "\n" +
    546                             "Options:\n"
    547                             "  --version   show program's version number and exit\n"
    548                             "  -h, --help  show this help message and exit\n")
    549         finally:
    550             sys.argv[:] = save_argv
    551 
    552     def test_custom_progname(self):
    553         parser = OptionParser(prog="thingy",
    554                               version="%prog 0.1",
    555                               usage="%prog arg arg")
    556         parser.remove_option("-h")
    557         parser.remove_option("--version")
    558         expected_usage = "Usage: thingy arg arg\n"
    559         self.assertUsage(parser, expected_usage)
    560         self.assertVersion(parser, "thingy 0.1")
    561         self.assertHelp(parser, expected_usage + "\n")
    562 
    563 
    564 class TestExpandDefaults(BaseTest):
    565     def setUp(self):
    566         self.parser = OptionParser(prog="test")
    567         self.help_prefix = """\
    568 Usage: test [options]
    569 
    570 Options:
    571   -h, --help            show this help message and exit
    572 """
    573         self.file_help = "read from FILE [default: %default]"
    574         self.expected_help_file = self.help_prefix + \
    575             "  -f FILE, --file=FILE  read from FILE [default: foo.txt]\n"
    576         self.expected_help_none = self.help_prefix + \
    577             "  -f FILE, --file=FILE  read from FILE [default: none]\n"
    578 
    579     def test_option_default(self):
    580         self.parser.add_option("-f", "--file",
    581                                default="foo.txt",
    582                                help=self.file_help)
    583         self.assertHelp(self.parser, self.expected_help_file)
    584 
    585     def test_parser_default_1(self):
    586         self.parser.add_option("-f", "--file",
    587                                help=self.file_help)
    588         self.parser.set_default('file', "foo.txt")
    589         self.assertHelp(self.parser, self.expected_help_file)
    590 
    591     def test_parser_default_2(self):
    592         self.parser.add_option("-f", "--file",
    593                                help=self.file_help)
    594         self.parser.set_defaults(file="foo.txt")
    595         self.assertHelp(self.parser, self.expected_help_file)
    596 
    597     def test_no_default(self):
    598         self.parser.add_option("-f", "--file",
    599                                help=self.file_help)
    600         self.assertHelp(self.parser, self.expected_help_none)
    601 
    602     def test_default_none_1(self):
    603         self.parser.add_option("-f", "--file",
    604                                default=None,
    605                                help=self.file_help)
    606         self.assertHelp(self.parser, self.expected_help_none)
    607 
    608     def test_default_none_2(self):
    609         self.parser.add_option("-f", "--file",
    610                                help=self.file_help)
    611         self.parser.set_defaults(file=None)
    612         self.assertHelp(self.parser, self.expected_help_none)
    613 
    614     def test_float_default(self):
    615         self.parser.add_option(
    616             "-p", "--prob",
    617             help="blow up with probability PROB [default: %default]")
    618         self.parser.set_defaults(prob=0.43)
    619         expected_help = self.help_prefix + \
    620             "  -p PROB, --prob=PROB  blow up with probability PROB [default: 0.43]\n"
    621         self.assertHelp(self.parser, expected_help)
    622 
    623     def test_alt_expand(self):
    624         self.parser.add_option("-f", "--file",
    625                                default="foo.txt",
    626                                help="read from FILE [default: *DEFAULT*]")
    627         self.parser.formatter.default_tag = "*DEFAULT*"
    628         self.assertHelp(self.parser, self.expected_help_file)
    629 
    630     def test_no_expand(self):
    631         self.parser.add_option("-f", "--file",
    632                                default="foo.txt",
    633                                help="read from %default file")
    634         self.parser.formatter.default_tag = None
    635         expected_help = self.help_prefix + \
    636             "  -f FILE, --file=FILE  read from %default file\n"
    637         self.assertHelp(self.parser, expected_help)
    638 
    639 
    640 # -- Test parser.parse_args() ------------------------------------------
    641 
    642 class TestStandard(BaseTest):
    643     def setUp(self):
    644         options = [make_option("-a", type="string"),
    645                    make_option("-b", "--boo", type="int", dest='boo'),
    646                    make_option("--foo", action="append")]
    647 
    648         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
    649                                                option_list=options)
    650 
    651     def test_required_value(self):
    652         self.assertParseFail(["-a"], "-a option requires 1 argument")
    653 
    654     def test_invalid_integer(self):
    655         self.assertParseFail(["-b", "5x"],
    656                              "option -b: invalid integer value: '5x'")
    657 
    658     def test_no_such_option(self):
    659         self.assertParseFail(["--boo13"], "no such option: --boo13")
    660 
    661     def test_long_invalid_integer(self):
    662         self.assertParseFail(["--boo=x5"],
    663                              "option --boo: invalid integer value: 'x5'")
    664 
    665     def test_empty(self):
    666         self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
    667 
    668     def test_shortopt_empty_longopt_append(self):
    669         self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
    670                            {'a': "", 'boo': None, 'foo': ["blah", ""]},
    671                            [])
    672 
    673     def test_long_option_append(self):
    674         self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
    675                            {'a': None,
    676                             'boo': None,
    677                             'foo': ["bar", "", "x"]},
    678                            [])
    679 
    680     def test_option_argument_joined(self):
    681         self.assertParseOK(["-abc"],
    682                            {'a': "bc", 'boo': None, 'foo': None},
    683                            [])
    684 
    685     def test_option_argument_split(self):
    686         self.assertParseOK(["-a", "34"],
    687                            {'a': "34", 'boo': None, 'foo': None},
    688                            [])
    689 
    690     def test_option_argument_joined_integer(self):
    691         self.assertParseOK(["-b34"],
    692                            {'a': None, 'boo': 34, 'foo': None},
    693                            [])
    694 
    695     def test_option_argument_split_negative_integer(self):
    696         self.assertParseOK(["-b", "-5"],
    697                            {'a': None, 'boo': -5, 'foo': None},
    698                            [])
    699 
    700     def test_long_option_argument_joined(self):
    701         self.assertParseOK(["--boo=13"],
    702                            {'a': None, 'boo': 13, 'foo': None},
    703                            [])
    704 
    705     def test_long_option_argument_split(self):
    706         self.assertParseOK(["--boo", "111"],
    707                            {'a': None, 'boo': 111, 'foo': None},
    708                            [])
    709 
    710     def test_long_option_short_option(self):
    711         self.assertParseOK(["--foo=bar", "-axyz"],
    712                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
    713                            [])
    714 
    715     def test_abbrev_long_option(self):
    716         self.assertParseOK(["--f=bar", "-axyz"],
    717                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
    718                            [])
    719 
    720     def test_defaults(self):
    721         (options, args) = self.parser.parse_args([])
    722         defaults = self.parser.get_default_values()
    723         self.assertEqual(vars(defaults), vars(options))
    724 
    725     def test_ambiguous_option(self):
    726         self.parser.add_option("--foz", action="store",
    727                                type="string", dest="foo")
    728         self.assertParseFail(["--f=bar"],
    729                              "ambiguous option: --f (--foo, --foz?)")
    730 
    731 
    732     def test_short_and_long_option_split(self):
    733         self.assertParseOK(["-a", "xyz", "--foo", "bar"],
    734                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
    735                            [])
    736 
    737     def test_short_option_split_long_option_append(self):
    738         self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
    739                            {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
    740                            [])
    741 
    742     def test_short_option_split_one_positional_arg(self):
    743         self.assertParseOK(["-a", "foo", "bar"],
    744                            {'a': "foo", 'boo': None, 'foo': None},
    745                            ["bar"])
    746 
    747     def test_short_option_consumes_separator(self):
    748         self.assertParseOK(["-a", "--", "foo", "bar"],
    749                            {'a': "--", 'boo': None, 'foo': None},
    750                            ["foo", "bar"])
    751         self.assertParseOK(["-a", "--", "--foo", "bar"],
    752                            {'a': "--", 'boo': None, 'foo': ["bar"]},
    753                            [])
    754 
    755     def test_short_option_joined_and_separator(self):
    756         self.assertParseOK(["-ab", "--", "--foo", "bar"],
    757                            {'a': "b", 'boo': None, 'foo': None},
    758                            ["--foo", "bar"]),
    759 
    760     def test_hyphen_becomes_positional_arg(self):
    761         self.assertParseOK(["-ab", "-", "--foo", "bar"],
    762                            {'a': "b", 'boo': None, 'foo': ["bar"]},
    763                            ["-"])
    764 
    765     def test_no_append_versus_append(self):
    766         self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
    767                            {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
    768                            [])
    769 
    770     def test_option_consumes_optionlike_string(self):
    771         self.assertParseOK(["-a", "-b3"],
    772                            {'a': "-b3", 'boo': None, 'foo': None},
    773                            [])
    774 
    775     def test_combined_single_invalid_option(self):
    776         self.parser.add_option("-t", action="store_true")
    777         self.assertParseFail(["-test"],
    778                              "no such option: -e")
    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(support.TESTFN):
   1027             os.rmdir(support.TESTFN)
   1028         elif os.path.isfile(support.TESTFN):
   1029             os.unlink(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         support.create_empty_file(support.TESTFN)
   1045         self.assertParseOK(["--file", support.TESTFN, "-afoo"],
   1046                            {'file': support.TESTFN, 'a': 'foo'},
   1047                            [])
   1048 
   1049     def test_filetype_noexist(self):
   1050         self.assertParseFail(["--file", support.TESTFN, "-afoo"],
   1051                              "%s: file does not exist" %
   1052                              support.TESTFN)
   1053 
   1054     def test_filetype_notfile(self):
   1055         os.mkdir(support.TESTFN)
   1056         self.assertParseFail(["--file", support.TESTFN, "-afoo"],
   1057                              "%s: not a regular file" %
   1058                              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 support.EnvironmentVarGuard() as env:
   1503             env['COLUMNS'] = str(columns)
   1504             return InterceptingOptionParser(option_list=options)
   1505 
   1506     def assertHelpEquals(self, expected_output):
   1507         save_argv = sys.argv[:]
   1508         try:
   1509             # Make optparse believe bar.py is being executed.
   1510             sys.argv[0] = os.path.join("foo", "bar.py")
   1511             self.assertOutput(["-h"], expected_output)
   1512         finally:
   1513             sys.argv[:] = save_argv
   1514 
   1515     def test_help(self):
   1516         self.assertHelpEquals(_expected_help_basic)
   1517 
   1518     def test_help_old_usage(self):
   1519         self.parser.set_usage("Usage: %prog [options]")
   1520         self.assertHelpEquals(_expected_help_basic)
   1521 
   1522     def test_help_long_opts_first(self):
   1523         self.parser.formatter.short_first = 0
   1524         self.assertHelpEquals(_expected_help_long_opts_first)
   1525 
   1526     def test_help_title_formatter(self):
   1527         with support.EnvironmentVarGuard() as env:
   1528             env["COLUMNS"] = "80"
   1529             self.parser.formatter = TitledHelpFormatter()
   1530             self.assertHelpEquals(_expected_help_title_formatter)
   1531 
   1532     def test_wrap_columns(self):
   1533         # Ensure that wrapping respects $COLUMNS environment variable.
   1534         # Need to reconstruct the parser, since that's the only time
   1535         # we look at $COLUMNS.
   1536         self.parser = self.make_parser(60)
   1537         self.assertHelpEquals(_expected_help_short_lines)
   1538         self.parser = self.make_parser(0)
   1539         self.assertHelpEquals(_expected_very_help_short_lines)
   1540 
   1541     def test_help_unicode(self):
   1542         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
   1543         self.parser.add_option("-a", action="store_true", help="ol\u00E9!")
   1544         expect = """\
   1545 Options:
   1546   -h, --help  show this help message and exit
   1547   -a          ol\u00E9!
   1548 """
   1549         self.assertHelpEquals(expect)
   1550 
   1551     def test_help_unicode_description(self):
   1552         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
   1553                                                description="ol\u00E9!")
   1554         expect = """\
   1555 ol\u00E9!
   1556 
   1557 Options:
   1558   -h, --help  show this help message and exit
   1559 """
   1560         self.assertHelpEquals(expect)
   1561 
   1562     def test_help_description_groups(self):
   1563         self.parser.set_description(
   1564             "This is the program description for %prog.  %prog has "
   1565             "an option group as well as single options.")
   1566 
   1567         group = OptionGroup(
   1568             self.parser, "Dangerous Options",
   1569             "Caution: use of these options is at your own risk.  "
   1570             "It is believed that some of them bite.")
   1571         group.add_option("-g", action="store_true", help="Group option.")
   1572         self.parser.add_option_group(group)
   1573 
   1574         expect = """\
   1575 Usage: bar.py [options]
   1576 
   1577 This is the program description for bar.py.  bar.py has an option group as
   1578 well as single options.
   1579 
   1580 Options:
   1581   -a APPLE           throw APPLEs at basket
   1582   -b NUM, --boo=NUM  shout "boo!" NUM times (in order to frighten away all the
   1583                      evil spirits that cause trouble and mayhem)
   1584   --foo=FOO          store FOO in the foo list for later fooing
   1585   -h, --help         show this help message and exit
   1586 
   1587   Dangerous Options:
   1588     Caution: use of these options is at your own risk.  It is believed
   1589     that some of them bite.
   1590 
   1591     -g               Group option.
   1592 """
   1593 
   1594         self.assertHelpEquals(expect)
   1595 
   1596         self.parser.epilog = "Please report bugs to /dev/null."
   1597         self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n")
   1598 
   1599 
   1600 class TestMatchAbbrev(BaseTest):
   1601     def test_match_abbrev(self):
   1602         self.assertEqual(_match_abbrev("--f",
   1603                                        {"--foz": None,
   1604                                         "--foo": None,
   1605                                         "--fie": None,
   1606                                         "--f": None}),
   1607                          "--f")
   1608 
   1609     def test_match_abbrev_error(self):
   1610         s = "--f"
   1611         wordmap = {"--foz": None, "--foo": None, "--fie": None}
   1612         self.assertRaises(
   1613             _match_abbrev, (s, wordmap), None,
   1614             BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)")
   1615 
   1616 
   1617 class TestParseNumber(BaseTest):
   1618     def setUp(self):
   1619         self.parser = InterceptingOptionParser()
   1620         self.parser.add_option("-n", type=int)
   1621         self.parser.add_option("-l", type=int)
   1622 
   1623     def test_parse_num_fail(self):
   1624         self.assertRaises(
   1625             _parse_num, ("", int), {},
   1626             ValueError,
   1627             re.compile(r"invalid literal for int().*: '?'?"))
   1628         self.assertRaises(
   1629             _parse_num, ("0xOoops", int), {},
   1630             ValueError,
   1631             re.compile(r"invalid literal for int().*: s?'?0xOoops'?"))
   1632 
   1633     def test_parse_num_ok(self):
   1634         self.assertEqual(_parse_num("0", int), 0)
   1635         self.assertEqual(_parse_num("0x10", int), 16)
   1636         self.assertEqual(_parse_num("0XA", int), 10)
   1637         self.assertEqual(_parse_num("010", int), 8)
   1638         self.assertEqual(_parse_num("0b11", int), 3)
   1639         self.assertEqual(_parse_num("0b", int), 0)
   1640 
   1641     def test_numeric_options(self):
   1642         self.assertParseOK(["-n", "42", "-l", "0x20"],
   1643                            { "n": 42, "l": 0x20 }, [])
   1644         self.assertParseOK(["-n", "0b0101", "-l010"],
   1645                            { "n": 5, "l": 8 }, [])
   1646         self.assertParseFail(["-n008"],
   1647                              "option -n: invalid integer value: '008'")
   1648         self.assertParseFail(["-l0b0123"],
   1649                              "option -l: invalid integer value: '0b0123'")
   1650         self.assertParseFail(["-l", "0x12x"],
   1651                              "option -l: invalid integer value: '0x12x'")
   1652 
   1653 
   1654 class MiscTestCase(unittest.TestCase):
   1655     def test__all__(self):
   1656         blacklist = {'check_builtin', 'AmbiguousOptionError', 'NO_DEFAULT'}
   1657         support.check__all__(self, optparse, blacklist=blacklist)
   1658 
   1659 
   1660 def test_main():
   1661     support.run_unittest(__name__)
   1662 
   1663 if __name__ == '__main__':
   1664     test_main()
   1665