def test_dispatcher_commands_are_not_loaded_if_not_needed(): class MyCommand1(BaseCommand): """Expected to be executed.""" name = "command1" help_msg = "some help" _executed = [] def run(self, parsed_args): self._executed.append(parsed_args) class MyCommand2(BaseCommand): """Expected to not be instantiated, or parse args, or run.""" name = "command2" help_msg = "some help" def __init__(self, *args): raise AssertionError def fill_parser(self, parser): raise AssertionError def run(self, parsed_args): raise AssertionError groups = [CommandGroup("title", [MyCommand1, MyCommand2])] dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["command1"]) dispatcher.load_command("config") dispatcher.run() assert isinstance(MyCommand1._executed[0], argparse.Namespace)
def test_tool_exec_command_dash_help_missing_params(help_option): """Execute a command (which needs params) asking for help.""" def fill_parser(self, parser): parser.add_argument("mandatory") 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(["somecommand", help_option]) # 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", "mandatory", ]
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_generic_setup_trace(options): """Generic parameter handling for trace log setup, directly or after the command.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] emit.set_mode(EmitterMode.NORMAL) # this is how `main` will init the Emitter dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(options) assert emit.get_mode() == EmitterMode.TRACE
def test_dispatcher_generic_setup_mutually_exclusive(options): """Disallow mutually exclusive generic options.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] dispatcher = Dispatcher(groups) with pytest.raises(ArgumentParsingError) as err: dispatcher.pre_parse_args(options) assert str(err.value) == "The 'verbose', 'trace' and 'quiet' options are mutually exclusive."
def test_dispatcher_generic_setup_default(): """Generic parameter handling for default values.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] emit.set_mode(EmitterMode.NORMAL) # this is how `main` will init the Emitter dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["somecommand"]) assert emit.get_mode() == EmitterMode.NORMAL
def test_dispatcher_generic_setup_paramglobal_without_param_simple(options): """Generic parameter handling for a param type global arg without the requested parameter.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] extra = GlobalArgument("globalparam", "option", "-g", "--globalparam", "Test global param.") dispatcher = Dispatcher(groups, [extra]) with pytest.raises(ArgumentParsingError) as err: dispatcher.pre_parse_args(options) assert str(err.value) == "The 'globalparam' option expects one argument."
def test_dispatcher_command_loading(): """Parses and return global arguments.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["somecommand"]) command = dispatcher.load_command("test-config") assert isinstance(command, cmd) assert command.config == "test-config"
def test_dispatcher_generic_setup_paramglobal_without_param_confusing(options): """Generic parameter handling for a param type global arg confusing the command as the arg.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] extra = GlobalArgument("globalparam", "option", "-g", "--globalparam", "Test global param.") dispatcher = Dispatcher(groups, [extra]) with patch("charmcraft.helptexts.HelpBuilder.get_full_help") as mock_helper: mock_helper.return_value = "help text" with pytest.raises(ArgumentParsingError) as err: dispatcher.pre_parse_args(options) # generic usage message because "no command" (as 'somecommand' was consumed by --globalparam) assert str(err.value) == "help text"
def test_tool_exec_help_on_too_many_things(sysargv, help_builder): """Trying to get help on too many items.""" help_builder.init("testapp", "general summary", []) dispatcher = Dispatcher([]) with pytest.raises(ArgumentParsingError) as cm: dispatcher.pre_parse_args(sysargv) expected = textwrap.dedent("""\ Usage: testapp [options] command [args]... Try 'testapp -h' for help. Error: Too many parameters when requesting help; pass a command, '--all', or leave it empty """) error = cm.value assert str(error) == expected
def test_tool_exec_help_on_command_incorrect(sysargv, help_builder): """Execute a command that doesn't exist.""" help_builder.init("testapp", "general summary", []) dispatcher = Dispatcher([]) with pytest.raises(ArgumentParsingError) as cm: dispatcher.pre_parse_args(sysargv) expected = textwrap.dedent("""\ Usage: testapp [options] command [args]... Try 'testapp -h' for help. Error: command 'wrongcommand' not found to provide help for """) error = cm.value assert str(error) == expected
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_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_tool_exec_help_command_on_command_wrong(): """Execute charmcraft asking for help on a command which does not exist.""" command_groups = [CommandGroup("group", [])] dispatcher = Dispatcher(command_groups) with patch("charmcraft.helptexts.HelpBuilder.get_usage_message") as mock: mock.return_value = "test help" with pytest.raises(ArgumentParsingError) as cm: dispatcher.pre_parse_args(["help", "wrongcommand"]) error = cm.value # check the given information to the help text builder assert mock.call_args[0] == ( "command 'wrongcommand' not found to provide help for", ) # check the result of the help builder is what is shown assert str(error) == "test help"
def test_dispatcher_generic_setup_paramglobal_with_param(options): """Generic parameter handling for a param type global arg, directly or after the cmd.""" cmd = create_command("somecommand") groups = [CommandGroup("title", [cmd])] extra = GlobalArgument("globalparam", "option", "-g", "--globalparam", "Test global param.") dispatcher = Dispatcher(groups, [extra]) global_args = dispatcher.pre_parse_args(options) assert global_args["globalparam"] == "foobar"
def test_tool_exec_full_help(sysargv): """Execute charmcraft explicitly asking for help.""" dispatcher = Dispatcher([]) with patch("charmcraft.helptexts.HelpBuilder.get_full_help") as mock: mock.return_value = "test help" with pytest.raises(ProvideHelpException) as cm: dispatcher.pre_parse_args(sysargv) # 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 sorted(x[0] for x in args[0]) == [ "-h, --help", "-q, --quiet", "-t, --trace", "-v, --verbose", ]
def test_tool_exec_no_arguments_help(): """Execute charmcraft without any option at all.""" dispatcher = Dispatcher([]) with patch("charmcraft.helptexts.HelpBuilder.get_full_help") as mock: mock.return_value = "test help" with pytest.raises(ArgumentParsingError) as cm: dispatcher.pre_parse_args([]) error = cm.value # 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", ] # check the result of the full help builder is what is shown assert str(error) == "test help"
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 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_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_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_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 = [CommandGroup("title", [MyCommand1, MyCommand2])] dispatcher = Dispatcher(groups) dispatcher.pre_parse_args(["name2"]) dispatcher.load_command("config") dispatcher.run() assert MyCommand1._executed == [] assert isinstance(MyCommand2._executed[0], argparse.Namespace)
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}