~fabrixxm/climatik

296bc40f749529e26689dfab070dcb17248699ad — fabrixxm 2 years ago 0e80234
Add unit tests
A nose2.cfg => nose2.cfg +3 -0
@@ 0,0 1,3 @@
[unittest]
start-dir=./tests
code-directories=../

A tests/climatiktest.py => tests/climatiktest.py +32 -0
@@ 0,0 1,32 @@
import unittest
from io import StringIO
import climatik

class ClimatikTest(unittest.TestCase):
    def setUp(self):
        climatik.commands = {
            '' : {
                'help': '',
                'description': '',
                'commands': {}
            }
        }

    def get_group(self, group=""):
        self.assertIn(group, climatik.commands)
        return climatik.commands[group]

    def get_command(self, cmd="test", group=""):
        group = self.get_group(group)
        self.assertIn(cmd, group['commands'])
        return group['commands'][cmd]

    def get_arg(self, name="arg", cmd="test", group=""):
        cmd = self.get_command(cmd, group)
        self.assertIn(name, cmd['args'])
        return cmd['args'][name]

    def get_param(self, name="--arg", cmd="test", group=""):
        cmd = self.get_command(cmd, group)
        self.assertIn(name, cmd['args'])
        return cmd['args'][name]

A tests/test_args.py => tests/test_args.py +70 -0
@@ 0,0 1,70 @@
import climatik
from climatik import command
from typing import Optional

from climatiktest import ClimatikTest

class TestArgs(ClimatikTest):
    def test_no_args(self):
        @command
        def test():
            pass
        
        cmd = self.get_command()
        self.assertDictEqual(cmd['args'], {})

    def test_positional_args(self):
        @command
        def test(arg):
            pass
        
        cmd = self.get_command()
        self.assertIn('arg', cmd['args'])

    def test_positional_args_with_underscore(self):
        @command
        def test(some_arg):
            pass
        
        cmd = self.get_command()
        self.assertIn('some-arg', cmd['args'])

    def test_positional_args_required_no_type_hint(self):
        @command
        def test(arg):
            pass
        
        arg = self.get_arg()
        self.assertEqual(arg['type'], str)
        self.assertNotIn('nargs', arg)

    def test_positional_args_required_type_hint(self):
        @command
        def test(arg:int):
            pass
        
        arg = self.get_arg()
        self.assertEqual(arg['type'], int)
        self.assertNotIn('nargs', arg)
    
    def test_positional_args_optional_type_hint(self):
        @command
        def test(arg:Optional[int] = None):
            pass
        
        arg = self.get_arg()
        self.assertEqual(arg['type'], int)
        self.assertEqual(arg['default'], None)
        self.assertIn('nargs', arg)
        self.assertEqual(arg['nargs'], "?")

    def multiple_required_args(self):
        @command
        def test(src, dest):
            pass
        src_arg = self.get_arg("src")
        dest_arg = self.get_arg("dest")
        self.assertEqual(src_arg['type'], str)
        self.assertNotIn('nargs', src_arg)
        self.assertEqual(dest_arg['type'], str)
        self.assertNotIn('nargs', dest_arg)
\ No newline at end of file

A tests/test_command.py => tests/test_command.py +32 -0
@@ 0,0 1,32 @@
import climatik
from climatik import command
from typing import Optional

from climatiktest import ClimatikTest

class TestBase(ClimatikTest):

    def test_create_subcommand(self):
        @command
        def test():
            pass
        cmd = self.get_command()
        self.assertEqual(cmd['func'], test)

    def test_create_subcommand_with_custom_name(self):
        @command("foo")
        def test():
            pass
        self.assertNotIn('test', climatik.commands[''])
        cmd = self.get_command('foo')
        self.assertEqual(cmd['func'], test)

    def multiple_commands(self):
        @command
        def test1():
            pass
    
        @command
        def test2():
            pass


A tests/test_command_group.py => tests/test_command_group.py +103 -0
@@ 0,0 1,103 @@

import climatik
from climatik import command, group, NameClashException
from climatiktest import ClimatikTest


