1
0
Fork 0
wuttjamaican/tests/commands/test_base.py
Lance Edgar ed6a5db452 Add Subcommand.make_arg_parser() method
split that out for clarity
2023-11-21 20:48:44 -06:00

205 lines
6.1 KiB
Python

# -*- coding: utf-8; -*-
import argparse
import sys
from unittest import TestCase
from unittest.mock import MagicMock, patch
from wuttjamaican.commands import base
from wuttjamaican.commands.setup import Setup
class TestCommand(TestCase):
def test_base(self):
# base command is for 'wutta' and has a 'setup' subcommand
cmd = base.Command()
self.assertEqual(cmd.name, 'wutta')
self.assertIn('setup', cmd.subcommands)
self.assertEqual(str(cmd), 'wutta')
def test_subcommand_entry_points(self):
with patch('wuttjamaican.commands.base.load_entry_points') as load_entry_points:
# empty entry points
load_entry_points.side_effect = lambda group: {}
cmd = base.Command()
self.assertEqual(cmd.subcommands, {})
# typical entry points
load_entry_points.side_effect = lambda group: {'setup': Setup}
cmd = base.Command()
self.assertEqual(cmd.subcommands, {'setup': Setup})
self.assertEqual(cmd.subcommands['setup'].name, 'setup')
# legacy entry points
# nb. mock returns entry points only when legacy name is used
load_entry_points.side_effect = lambda group: {} if 'subcommands' in group else {'setup': Setup}
cmd = base.Command()
self.assertEqual(cmd.subcommands, {'setup': Setup})
self.assertEqual(cmd.subcommands['setup'].name, 'setup')
def test_sorted_subcommands(self):
cmd = base.Command(subcommands={'foo': 'FooSubcommand',
'bar': 'BarSubcommand'})
srtd = cmd.sorted_subcommands()
self.assertEqual(srtd, ['BarSubcommand', 'FooSubcommand'])
def test_run_may_print_help(self):
class Hello(base.Subcommand):
name = 'hello'
cmd = base.Command(subcommands={'hello': Hello})
# first run is not "tested" per se but gives us some coverage.
# (this will *actually* print help, b/c no args specified)
try:
cmd.run()
except SystemExit:
pass
# from now on we mock the help
print_help = MagicMock()
cmd.print_help = print_help
# help is shown if no subcommand is given
try:
cmd.run()
except SystemExit:
pass
print_help.assert_called_once_with()
# help is shown if -h is given
print_help.reset_mock()
try:
cmd.run('-h')
except SystemExit:
pass
print_help.assert_called_once_with()
# help is shown if --help is given
print_help.reset_mock()
try:
cmd.run('--help')
except SystemExit:
pass
print_help.assert_called_once_with()
# help is shown if bad arg is given
print_help.reset_mock()
try:
cmd.run('--this-means-nothing')
except SystemExit:
pass
print_help.assert_called_once_with()
# help is shown if bad subcmd is given
print_help.reset_mock()
try:
cmd.run('make-sandwich')
except SystemExit:
pass
print_help.assert_called_once_with()
# main help is *not* shown if subcommand *and* -h are given
# (sub help is shown instead in that case)
print_help.reset_mock()
try:
cmd.run('hello', '-h')
except SystemExit:
pass
print_help.assert_not_called()
def test_run_invokes_subcommand(self):
class Hello(base.Subcommand):
name = 'hello'
def add_args(self):
self.parser.add_argument('--foo', action='store_true')
def run(self, args):
self.run_with(foo=args.foo)
run_with = Hello.run_with = MagicMock()
cmd = base.Command(subcommands={'hello': Hello})
# omit --foo in which case that is false by default
cmd.run('hello')
run_with.assert_called_once_with(foo=False)
# specify --foo in which case that is true
run_with.reset_mock()
cmd.run('hello', '--foo')
run_with.assert_called_once_with(foo=True)
class TestCommandArgumentParser(TestCase):
def test_parse_args(self):
kw = {
'prog': 'wutta',
'add_help': False,
}
# nb. examples below assume a command line like:
# bin/wutta foo --bar
# first here is what default parser does
parser = argparse.ArgumentParser(**kw)
parser.add_argument('subcommand', nargs='*')
try:
args = parser.parse_args(['foo', '--bar'])
except SystemExit:
# nb. parser was not happy, tried to exit process
args = None
else:
self.assertEqual(args.subcommand, ['foo', '--bar'])
self.assertFalse(hasattr(args, 'argv'))
# now here is was custom parser does
# (moves extras to argv for subcommand parser)
parser = base.CommandArgumentParser(**kw)
parser.add_argument('subcommand', nargs='*')
args = parser.parse_args(['foo', '--bar'])
self.assertEqual(args.subcommand, ['foo'])
self.assertEqual(args.argv, ['--bar'])
class TestSubcommand(TestCase):
def test_basic(self):
cmd = base.Command()
subcmd = base.Subcommand(cmd)
subcmd.name = 'foobar'
self.assertEqual(repr(subcmd), 'Subcommand(name=foobar)')
# TODO: this doesn't really test anything per se, but at least
# gives us the coverage..
subcmd._run()
class TestMain(TestCase):
# nb. this doesn't test anything per se but gives coverage
def test_explicit_args(self):
try:
base.main('--help')
except SystemExit:
pass
def test_implicit_args(self):
def true_exit(*args):
sys.exit(*args)
with patch('wuttjamaican.commands.base.sys') as mocksys:
mocksys.argv = ['wutta', '--help']
mocksys.exit = true_exit
try:
base.main()
except SystemExit:
pass