def test_tool_exec_help_command_on_command_ok(): """Execute charmcraft asking for help on a command ok.""" dispatcher = Dispatcher(['help', 'version'], COMMAND_GROUPS) with patch('charmcraft.helptexts.get_command_help') as mock: mock.return_value = 'test help' with pytest.raises(CommandError) as cm: dispatcher.run() error = cm.value # check the given information to the builder args = mock.call_args[0] assert args[0] == COMMAND_GROUPS assert args[1].__class__ == VersionCommand assert {x[0] for x in args[2] } == {'-h, --help', '-v, --verbose', '-q, --quiet'} # check the result of the full help builder is what is shown assert error.argsparsing assert str(error) == "test help"
def test_dispatcher_build_commands_ok(): """Correct command loading.""" cmd0, cmd1, cmd2 = [create_command("cmd-name-{}".format(n), "cmd help") for n in range(3)] groups = [ CommandGroup("whatever title", [cmd0]), CommandGroup("other title", [cmd1, cmd2]), ] dispatcher = Dispatcher(groups) assert len(dispatcher.commands) == 3 for cmd in [cmd0, cmd1, cmd2]: expected_class = dispatcher.commands[cmd.name] assert expected_class == cmd
def test_tool_exec_help_command_all(): """Execute charmcraft asking for detailed help.""" dispatcher = Dispatcher(['help', '--all'], COMMAND_GROUPS) with patch('charmcraft.helptexts.get_detailed_help') as mock: mock.return_value = 'test help' with pytest.raises(CommandError) as cm: dispatcher.run() error = cm.value # check the given information to the builder args = mock.call_args[0] assert args[0] == COMMAND_GROUPS assert sorted(x[0] for x in args[1]) == [ '-h, --help', '-p, --project-dir', '-q, --quiet', '-v, --verbose' ] # check the result of the full help builder is what is shown assert error.argsparsing assert str(error) == "test help" assert error.retcode == 0
def test_tool_exec_help_command_all(): """Execute charmcraft asking for detailed help.""" command_groups = [CommandGroup("group", [])] dispatcher = Dispatcher(command_groups) with patch("charmcraft.helptexts.HelpBuilder.get_detailed_help") as mock: mock.return_value = "test help" with pytest.raises(ProvideHelpException) as cm: dispatcher.pre_parse_args(["help", "--all"]) # check the result of the help builder is what is transmitted assert str(cm.value) == "test help" # check the given information to the help text builder args = mock.call_args[0] assert sorted(x[0] for x in args[0]) == [ "-h, --help", "-q, --quiet", "-t, --trace", "-v, --verbose", ]
def test_dispatcher_command_execution_ok(): """Command execution depends of the indicated name in command line, return code ok.""" class MyCommandControl(BaseCommand): help_msg = "some help" def run(self, parsed_args): self._executed.append(parsed_args) class MyCommand1(MyCommandControl): name = "name1" _executed = [] class MyCommand2(MyCommandControl): name = "name2" _executed = [] groups = [("test-group", "title", [MyCommand1, MyCommand2])] dispatcher = Dispatcher(["name2"], groups) dispatcher.run() assert MyCommand1._executed == [] assert isinstance(MyCommand2._executed[0], argparse.Namespace)
def test_tool_exec_help_command_on_command_complex(): """Execute charmcraft asking for help on a command with parameters and options.""" def fill_parser(self, parser): parser.add_argument('param1', help="help on param1") parser.add_argument('param2', help="help on param2") parser.add_argument('--option1', help="help on option1") parser.add_argument('-o2', '--option2', help="help on option2") cmd = create_command('somecommand', 'This command does that.') cmd.fill_parser = fill_parser command_groups = COMMAND_GROUPS + [('group', 'help text', [cmd])] dispatcher = Dispatcher(['help', 'somecommand'], command_groups) with patch('charmcraft.helptexts.get_command_help') as mock: mock.return_value = 'test help' with pytest.raises(CommandError) as cm: dispatcher.run() error = cm.value # check the given information to the builder args = mock.call_args[0] assert args[0] == COMMAND_GROUPS assert args[1].__class__ == cmd expected_options = [ '--option1', '-h, --help', '-o2, --option2', '-p, --project-dir', '-q, --quiet', '-v, --verbose', 'param1', 'param2', ] assert sorted(x[0] for x in args[2]) == expected_options # check the result of the full help builder is what is shown assert error.argsparsing assert str(error) == "test help" assert error.retcode == 0
def test_tool_exec_command_bad_option_type(help_builder): """Execute a correct command but giving the valid option a bad value.""" def fill_parser(self, parser): parser.add_argument("--number", type=int) cmd = create_command("somecommand", "This command does that.") cmd.fill_parser = fill_parser command_groups = [CommandGroup("group", [cmd])] dispatcher = Dispatcher(command_groups) dispatcher.pre_parse_args(["somecommand", "--number=foo"]) help_builder.init("testapp", "general summary", command_groups) with pytest.raises(ArgumentParsingError) as cm: dispatcher.load_command("config") expected = textwrap.dedent("""\ Usage: testapp [options] command [args]... Try 'testapp somecommand -h' for help. Error: argument --number: invalid int value: 'foo' """) error = cm.value assert str(error) == expected
def test_dispatcher_build_commands_ok(): """Correct command loading.""" cmd0, cmd1, cmd2 = [create_command('cmd-name-{}'.format(n), 'cmd help') for n in range(3)] groups = [ ('test-group-A', 'whatever title', [cmd0]), ('test-group-B', 'other title', [cmd1, cmd2]), ] dispatcher = Dispatcher([cmd0.name], groups) assert len(dispatcher.commands) == 3 for cmd, group in [(cmd0, 'test-group-A'), (cmd1, 'test-group-B'), (cmd2, 'test-group-B')]: expected_class, expected_group = dispatcher.commands[cmd.name] assert expected_class == cmd assert expected_group == group
def test_tool_exec_full_help(sysargv): """Execute charmcraft without any option at all or explicitly asking for help.""" with patch("charmcraft.helptexts.get_full_help") as mock: mock.return_value = "test help" with pytest.raises(CommandError) as cm: dispatcher = Dispatcher(sysargv, COMMAND_GROUPS) dispatcher.run() error = cm.value # check the given information to the builder args = mock.call_args[0] assert args[0] == COMMAND_GROUPS assert sorted(x[0] for x in args[1]) == [ "-h, --help", "-p, --project-dir", "-q, --quiet", "-v, --verbose", ] # check the result of the full help builder is what is shown assert error.argsparsing assert str(error) == "test help"
def test_tool_exec_help_command_on_command_complex(): """Execute charmcraft asking for help on a command with parameters and options.""" def fill_parser(self, parser): parser.add_argument("param1", help="help on param1") parser.add_argument("param2", help="help on param2") parser.add_argument("param3", metavar="transformed3", help="help on param2") parser.add_argument("--option1", help="help on option1") parser.add_argument("-o2", "--option2", help="help on option2") cmd = create_command("somecommand", "This command does that.") cmd.fill_parser = fill_parser command_groups = [CommandGroup("group", [cmd])] dispatcher = Dispatcher(command_groups) with patch("charmcraft.helptexts.HelpBuilder.get_command_help") as mock: mock.return_value = "test help" with pytest.raises(ProvideHelpException) as cm: dispatcher.pre_parse_args(["help", "somecommand"]) # check the result of the help builder is what is transmitted assert str(cm.value) == "test help" # check the given information to the help text builder args = mock.call_args[0] assert args[0].__class__ == cmd expected_options = [ "--option1", "-h, --help", "-o2, --option2", "-q, --quiet", "-t, --trace", "-v, --verbose", "param1", "param2", "transformed3", ] assert sorted(x[0] for x in args[1]) == expected_options
def test_dispatcher_command_execution_ok(): """Command execution depends of the indicated name in command line, return code ok.""" class MyCommandControl(BaseCommand): help_msg = "some help" def __init__(self, group): super().__init__(group) self.executed = None def run(self, parsed_args): self.executed = parsed_args class MyCommand1(MyCommandControl): name = 'name1' class MyCommand2(MyCommandControl): name = 'name2' groups = [('test-group', 'title', [MyCommand1, MyCommand2])] dispatcher = Dispatcher(['name2'], groups) dispatcher.run() assert dispatcher.commands['name1'].executed is None assert isinstance(dispatcher.commands['name2'].executed, argparse.Namespace)
def test_tool_exec_help_command_on_command_ok(): """Execute charmcraft asking for help on a command ok.""" cmd = create_command("somecommand", "This command does that.") command_groups = [CommandGroup("group", [cmd])] dispatcher = Dispatcher(command_groups) with patch("charmcraft.helptexts.HelpBuilder.get_command_help") as mock: mock.return_value = "test help" with pytest.raises(ProvideHelpException) as cm: dispatcher.pre_parse_args(["help", "somecommand"]) # check the result of the help builder is what is transmitted assert str(cm.value) == "test help" # check the given information to the help text builder args = mock.call_args[0] assert isinstance(args[0], cmd) assert sorted(x[0] for x in args[1]) == [ "-h, --help", "-q, --quiet", "-t, --trace", "-v, --verbose", ]
def test_dispatcher_command_execution_crash(): """Command crashing doesn't pass through, we inform nicely.""" class MyCommand(BaseCommand): help_msg = "some help" name = "cmdname" def run(self, parsed_args): raise ValueError() groups = [CommandGroup("title", [MyCommand])] dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["cmdname"]) dispatcher.load_command("config") with pytest.raises(ValueError): dispatcher.run()
def test_tool_exec_command_dash_help_reverse(help_option): """Execute a command (that needs no params) asking for help.""" cmd = create_command("somecommand", "This command does that.") command_groups = [CommandGroup("group", [cmd])] dispatcher = Dispatcher(command_groups) with patch("charmcraft.helptexts.HelpBuilder.get_command_help") as mock: mock.return_value = "test help" with pytest.raises(ProvideHelpException) as cm: dispatcher.pre_parse_args([help_option, "somecommand"]) # check the result of the full help builder is what is transmitted assert str(cm.value) == "test help" # check the given information to the help text builder args = mock.call_args[0] assert args[0].__class__ == cmd assert sorted(x[0] for x in args[1]) == [ "-h, --help", "-q, --quiet", "-t, --trace", "-v, --verbose", ]
def test_tool_exec_command_dash_help_reverse(help_option): """Execute a command (that needs no params) asking for help.""" cmd = create_command('somecommand', 'This command does that.') command_groups = COMMAND_GROUPS + [('group', 'help text', [cmd])] dispatcher = Dispatcher([help_option, 'somecommand'], command_groups) with patch('charmcraft.helptexts.get_command_help') as mock: mock.return_value = 'test help' with pytest.raises(CommandError) as cm: dispatcher.run() error = cm.value # check the given information to the builder args = mock.call_args[0] assert args[0] == COMMAND_GROUPS assert args[1].__class__ == cmd assert {x[0] for x in args[2] } == {'-h, --help', '-v, --verbose', '-q, --quiet'} # check the result of the full help builder is what is shown assert error.argsparsing assert str(error) == "test help"
def test_tool_exec_command_wrong_option(): """Execute a correct command but with a wrong option.""" cmd = create_command('somecommand', 'This command does that.') command_groups = [('group', 'help text', [cmd])] with pytest.raises(CommandError) as cm: Dispatcher(['somecommand', '--whatever'], command_groups) expected = textwrap.dedent("""\ Usage: charmcraft [options] command [args]... Try 'charmcraft somecommand -h' for help. Error: unrecognized arguments: --whatever """) error = cm.value assert error.argsparsing assert str(error) == expected
def test_dispatcher_command_return_code(): """Command ends indicating the return code to be used.""" class MyCommand(BaseCommand): help_msg = "some help" name = "cmdname" def run(self, parsed_args): return 17 groups = [CommandGroup("title", [MyCommand])] dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["cmdname"]) dispatcher.load_command("config") retcode = dispatcher.run() assert retcode == 17
def test_dispatcher_build_commands_ok(): """Correct command loading.""" cmd0, cmd1, cmd2 = [ create_command("cmd-name-{}".format(n), "cmd help") for n in range(3) ] groups = [ ("test-group-A", "whatever title", [cmd0]), ("test-group-B", "other title", [cmd1, cmd2]), ] dispatcher = Dispatcher([cmd0.name], groups) assert len(dispatcher.commands) == 3 for cmd, group in [ (cmd0, "test-group-A"), (cmd1, "test-group-B"), (cmd2, "test-group-B"), ]: expected_class, expected_group = dispatcher.commands[cmd.name] assert expected_class == cmd assert expected_group == group
def test_dispatcher_build_commands_repeated(): """Error while loading commands with repeated name.""" class Foo(BaseCommand): help_msg = "some help" name = "repeated" class Bar(BaseCommand): help_msg = "some help" name = "cool" class Baz(BaseCommand): help_msg = "some help" name = "repeated" groups = [ ("test-group-1", "whatever title", [Foo, Bar]), ("test-group-2", "other title", [Baz]), ] expected_msg = "Multiple commands with same name: (Foo|Baz) and (Baz|Foo)" with pytest.raises(RuntimeError, match=expected_msg): Dispatcher([], groups)
def test_dispatcher_load_commands_repeated(): """Error while loading commands with repeated name.""" class Foo(BaseCommand): help_msg = "some help" name = 'repeated' class Bar(BaseCommand): help_msg = "some help" name = 'cool' class Baz(BaseCommand): help_msg = "some help" name = 'repeated' groups = [ ('test-group-1', 'whatever title', [Foo, Bar]), ('test-group-2', 'other title', [Baz]), ] expected_msg = "Multiple commands with same name: (Foo|Baz) and (Baz|Foo)" with pytest.raises(RuntimeError, match=expected_msg): Dispatcher([], groups)
def test_tool_exec_command_bad_option_type(): """Execute a correct command but giving the valid option a bad value.""" def fill_parser(self, parser): parser.add_argument('--number', type=int) cmd = create_command('somecommand', 'This command does that.') cmd.fill_parser = fill_parser command_groups = [('group', 'help text', [cmd])] with pytest.raises(CommandError) as cm: Dispatcher(['somecommand', '--number=foo'], command_groups) expected = textwrap.dedent("""\ Usage: charmcraft [options] command [args]... Try 'charmcraft somecommand -h' for help. Error: argument --number: invalid int value: 'foo' """) error = cm.value assert error.argsparsing assert str(error) == expected
def test_tool_exec_command_wrong_option(help_builder): """Execute a correct command but with a wrong option.""" cmd = create_command("somecommand", "This command does that.") command_groups = [CommandGroup("group", [cmd])] dispatcher = Dispatcher(command_groups) dispatcher.pre_parse_args(["somecommand", "--whatever"]) help_builder.init("testapp", "general summary", command_groups) with pytest.raises(ArgumentParsingError) as cm: dispatcher.load_command("config") expected = textwrap.dedent("""\ Usage: testapp [options] command [args]... Try 'testapp somecommand -h' for help. Error: unrecognized arguments: --whatever """) error = cm.value assert str(error) == expected
def get_generated_help(groups): """Helper to use the dispatcher to make the custom arg parser to generate special help.""" dispatcher = Dispatcher([], groups) with patch.object(argparse.ArgumentParser, 'format_help', str): generated_help = dispatcher.main_parser.format_help() return generated_help
def test_dispatcher_pre_parsing(): """Parses and return global arguments.""" groups = [CommandGroup("title", [create_command("somecommand")])] dispatcher = Dispatcher(groups) global_args = dispatcher.pre_parse_args(["-q", "somecommand"]) assert global_args == {"help": False, "verbose": False, "quiet": True, "trace": False}