Changeset - 4077e8038111
[Not reviewed]
0 1 1
Lance Edgar (lance) - 11 years ago 2014-02-10 00:24:28
lance@edbob.org
Add basic tests for command classes.
2 files changed with 77 insertions and 14 deletions:
0 comments (0 inline, 0 general)
rattail/commands.py
Show inline comments
 
@@ -155,120 +155,108 @@ Commands:\n""".format(self.description, self.name))
 
            if len(args.command) != 1:
 
                self.print_help()
 
                return
 
            cmd = args.command[0]
 
            if cmd not in self.subcommands:
 
                self.print_help()
 
                return
 
            cmd = self.subcommands[cmd](parent=self)
 
            cmd.parser.print_help()
 
            return
 
        elif cmd not in self.subcommands:
 
            self.print_help()
 
            return
 

	
 
        # Basic logging should be established before init()ing.
 

	
 
        # Use root logger if setting logging flags.
 
        log = logging.getLogger()
 

	
 
        # TODO: Figure out the basic logging pattern we're after here.
 
        # edbob.basic_logging()
 
        logging.basicConfig()
 

	
 
        if args.verbose:
 
            log.setLevel(logging.INFO)
 
        if args.debug:
 
            log.setLevel(logging.DEBUG)
 

	
 
        # Initialize everything...
 
        if not args.no_init:
 
            edbob.init(self.name, *(args.config_paths or []))
 

	
 
            # Command line logging flags should override config.
 
            if args.verbose:
 
                log.setLevel(logging.INFO)
 
            if args.debug:
 
                log.setLevel(logging.DEBUG)
 
        
 
        # And finally, do something of real value...
 
        cmd = self.subcommands[cmd](self)
 
        cmd.show_progress = args.progress
 
        cmd._run(*(args.command + args.argv))
 

	
 

	
 
class Subcommand(object):
 
    """
 
    Base class for application subcommands.
 
    """
 
    name = 'UNDEFINED'
 
    description = 'UNDEFINED'
 

	
 
    def __init__(self, parent):
 
        self.parent = parent
 
        self.stdout = parent.stdout
 
        self.stderr = parent.stderr
 
        self.parser = argparse.ArgumentParser(
 
            prog='{0} {1}'.format(self.parent.name, self.name),
 
            description=self.description)
 
        self.add_parser_args(self.parser)
 

	
 
    @property
 
    def name(self):
 
        """
 
        The name of the subcommand.
 
        """
 
        raise NotImplementedError
 

	
 
    @property
 
    def description(self):
 
        """
 
        The description for the subcommand.
 
        """
 
        raise NotImplementedError
 

	
 
    def __repr__(self):
 
        return "Subcommand(name={0})".format(repr(self.name))
 

	
 
    def add_parser_args(self, parser):
 
        """
 
        Configure additional arguments for the subcommand argument parser.
 
        """
 
        pass
 
            
 
    def _run(self, *args):
 
        args = self.parser.parse_args(list(args))
 
        return self.run(args)
 

	
 
    def run(self, args):
 
        """
 
        Run the subcommand logic.
 
        """
 
        raise NotImplementedError
 

	
 

	
 
class AddUser(Subcommand):
 
    """
 
    Adds a user to the database.
 
    """
 

	
 
    name = 'adduser'
 
    description = "Add a user to the database."
 

	
 
    def add_parser_args(self, parser):
 
        parser.add_argument('url', metavar='URL',
 
                            help="Database engine URL")
 
        parser.add_argument('username',
 
                            help="Username for the new account.")
 
        parser.add_argument('-A', '--administrator',
 
                            action='store_true',
 
                            help="Add the new user to the Administrator role.")
 

	
 
    def run(self, args):
 
        from sqlalchemy import create_engine
 
        from sqlalchemy.orm import sessionmaker
 
        from .db.model import User
 
        from .db.auth import set_user_password, administrator_role
 

	
 
        engine = create_engine(args.url)
 
        Session = sessionmaker(bind=engine)
 

	
 
        session = Session()
 
        if session.query(User).filter_by(username=args.username).count():
tests/test_commands.py
Show inline comments
 
new file 100644
 

	
 
from unittest import TestCase
 
from cStringIO import StringIO
 

	
 
from mock import patch
 

	
 
from rattail import commands
 

	
 

	
 
class TestArgumentParser(TestCase):
 

	
 
    def test_parse_args_preserves_extra_argv(self):
 
        parser = commands.ArgumentParser()
 
        parser.add_argument('--some-optional-arg')
 
        parser.add_argument('some_required_arg')
 
        args = parser.parse_args([
 
                '--some-optional-arg', 'optional-value', 'required-value',
 
                'some', 'extra', 'args'])
 
        self.assertEqual(args.some_required_arg, 'required-value')
 
        self.assertEqual(args.some_optional_arg, 'optional-value')
 
        self.assertEqual(args.argv, ['some', 'extra', 'args'])
 

	
 

	
 
class TestCommand(TestCase):
 

	
 
    def test_initial_subcommands_are_sane(self):
 
        command = commands.Command()
 
        self.assertTrue('filemon' in command.subcommands)
 

	
 
    def test_unicode(self):
 
        command = commands.Command()
 
        command.name = 'some-app'
 
        self.assertEqual(unicode(command), u'some-app')
 
        
 
    def test_iter_subcommands_includes_expected_item(self):
 
        command = commands.Command()
 
        found = False
 
        for subcommand in command.iter_subcommands():
 
            if subcommand.name == 'filemon':
 
                found = True
 
                break
 
        self.assertTrue(found)
 

	
 
    def test_print_help(self):
 
        command = commands.Command()
 
        stdout = StringIO()
 
        command.stdout = stdout
 
        command.print_help()
 
        output = stdout.getvalue()
 
        stdout.close()
 
        self.assertTrue('Usage:' in output)
 
        self.assertTrue('Options:' in output)
 

	
 

	
 
class TestSubcommand(TestCase):
 

	
 
    def test_repr(self):
 
        command = commands.Command()
 
        subcommand = commands.Subcommand(command)
 
        subcommand.name = 'fake-command'
 
        self.assertEqual(repr(subcommand), "Subcommand(name='fake-command')")
 

	
 
    def test_add_parser_args_does_nothing(self):
 
        command = commands.Command()
 
        subcommand = commands.Subcommand(command)
 
        # Not sure this is really the way to test this, but...
 
        self.assertEqual(len(subcommand.parser._action_groups[0]._actions), 1)
 
        subcommand.add_parser_args(subcommand.parser)
 
        self.assertEqual(len(subcommand.parser._action_groups[0]._actions), 1)
 

	
 
    def test_run_not_implemented(self):
 
        command = commands.Command()
 
        subcommand = commands.Subcommand(command)
 
        args = subcommand.parser.parse_args([])
 
        self.assertRaises(NotImplementedError, subcommand.run, args)
0 comments (0 inline, 0 general)