diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-12 19:58:48 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-12 19:58:48 -0400 |
commit | fbfae45295ba87ec26d97dc4b8abd56631ce3a5d (patch) | |
tree | 575c598e51ad14b9d7a66d327c7b0ac60ada60bb | |
parent | 269c6d3d361729a73fed9070c3d084bb37382e6a (diff) | |
download | python-coveragepy-git-fbfae45295ba87ec26d97dc4b8abd56631ce3a5d.tar.gz |
First new-style command: run
-rw-r--r-- | coverage/cmdline.py | 79 | ||||
-rw-r--r-- | test/test_cmdline.py | 219 |
2 files changed, 147 insertions, 151 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 6481f229..9ea72614 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -5,7 +5,9 @@ import optparse, sys from coverage.execfile import run_python_file -class opts: +class Opts: + """A namespace class for individual options we'll build parsers from.""" + directory = optparse.Option( '-d', '--directory', action='store', dest='directory', ) @@ -17,7 +19,8 @@ class opts: ) pylib = optparse.Option( '-L', '--pylib', action='store_true', - help="Measure coverage even inside the Python installed library, which isn't done by default." + help="Measure coverage even inside the Python installed library, " + "which isn't done by default." ) show_missing = optparse.Option( '-m', '--show-missing', action='store_true', @@ -27,13 +30,19 @@ class opts: ) parallel_mode = optparse.Option( '-p', '--parallel-mode', action='store_true', - help="Include the machine name and process id in the .coverage data file name." + help="Include the machine name and process id in the .coverage " + "data file name." ) timid = optparse.Option( '', '--timid', action='store_true', - help="Use a simpler but slower trace method. Use this if you get seemingly impossible results!" + help="Use a simpler but slower trace method. Use this if you get " + "seemingly impossible results!" + ) + append = optparse.Option( + '-a', '--append', action='store_false', dest="erase_first", + help="Append coverage data to .coverage, otherwise it is started " + "clean with each run." ) - class CoverageOptionParser(optparse.OptionParser, object): """Base OptionParser for coverage. @@ -57,10 +66,11 @@ class CoverageOptionParser(optparse.OptionParser, object): pylib=None, show_missing=None, timid=None, + erase_first=None, ) self.disable_interspersed_args() - self.help_fn = None + self.help_fn = lambda: None class OptionParserError(Exception): """Used to stop the optparse error handler ending the process.""" @@ -73,7 +83,8 @@ class CoverageOptionParser(optparse.OptionParser, object): """ try: - options, args = super(CoverageOptionParser, self).parse_args(args, options) + options, args = \ + super(CoverageOptionParser, self).parse_args(args, options) except self.OptionParserError: return False, None, None return True, options, args @@ -98,14 +109,14 @@ class ClassicOptionParser(CoverageOptionParser): self.add_action('-x', '--execute', 'execute') self.add_options([ - opts.directory, - opts.help, - opts.ignore_errors, - opts.pylib, - opts.show_missing, - opts.omit, - opts.parallel_mode, - opts.timid, + Opts.directory, + Opts.help, + Opts.ignore_errors, + Opts.pylib, + Opts.show_missing, + Opts.omit, + Opts.parallel_mode, + Opts.timid, ]) def add_action(self, dash, dashdash, action_code): @@ -123,26 +134,24 @@ class ClassicOptionParser(CoverageOptionParser): class NewOptionParser(CoverageOptionParser): """Parse one of the new-style commands for coverage.py.""" - def __init__(self, action): + def __init__(self, action, options, defaults={}): super(NewOptionParser, self).__init__( usage="coverage %s [blah]" % action ) - self.set_defaults(actions=[action]) - - -class RunOptionParser(NewOptionParser): - def __init__(self): - super(RunOptionParser, self).__init__("execute") - self.add_options([ - opts.pylib, - opts.parallel_mode, - opts.timid, - ]) - + self.set_defaults(actions=[action], **defaults) + self.add_options(options) CMDS = { - 'run': RunOptionParser(), -} + 'run': NewOptionParser("execute", + [ + Opts.append, + Opts.pylib, + Opts.parallel_mode, + Opts.timid + ], + defaults={'erase_first':True} + ), + } class CoverageScript: @@ -233,6 +242,10 @@ class CoverageScript: self.help_fn("Unexpected arguments: %s" % " ".join(args)) return ERR + if 'execute' in options.actions and not args: + self.help_fn("Nothing to do.") + return ERR + # Do something. self.coverage = self.covpkg.coverage( data_suffix = bool(options.parallel_mode), @@ -240,16 +253,12 @@ class CoverageScript: timid = options.timid, ) - if 'erase' in options.actions: + if 'erase' in options.actions or options.erase_first: self.coverage.erase() else: self.coverage.load() if 'execute' in options.actions: - if not args: - self.help_fn("Nothing to do.") - return ERR - # Run the script. self.coverage.start() try: diff --git a/test/test_cmdline.py b/test/test_cmdline.py index 875692cd..d51553f0 100644 --- a/test/test_cmdline.py +++ b/test/test_cmdline.py @@ -6,104 +6,9 @@ import coverage from coveragetest import CoverageTest -class CmdLineParserTest(CoverageTest): - """Tests of command-line processing for Coverage.""" +OK, ERR = 0, 1 - def setUp(self): - super(CmdLineParserTest, self).setUp() - self.help_out = None - - def help_fn(self, error=None, topic=None): - """A mock help_fn to capture the error messages for tests.""" - assert error or topic - self.help_out = error or ("topic:"+topic) - - def command_line(self, args, ret=0, help_out=""): - """Run a Coverage command line, with `args` as arguments. - - The return code must be `ret`, and the help messages written must be - `help_out`. - - """ - self.help_out = "" - argv = shlex.split(args) - script = coverage.CoverageScript(_help_fn=self.help_fn) - ret_code = script.command_line(argv) - self.assertEqual(ret_code, ret) - self.assertEqual(self.help_out, help_out) - - -class ClassicCmdLineParserTest(CmdLineParserTest): - - def testNoArgumentsAtAll(self): - self.command_line('', - help_out="Code coverage for Python. Use -h for help." - ) - - def testHelp(self): - self.command_line('-h', help_out="topic:usage") - self.command_line('--help', help_out="topic:usage") - - def testUnknownOption(self): - self.command_line('-z', ret=1, - help_out="no such option: -z" - ) - - def testBadActionCombinations(self): - self.command_line('-e -a', ret=1, - help_out="You can't specify the 'erase' and 'annotate' " - "options at the same time." - ) - self.command_line('-e -r', ret=1, - help_out="You can't specify the 'erase' and 'report' " - "options at the same time." - ) - self.command_line('-e -b', ret=1, - help_out="You can't specify the 'erase' and 'html' " - "options at the same time." - ) - self.command_line('-e -c', ret=1, - help_out="You can't specify the 'erase' and 'combine' " - "options at the same time." - ) - self.command_line('-x -a', ret=1, - help_out="You can't specify the 'execute' and 'annotate' " - "options at the same time." - ) - self.command_line('-x -r', ret=1, - help_out="You can't specify the 'execute' and 'report' " - "options at the same time." - ) - self.command_line('-x -b', ret=1, - help_out="You can't specify the 'execute' and 'html' " - "options at the same time." - ) - self.command_line('-x -c', ret=1, - help_out="You can't specify the 'execute' and 'combine' " - "options at the same time." - ) - - def testNeedAction(self): - self.command_line('-p', ret=1, - help_out="You must specify at least one of " - "-e, -x, -c, -r, -a, or -b." - ) - - def testArglessActions(self): - self.command_line('-e foo bar', ret=1, - help_out="Unexpected arguments: foo bar" - ) - self.command_line('-c baz quux', ret=1, - help_out="Unexpected arguments: baz quux" - ) - - def testNothingToDo(self): - self.command_line('-x', ret=1, - help_out="Nothing to do." - ) - - -class CmdLineActionTest(CoverageTest): +class CmdLineTest(CoverageTest): """Tests of execution paths through the command line interpreter.""" def model_object(self): @@ -112,20 +17,24 @@ class CmdLineActionTest(CoverageTest): mk.coverage.return_value = mk return mk - def run_command_line(self, args, ret): - """Run `args` through command_line, returning the Mock it used.""" + def run_command_line(self, args): + """Run `args` through command_line. + + Returns the Mock it used and the status code returned. + + """ m = self.model_object() - ret_actual = coverage.CoverageScript( + ret = coverage.CoverageScript( _covpkg=m, _run_python_file=m.run_python_file, _help_fn=m.help_fn ).command_line(shlex.split(args)) - self.assertEqual(ret_actual, ret, - "Wrong status: got %s, wanted %s" % (ret_actual, ret) - ) - return m + return m, ret - def cmd_executes(self, args, code, ret=0): + def cmd_executes(self, args, code, ret=OK): """Assert that the `args` end up executing the sequence in `code`.""" - m1 = self.run_command_line(args, ret) + m1, r1 = self.run_command_line(args) + self.assertEqual(r1, ret, + "Wrong status: got %s, wanted %s" % (r1, ret) + ) code = textwrap.dedent(code) code = re.sub(r"(?m)^\.", "m2.", code) @@ -136,19 +45,28 @@ class CmdLineActionTest(CoverageTest): def cmd_executes_same(self, args1, args2): """Assert that the `args1` executes the same as `args2`.""" - m1 = self.run_command_line(args1, ret=0) - m2 = self.run_command_line(args2, ret=0) + m1, r1 = self.run_command_line(args1) + m2, r2 = self.run_command_line(args2) + self.assertEqual(r1, r2) self.assertEqual(m1.method_calls, m2.method_calls) - def cmd_help(self, args, help): + def cmd_help(self, args, help_msg=None, topic=None, ret=ERR): """Run a command line, and check that it prints the right help.""" - m = self.run_command_line(args, ret=1) - self.assertEqual(m.method_calls, - [('help_fn', (help,), {})] - ) - + m, r = self.run_command_line(args) + self.assertEqual(r, ret, + "Wrong status: got %s, wanted %s" % (r, ret) + ) + if help_msg: + self.assertEqual(m.method_calls, + [('help_fn', (help_msg,), {})] + ) + else: + self.assertEqual(m.method_calls, + [('help_fn', (), {'topic':topic})] + ) + -class ClassicCmdLineActionTest(CmdLineActionTest): +class ClassicCmdLineTest(CmdLineTest): """Tests of the classic coverage.py command line.""" def testErase(self): @@ -348,10 +266,79 @@ class ClassicCmdLineActionTest(CmdLineActionTest): self.cmd_executes_same("-b -of", "-b --omit=f") self.cmd_executes_same("-b -of,b", "-b --omit=f,b") + def testHelp(self): + # coverage -h + self.cmd_help("-h", topic="usage", ret=OK) + self.cmd_help("--help", topic="usage", ret=OK) + + ## Error cases + + def testArglessActions(self): + self.cmd_help("-e foo bar", "Unexpected arguments: foo bar") + self.cmd_help("-c baz quux", "Unexpected arguments: baz quux") + + def testNeedAction(self): + self.cmd_help("-p", "You must specify at least one of " + "-e, -x, -c, -r, -a, or -b.") + + def testBadActionCombinations(self): + self.cmd_help('-e -a', + "You can't specify the 'erase' and 'annotate' " + "options at the same time." + ) + self.cmd_help('-e -r', + "You can't specify the 'erase' and 'report' " + "options at the same time." + ) + self.cmd_help('-e -b', + "You can't specify the 'erase' and 'html' " + "options at the same time." + ) + self.cmd_help('-e -c', + "You can't specify the 'erase' and 'combine' " + "options at the same time." + ) + self.cmd_help('-x -a', + "You can't specify the 'execute' and 'annotate' " + "options at the same time." + ) + self.cmd_help('-x -r', + "You can't specify the 'execute' and 'report' " + "options at the same time." + ) + self.cmd_help('-x -b', + "You can't specify the 'execute' and 'html' " + "options at the same time." + ) + self.cmd_help('-x -c', + "You can't specify the 'execute' and 'combine' " + "options at the same time." + ) + + def testNothingToDo(self): + self.cmd_help("-x", "Nothing to do.") + + def testUnknownOption(self): + self.cmd_help("-z", "no such option: -z") -class NewCmdLineActionTest(CmdLineActionTest): + +class NewCmdLineTest(CmdLineTest): """Tests of the coverage.py command line.""" + def testRun(self): + self.cmd_executes_same("run f.py", "-e -x f.py") + self.cmd_executes_same("run f.py -a -z a1 a2", "-e -x f.py -a -z a1 a2") + self.cmd_executes_same("run -a f.py", "-x f.py") + self.cmd_executes_same("run -p f.py", "-e -x -p f.py") + self.cmd_executes_same("run -L f.py", "-e -x -L f.py") + self.cmd_executes_same("run --timid f.py", "-e -x --timid f.py") + self.cmd_executes_same("run", "-x") + + def testNoArgumentsAtAll(self): + self.cmd_help("", + "Code coverage for Python. Use -h for help.", ret=OK + ) + def testBadCommand(self): self.cmd_help("xyzzy", "Unknown command: 'xyzzy'") |