diff options
author | Greg Ward <gward@python.net> | 2004-10-27 02:20:04 (GMT) |
---|---|---|
committer | Greg Ward <gward@python.net> | 2004-10-27 02:20:04 (GMT) |
commit | 48aa84b24d02f1564f74bba34f0e3e7d820a8c15 (patch) | |
tree | 63118d70b111358a91a5ac601621b5ee66875ebb /Lib/test/test_optparse.py | |
parent | 99b5548298ffc2ae5f03bd9ef873ce45a9844f0e (diff) | |
download | cpython-48aa84b24d02f1564f74bba34f0e3e7d820a8c15.zip cpython-48aa84b24d02f1564f74bba34f0e3e7d820a8c15.tar.gz cpython-48aa84b24d02f1564f74bba34f0e3e7d820a8c15.tar.bz2 |
Update optparse module and test suite to Optik 1.5a2.
Diffstat (limited to 'Lib/test/test_optparse.py')
-rw-r--r-- | Lib/test/test_optparse.py | 406 |
1 files changed, 214 insertions, 192 deletions
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py index 883194e..c02dd10 100644 --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -17,10 +17,37 @@ from cStringIO import StringIO from pprint import pprint from test import test_support -from optparse import (make_option, Option, IndentedHelpFormatter, - TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, - SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, - BadOptionError, OptionValueError, _match_abbrev) +from optparse import make_option, Option, IndentedHelpFormatter, \ + TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \ + SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \ + BadOptionError, OptionValueError, Values, _match_abbrev + +# Do the right thing with boolean values for all known Python versions. +try: + True, False +except NameError: + (True, False) = (1, 0) + + +class InterceptedError(Exception): + def __init__(self, + error_message=None, + exit_status=None, + exit_message=None): + self.error_message = error_message + self.exit_status = exit_status + self.exit_message = exit_message + + def __str__(self): + return self.error_message or self.exit_message or "intercepted error" + +class InterceptingOptionParser(OptionParser): + def exit(self, status=0, msg=None): + raise InterceptedError(exit_status=status, exit_message=msg) + + def error(self, msg): + raise InterceptedError(error_message=msg) + class BaseTest(unittest.TestCase): def assertParseOK(self, args, expected_opts, expected_positional_args): @@ -58,12 +85,11 @@ Args were %(args)s.""" % locals ()) args, kwargs, expected_exception, - expected_output, - get_output=None, - exact_match=False): - """Assert the expected exception is raised when calling a function. - - Also check whether the right error message is given for a given error. + expected_message): + """ + Assert that the expected exception is raised when calling a + function, and that the right error message is included with + that exception. Arguments: func -- the function to call @@ -71,9 +97,6 @@ Args were %(args)s.""" % locals ()) kwargs -- keyword arguments to `func` expected_exception -- exception that should be raised expected_output -- output we expect to see - get_output -- function to call to get the output - exact_match -- whether output must exactly match expected output, - or merely contain it Returns the exception raised for further testing. """ @@ -81,25 +104,18 @@ Args were %(args)s.""" % locals ()) args = () if kwargs is None: kwargs = {} - if get_output is None: - get_output = self.exception try: - out = func(*args, **kwargs) + func(*args, **kwargs) except expected_exception, err: - actual_output = get_output(err) - - if exact_match: - match = actual_output == expected_exception - else: - match = actual_output.find(expected_output) != -1 - - self.assert_(match, - """mismatched output -expected output: -'''%(expected_output)s''' -actual output: -'''%(actual_output)s''' + actual_message = str(err) + self.assertEqual(actual_message, + expected_message, + """\ +expected exception message: +'''%(expected_message)s''' +actual exception message: +'''%(actual_message)s''' """ % locals()) return err @@ -110,44 +126,46 @@ with args %(args)r and kwargs %(kwargs)r """ % locals ()) - # -- Functions to be used as the get_output argument to assertRaises ------ - - def exception(self, err): - return str(err) - - def redirected_stdout(self, err): - return sys.stdout.getvalue() - - def redirected_stderr(self, err): - return sys.stderr.getvalue() # -- Assertions used in more than one class -------------------- def assertParseFail(self, cmdline_args, expected_output): - """Assert the parser fails with the expected message.""" - save_stderr = sys.stderr + """ + Assert the parser fails with the expected message. Caller + must ensure that self.parser is an InterceptingOptionParser. + """ try: - sys.stderr = StringIO() - self.assertRaises(self.parser.parse_args, (cmdline_args,), None, - SystemExit, expected_output, - self.redirected_stderr) - finally: - sys.stderr = save_stderr + self.parser.parse_args(cmdline_args) + except InterceptedError, err: + self.assertEqual(err.error_message, expected_output) + else: + self.assertFalse("expected parse failure") - def assertStdoutEquals(self, cmdline_args, expected_output): + def assertOutput(self, + cmdline_args, + expected_output, + expected_status=0, + expected_error=None): """Assert the parser prints the expected output on stdout.""" save_stdout = sys.stdout try: - sys.stdout = StringIO() - self.assertRaises(self.parser.parse_args, (cmdline_args,), None, - SystemExit, expected_output, - self.redirected_stdout) - finally: - sys.stdout = save_stdout + try: + sys.stdout = StringIO() + self.parser.parse_args(cmdline_args) + finally: + output = sys.stdout.getvalue() + sys.stdout = save_stdout + + except InterceptedError, err: + self.assertEqual(output, expected_output) + self.assertEqual(err.exit_status, expected_status) + self.assertEqual(err.exit_message, expected_error) + else: + self.assertFalse("expected parser.exit()") - def assertTypeError(self, func, expected_output, *args): - """Assert a TypeError is raised when executing func.""" - self.assertRaises(func, args, None, TypeError, expected_output) + def assertTypeError(self, func, expected_message, *args): + """Assert that TypeError is raised when executing func.""" + self.assertRaises(func, args, None, TypeError, expected_message) def assertHelp(self, parser, expected_help): actual_help = parser.format_help() @@ -159,120 +177,133 @@ and kwargs %(kwargs)r # -- Test make_option() aka Option ------------------------------------- -# It's not necessary to test correct options here. All the tests in the +# It's not necessary to test correct options here. All the tests in the # parser.parse_args() section deal with those, because they're needed -# there. Duplication makes no sense to me. +# there. class TestOptionChecks(BaseTest): def setUp(self): self.parser = OptionParser(usage=SUPPRESS_USAGE) - def assertOptionError(self, expected_output, args=[], kwargs={}): + def assertOptionError(self, expected_message, args=[], kwargs={}): self.assertRaises(make_option, args, kwargs, - OptionError, expected_output) + OptionError, expected_message) def test_opt_string_empty(self): self.assertTypeError(make_option, "at least one option string must be supplied") def test_opt_string_too_short(self): - self.assertOptionError("invalid option string 'b': " - "must be at least two characters long", - ["b"]) + self.assertOptionError( + "invalid option string 'b': must be at least two characters long", + ["b"]) def test_opt_string_short_invalid(self): - self.assertOptionError("invalid short option string '--': must be " - "of the form -x, (x any non-dash char)", - ["--"]) + self.assertOptionError( + "invalid short option string '--': must be " + "of the form -x, (x any non-dash char)", + ["--"]) def test_opt_string_long_invalid(self): - self.assertOptionError("invalid long option string '---': " - "must start with --, followed by non-dash", - ["---"]) + self.assertOptionError( + "invalid long option string '---': " + "must start with --, followed by non-dash", + ["---"]) def test_attr_invalid(self): - self.assertOptionError("invalid keyword arguments: foo, bar", - ["-b"], {'foo': None, 'bar': None}) + self.assertOptionError( + "option -b: invalid keyword arguments: foo, bar", + ["-b"], {'foo': None, 'bar': None}) def test_action_invalid(self): - self.assertOptionError("invalid action: 'foo'", - ["-b"], {'action': 'foo'}) + self.assertOptionError( + "option -b: invalid action: 'foo'", + ["-b"], {'action': 'foo'}) def test_type_invalid(self): - self.assertOptionError("invalid option type: 'foo'", - ["-b"], {'type': 'foo'}) - self.assertOptionError("invalid option type: 'tuple'", - ["-b"], {'type': tuple}) + self.assertOptionError( + "option -b: invalid option type: 'foo'", + ["-b"], {'type': 'foo'}) + self.assertOptionError( + "option -b: invalid option type: 'tuple'", + ["-b"], {'type': tuple}) def test_no_type_for_action(self): - self.assertOptionError("must not supply a type for action 'count'", - ["-b"], {'action': 'count', 'type': 'int'}) + self.assertOptionError( + "option -b: must not supply a type for action 'count'", + ["-b"], {'action': 'count', 'type': 'int'}) def test_no_choices_list(self): - self.assertOptionError("must supply a list of " - "choices for type 'choice'", - ["-b", "--bad"], {'type': "choice"}) + self.assertOptionError( + "option -b/--bad: must supply a list of " + "choices for type 'choice'", + ["-b", "--bad"], {'type': "choice"}) def test_bad_choices_list(self): typename = type('').__name__ - self.assertOptionError("choices must be a list of " - "strings ('%s' supplied)" % typename, - ["-b", "--bad"], - {'type': "choice", 'choices':"bad choices"}) + self.assertOptionError( + "option -b/--bad: choices must be a list of " + "strings ('%s' supplied)" % typename, + ["-b", "--bad"], + {'type': "choice", 'choices':"bad choices"}) def test_no_choices_for_type(self): - self.assertOptionError("must not supply choices for type 'int'", - ["-b"], {'type': 'int', 'choices':"bad"}) + self.assertOptionError( + "option -b: must not supply choices for type 'int'", + ["-b"], {'type': 'int', 'choices':"bad"}) def test_no_const_for_action(self): - self.assertOptionError("'const' must not be supplied for action " - "'store'", - ["-b"], {'action': 'store', 'const': 1}) + self.assertOptionError( + "option -b: 'const' must not be supplied for action 'store'", + ["-b"], {'action': 'store', 'const': 1}) def test_no_nargs_for_action(self): - self.assertOptionError("'nargs' must not be supplied for action " - "'count'", - ["-b"], {'action': 'count', 'nargs': 2}) + self.assertOptionError( + "option -b: 'nargs' must not be supplied for action 'count'", + ["-b"], {'action': 'count', 'nargs': 2}) def test_callback_not_callable(self): - self.assertOptionError("callback not callable: 'foo'", - ["-b"], {'action': 'callback', - 'callback': 'foo'}) + self.assertOptionError( + "option -b: callback not callable: 'foo'", + ["-b"], {'action': 'callback', + 'callback': 'foo'}) def dummy(self): pass def test_callback_args_no_tuple(self): - self.assertOptionError("callback_args, if supplied, must be a tuple: " - "not 'foo'", - ["-b"], {'action': 'callback', - 'callback': self.dummy, - 'callback_args': 'foo'}) + self.assertOptionError( + "option -b: callback_args, if supplied, " + "must be a tuple: not 'foo'", + ["-b"], {'action': 'callback', + 'callback': self.dummy, + 'callback_args': 'foo'}) def test_callback_kwargs_no_dict(self): - self.assertOptionError("callback_kwargs, if supplied, must be a dict: " - "not 'foo'", - ["-b"], {'action': 'callback', - 'callback': self.dummy, - 'callback_kwargs': 'foo'}) + self.assertOptionError( + "option -b: callback_kwargs, if supplied, " + "must be a dict: not 'foo'", + ["-b"], {'action': 'callback', + 'callback': self.dummy, + 'callback_kwargs': 'foo'}) def test_no_callback_for_action(self): - self.assertOptionError("callback supplied ('foo') for " - "non-callback option", - ["-b"], {'action': 'store', - 'callback': 'foo'}) + self.assertOptionError( + "option -b: callback supplied ('foo') for non-callback option", + ["-b"], {'action': 'store', + 'callback': 'foo'}) def test_no_callback_args_for_action(self): - self.assertOptionError("callback_args supplied for non-callback " - "option", - ["-b"], {'action': 'store', - 'callback_args': 'foo'}) + self.assertOptionError( + "option -b: callback_args supplied for non-callback option", + ["-b"], {'action': 'store', + 'callback_args': 'foo'}) def test_no_callback_kwargs_for_action(self): - self.assertOptionError("callback_kwargs supplied for non-callback " - "option", - ["-b"], {'action': 'store', - 'callback_kwargs': 'foo'}) + self.assertOptionError( + "option -b: callback_kwargs supplied for non-callback option", + ["-b"], {'action': 'store', + 'callback_kwargs': 'foo'}) class TestOptionParser(BaseTest): def setUp(self): @@ -335,6 +366,27 @@ class TestOptionParser(BaseTest): self.assertRaises(self.parser.remove_option, ('foo',), None, ValueError, "no such option 'foo'") +class TestOptionValues(BaseTest): + def setUp(self): + pass + + def test_basics(self): + values = Values() + self.assertEqual(vars(values), {}) + self.assertEqual(values, {}) + self.assertNotEqual(values, {"foo": "bar"}) + self.assertNotEqual(values, "") + + dict = {"foo": "bar", "baz": 42} + values = Values(defaults=dict) + self.assertEqual(vars(values), dict) + self.assertEqual(values, dict) + self.assertNotEqual(values, {"foo": "bar"}) + self.assertNotEqual(values, {}) + self.assertNotEqual(values, "") + self.assertNotEqual(values, []) + + class TestTypeAliases(BaseTest): def setUp(self): self.parser = OptionParser() @@ -346,7 +398,7 @@ class TestTypeAliases(BaseTest): self.assertEquals(self.parser.get_option("-x").type, "int") self.assertEquals(self.parser.get_option("-s").type, "string") self.assertEquals(self.parser.get_option("-t").type, "string") - + # Custom type for testing processing of default values. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 } @@ -434,17 +486,16 @@ class TestProgName(BaseTest): # Make sure that program name taken from sys.argv[0] by default. save_argv = sys.argv[:] try: - # XXX Should the path be hard-coding forward-slashes? - sys.argv[0] = "/foo/bar/baz.py" + sys.argv[0] = os.path.join("foo", "bar", "baz.py") parser = OptionParser("usage: %prog ...", version="%prog 1.2") expected_usage = "usage: baz.py ...\n" self.assertUsage(parser, expected_usage) self.assertVersion(parser, "baz.py 1.2") self.assertHelp(parser, - expected_usage + "\n" + - "options:\n" - " --version show program's version number and exit\n" - " -h, --help show this help message and exit\n") + expected_usage + "\n" + + "options:\n" + " --version show program's version number and exit\n" + " -h, --help show this help message and exit\n") finally: sys.argv[:] = save_argv @@ -503,7 +554,7 @@ options: default=None, help=self.file_help) self.assertHelp(self.parser, self.expected_help_none) - + def test_default_none_2(self): self.parser.add_option("-f", "--file", help=self.file_help) @@ -544,7 +595,8 @@ class TestStandard(BaseTest): make_option("-b", "--boo", type="int", dest='boo'), make_option("--foo", action="append")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def test_required_value(self): self.assertParseFail(["-a"], "-a option requires an argument") @@ -707,7 +759,7 @@ class TestBool(BaseTest): class TestChoice(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-c", action="store", type="choice", dest="choice", choices=["one", "two", "three"]) @@ -730,7 +782,7 @@ class TestChoice(BaseTest): class TestCount(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.v_opt = make_option("-v", action="count", dest="verbose") self.parser.add_option(self.v_opt) self.parser.add_option("--verbose", type="int", dest="verbose") @@ -786,9 +838,9 @@ class TestCount(BaseTest): self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], {'verbose': 1}, []) -class TestNArgs(BaseTest): +class TestMultipleArgs(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-p", "--point", action="store", nargs=3, type="float", dest="point") @@ -811,9 +863,9 @@ class TestNArgs(BaseTest): self.assertParseFail(["--point", "1.0", "3.5"], "--point option requires 3 arguments") -class TestNArgsAppend(BaseTest): +class TestMultipleArgsAppend(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-p", "--point", action="store", nargs=3, type="float", dest="point") self.parser.add_option("-f", "--foo", action="append", nargs=2, @@ -835,14 +887,17 @@ class TestNArgsAppend(BaseTest): class TestVersion(BaseTest): def test_version(self): - oldargv = sys.argv[0] - sys.argv[0] = "./foo/bar" - self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1") - self.assertStdoutEquals(["--version"], "bar 0.1\n") - sys.argv[0] = oldargv + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + version="%prog 0.1") + save_argv = sys.argv[:] + try: + sys.argv[0] = os.path.join(os.curdir, "foo", "bar") + self.assertOutput(["--version"], "bar 0.1\n") + finally: + sys.argv[:] = save_argv def test_no_version(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.assertParseFail(["--version"], "no such option: --version") @@ -900,8 +955,8 @@ class TestOptionGroup(BaseTest): class TestExtendAddTypes(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE, - option_class=self.MyOption) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_class=self.MyOption) self.parser.add_option("-a", None, type="string", dest="a") self.parser.add_option("-f", "--file", type="file", dest="file") @@ -1119,7 +1174,8 @@ class TestCallbackVarArgs(BaseTest): make_option("-b", action="store_true", dest="b"), make_option("-c", "--callback", action="callback", callback=self.variable_args, dest="c")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def variable_args (self, option, opt, value, parser): self.assert_(value is None) @@ -1170,7 +1226,8 @@ class ConflictBase(BaseTest): def setUp(self): options = [make_option("-v", "--verbose", action="count", dest="verbose", help="increment verbosity")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def show_version (self, option, opt, value, parser): parser.values.show_version = 1 @@ -1201,41 +1258,6 @@ class TestConflict(ConflictBase): ValueError, "invalid conflict_resolution value 'foo'") -class TestConflictIgnore(ConflictBase): - """Test the old (Optik <= 1.1 behaviour) -- arguably broken, but - still available so should be tested. - """ - - def setUp(self): - ConflictBase.setUp(self) - self.parser.set_conflict_handler("ignore") - self.parser.add_option("-v", "--version", action="callback", - callback=self.show_version, help="show version") - - def test_conflict_ignore(self): - v_opt = self.parser.get_option("-v") - verbose_opt = self.parser.get_option("--verbose") - version_opt = self.parser.get_option("--version") - - self.assert_(v_opt is version_opt) - self.assert_(v_opt is not verbose_opt) - self.assertEqual(v_opt._long_opts, ["--version"]) - self.assertEqual(version_opt._short_opts, ["-v"]) - self.assertEqual(verbose_opt._short_opts, ["-v"]) - - def test_conflict_ignore_help(self): - self.assertStdoutEquals(["-h"], """\ -options: - -v, --verbose increment verbosity - -h, --help show this help message and exit - -v, --version show version -""") - - def test_conflict_ignore_short_opt(self): - self.assertParseOK(["-v"], - {'show_version': 1, 'verbose': None}, - []) - class TestConflictResolve(ConflictBase): def setUp(self): ConflictBase.setUp(self) @@ -1257,7 +1279,7 @@ class TestConflictResolve(ConflictBase): self.assertEqual(verbose_opt._long_opts, ["--verbose"]) def test_conflict_resolve_help(self): - self.assertStdoutEquals(["-h"], """\ + self.assertOutput(["-h"], """\ options: --verbose increment verbosity -h, --help show this help message and exit @@ -1281,7 +1303,7 @@ options: class TestConflictOverride(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.set_conflict_handler("resolve") self.parser.add_option("-n", "--dry-run", action="store_true", dest="dry_run", @@ -1296,7 +1318,7 @@ class TestConflictOverride(BaseTest): self.assertEqual(opt._long_opts, ["--dry-run"]) def test_conflict_override_help(self): - self.assertStdoutEquals(["-h"], """\ + self.assertOutput(["-h"], """\ options: -h, --help show this help message and exit -n, --dry-run dry run mode @@ -1375,16 +1397,16 @@ class TestHelp(BaseTest): help="store FOO in the foo list for later fooing"), ] os.environ['COLUMNS'] = str(columns) - return OptionParser(option_list=options) + return InterceptingOptionParser(option_list=options) def assertHelpEquals(self, expected_output): - # This trick is used to make optparse believe bar.py is being executed. - oldargv = sys.argv[0] - sys.argv[0] = "./foo/bar.py" - - self.assertStdoutEquals(["-h"], expected_output) - - sys.argv[0] = oldargv + save_argv = sys.argv[:] + try: + # Make optparse believe bar.py is being executed. + sys.argv[0] = os.path.join("foo", "bar.py") + self.assertOutput(["-h"], expected_output) + finally: + sys.argv[:] = save_argv def test_help(self): self.assertHelpEquals(_expected_help_basic) @@ -1441,7 +1463,7 @@ options: """) - + class TestMatchAbbrev(BaseTest): def test_match_abbrev(self): |