Changeset - 0590c952df64
[Not reviewed]
gc-11
0 5 0
Branko Majic (branko) - 6 years ago 2018-02-27 12:49:26
branko@majic.rs
GC-11: Added a help subcommand to the tool:

- Updated functional test for checking on the help subcommand as well.
- Implemented the 'help' subcommand.
- Updated required function signature for the subcommand_parser
decorator (functions should return ArgumentParser instance).
- Fixed a typo in inline documentation.
- Updated the test for subcommand_parser decorator to be a more robust
when checking if function registration works.
5 files changed with 91 insertions and 12 deletions:
0 comments (0 inline, 0 general)
functional_tests/test_help.py
Show inline comments
 
@@ -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
gimmecert/cli.py
Show inline comments
 
@@ -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
 

	
 

	
gimmecert/decorators.py
Show inline comments
 
@@ -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.
 

	
tests/test_cli.py
Show inline comments
 
@@ -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'))
tests/test_decorators.py
Show inline comments
 
@@ -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():
0 comments (0 inline, 0 general)