class TestCommandGroup(ClimatikTest):

    def test_simple_command_group(self):
        @command
        def foo():
            pass

        @command(group_name="group")
        def bar():
            pass

        self.assertIn('', climatik.commands)
        self.assertIn('foo', climatik.commands['']['commands'])
        self.assertIn('group', climatik.commands)
        self.assertIn('bar', climatik.commands['group']['commands'])
        
        parser = climatik.get_parser()
        self.assertIn('{foo,group}', parser.format_help())
        
        # this is the only way I fount to get the subparser help as a string...
        # I'm sue I'm missing something here.
        help = parser._subparsers._group_actions[0]._name_parser_map['group'].format_help()
        self.assertIn('{bar}', help)

    def test_overlap_group_on_command(self):
        """a group and a command on main group cannot have the same name"""
        with self.assertRaises(NameClashException) as context:
            @command
            def group():
                pass

            @command(group_name="group")
            def bar():
                pass

    def test_overlap_command_on_group(self):
        """a group and a command on main group cannot have the same name"""
        with self.assertRaises(NameClashException) as context:
            @command(group_name="group")
            def bar():
                pass

            @command
            def group():
                pass

    def test_group_help_and_description(self):
        group('group', help="Group help", description="group description")
        @command(group_name="group")
        def bar():
            pass
            
        g = self.get_group("group")
        self.assertEqual(g['help'], "Group help")
        self.assertEqual(g['description'], "group description")

        parser = climatik.get_parser()
        help = parser.format_help()
        self.assertIn("group     Group help", help)

        help = parser._subparsers._group_actions[0]._name_parser_map['group'].format_help()
        self.assertIn("group description", help)

    def test_group_help_and_description_after(self):
        @command(group_name="group")
        def bar():
            pass

        group('group', help="Group help", description="group description")

        g = self.get_group("group")
        self.assertEqual(g['help'], "Group help")
        self.assertEqual(g['description'], "group description")

        parser = climatik.get_parser()
        help = parser.format_help()
        self.assertIn("group     Group help", help)

        help = parser._subparsers._group_actions[0]._name_parser_map['group'].format_help()
        self.assertIn("group description", help)
    
    def test_group_context_manager(self):
        with group('group', help="Group help", description="group description"):
            @command
            def bar():
                pass

        g = self.get_group("group")
        self.assertEqual(g['help'], "Group help")
        self.assertEqual(g['description'], "group description")

        parser = climatik.get_parser()
        help = parser.format_help()
        self.assertIn("group     Group help", help)

        help = parser._subparsers._group_actions[0]._name_parser_map['group'].format_help()
        self.assertIn("group description", help)
\ No newline at end of file

A tests/test_docstring.py => tests/test_docstring.py +41 -0
@@ 0,0 1,41 @@
import climatik
from climatik import command
from typing import Optional

from climatiktest import ClimatikTest

class TestDocstring(ClimatikTest):
    def test_help_and_description(self):
        @command
        def test():
            """Command help line
            
            and description
            """
            pass
        
        cmd = self.get_command()
        self.assertEqual(cmd['help'], "Command help line")
        self.assertEqual(cmd['description'], test.__doc__)

        parser = climatik.get_parser()
        help = parser.format_help()
        self.assertIn('{test}', help)
        self.assertIn('Command help line', help)

    def test_arg_help_docstring(self):
        @command
        def test(arg):
            """Command help line
            
            @param arg: arg help line
            """
            pass
        
        cmd = self.get_command()
        self.assertEqual(cmd['help'], "Command help line")
        self.assertEqual(cmd['description'].strip(), "Command help line")
        
        arg = cmd['args']['arg']
        self.assertIn('help', arg)
        self.assertEqual(arg['help'], "arg help line")
\ No newline at end of file

A tests/test_params.py => tests/test_params.py +53 -0
@@ 0,0 1,53 @@
import climatik
from climatik import command
from typing import Optional

from climatiktest import ClimatikTest

class TestParams(ClimatikTest):
  
    def test_param_no_type_hint(self):
        """a param is an argument with a default value"""
        @command
        def test(arg = None):
            pass
        arg = self.get_param()
        self.assertEqual(arg['type'], str)
        self.assertEqual(arg['default'], None)

    def test_param_with_underscore(self):
        @command
        def test(some_arg = None):
            pass
        cmd = self.get_command()
        self.assertIn('--some-arg', cmd['args'])

    def test_param_type_hint(self):
        @command
        def test(arg:int = 0):
            pass
        arg = self.get_param()
        self.assertEqual(arg['type'], int)
        self.assertEqual(arg['default'], 0)

    def test_flag(self):
        """a flag is a param with type bool wich if set on command line will be `True`"""
        @command
        def test(do_something:bool):
            pass
        arg = self.get_param('--do-something')
        self.assertNotIn('type', arg)
        self.assertNotIn('default', arg )
        self.assertIn('action', arg)
        self.assertEqual(arg['action'], 'store_true')

    def test_flag_default_true(self):
        """a boolean flag with default `True` will be `False` if set on command line"""
        @command
        def test(invert_value:bool = True):
            pass
        arg = self.get_param('--invert-value')
        self.assertNotIn('type', arg)
        self.assertNotIn('default', arg )
        self.assertIn('action', arg)
        self.assertEqual(arg['action'], 'store_false')