diff --git a/functional_tests/test_help.py b/functional_tests/test_help.py index 6c54e2b51e4a3ab2216c81bf745798cac39b4cc8..43c78b15cd1208ff71e0708d365f7a87dc311a7a 100644 --- a/functional_tests/test_help.py +++ b/functional_tests/test_help.py @@ -63,20 +63,31 @@ def test_extended_help_shown(): # John is still not quite sure how the tool works. Therefore he # decides to try out the -h flag to the command. process = subprocess.Popen(["gimmecert", "-h"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - stdout, stderr = stdout.decode(), stderr.decode() + stdout_h_flag, stderr_h_flag = process.communicate() + stdout_h_flag, stderr_h_flag = stdout_h_flag.decode(), stderr_h_flag.decode() # In doing so, John is presented with much more extensive # instructions that provide him with better idea on how to use the # tool. - assert stderr == '' + assert stderr_h_flag == '' assert process.returncode == 0 - assert "usage: gimmecert [-h]" in stdout - assert "Examples:" in stdout - assert "optional arguments" in stdout + assert "usage: gimmecert [-h]" in stdout_h_flag + assert "Examples:" in stdout_h_flag + assert "optional arguments" in stdout_h_flag + # Subcommands listed. + assert "{help}" in stdout_h_flag # @TODO: Can't really test this without producing errors, but # possibly not needed. - # assert "positional arguments" in stdout - # @TODO: Can't test at the moment, should be added once the first - # commands is implemented. - # assert "command1|command2" in stdout + # assert "positional arguments" in stdout_h_flag + + # John also notices the help command in the list. He tries that + # one out as well. + process = subprocess.Popen(["gimmecert", "help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout_help, stderr_help = process.communicate() + stdout_help, stderr_help = stdout_help.decode(), stderr_help.decode() + + # John is presented with identical results as when running just + # with the -h flag. + assert process.returncode == 0 + assert stdout_help == stdout_h_flag + assert stderr_help == stderr_h_flag diff --git a/gimmecert/cli.py b/gimmecert/cli.py index 908f794f4fb03e2ff9ac0af5e79b22cefdbd7da0..218f4112b2f7c91491c2d86e7748354d695f4fd9 100644 --- a/gimmecert/cli.py +++ b/gimmecert/cli.py @@ -21,6 +21,8 @@ import argparse +from .decorators import subcommand_parser, get_subcommand_parser_setup_functions + DESCRIPTION = """\ Issues server and client X.509 certificates using a local CA @@ -30,6 +32,15 @@ Examples: """ +@subcommand_parser +def setup_help_subcommand_parser(parser, subparsers): + subparser = subparsers.add_parser('help', description='shows help') + + subparser.set_defaults(func=lambda args: parser.print_help()) + + return subparser + + def get_parser(): """ Sets-up and returns a CLI argument parser. @@ -41,6 +52,11 @@ def get_parser(): parser.set_defaults(func=lambda args: parser.print_usage()) + subparsers = parser.add_subparsers() + + for setup_subcommad_parser in get_subcommand_parser_setup_functions(): + setup_subcommad_parser(parser, subparsers) + return parser diff --git a/gimmecert/decorators.py b/gimmecert/decorators.py index a5832e78ae08f209bb6f037239ecd1bcdecfe32c..d8ea0fce4ab436ddaf320d4da4bfcb76db7058ab 100644 --- a/gimmecert/decorators.py +++ b/gimmecert/decorators.py @@ -41,7 +41,7 @@ def subcommand_parser(func): having multiple code paths that deal with instantion and set-up of subcommand parsers. - The registerd functions are expected to accept two arguments: + The registered functions are expected to accept two arguments: - parser (ArgumentParser), instance of parent parser to which the subcommand (sub)parser belongs to. @@ -50,6 +50,9 @@ def subcommand_parser(func): should instantiate a subparser through it by calling the standard subparsers.add_parser() method. + The registered functions are expeceted to return the subparser + itself. + It is expected that each subcomand parser will set a default function to be invoked with parsed arguments by doing a call to set_defaults(func=subcommand_function). @@ -65,6 +68,8 @@ def subcommand_parser(func): subparser.set_defaults(func=mysubcommand) + return subparser + Later on the registered setup functions should be retrieved through get_subcommand_parser_setup_functions() function. diff --git a/tests/test_cli.py b/tests/test_cli.py index ef2922ce99aa71d1ec9bfd3b34ad2d0a86c758af..55809df657ede4fe0dba763056395aebbe1fbc2d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -22,6 +22,7 @@ import argparse import gimmecert.cli +import gimmecert.decorators from unittest import mock @@ -88,3 +89,48 @@ def test_parser_help_contains_examples(): parser = gimmecert.cli.get_parser() assert 'Examples' in parser.description + + +def test_setup_help_subcommand_parser_registered(): + registered_functions = gimmecert.decorators.get_subcommand_parser_setup_functions() + + assert gimmecert.cli.setup_help_subcommand_parser in registered_functions + + +@mock.patch('gimmecert.cli.get_subcommand_parser_setup_functions') +def test_get_parser_calls_setup_subcommand_parser_functions(mock_get_subcommand_parser_setup_functions): + mock_setup1 = mock.Mock() + mock_setup2 = mock.Mock() + mock_get_subcommand_parser_setup_functions.return_value = [mock_setup1, mock_setup2] + + gimmecert.cli.get_parser() + + assert mock_setup1.called + assert mock_setup2.called + + +def test_setup_help_subcommand_parser_adds_parser(): + mock_parser = mock.Mock() + mock_subparsers = mock.Mock() + + gimmecert.cli.setup_help_subcommand_parser(mock_parser, mock_subparsers) + + assert mock_subparsers.add_parser.called + + +def test_help_subcommand_returns_parser(): + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + + subparser = gimmecert.cli.setup_help_subcommand_parser(parser, subparsers) + + assert isinstance(subparser, argparse.ArgumentParser) + + +def test_help_subcommand_sets_function_callback(): + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + + subparser = gimmecert.cli.setup_help_subcommand_parser(parser, subparsers) + + assert callable(subparser.get_default('func')) diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 255bc59955d67bf261d57d4a604cb17ae1979013..2e7e315111415c74b87c617ea1dc32b1316ef708 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -45,7 +45,8 @@ def test_subcommand_parser_decorator_registers_function(): registered_functions = gimmecert.decorators.get_subcommand_parser_setup_functions() - assert registered_functions == [myfunction1, myfunction2] + assert myfunction1 in registered_functions + assert myfunction2 in registered_functions def test_subcommand_parser_decorator_ensures_function_has_correct_signature():