diff options
| author | kmvanbrunt <kmvanbrunt@gmail.com> | 2018-03-29 22:52:05 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-03-29 22:52:05 -0400 |
| commit | 852093899d012939bc405f03c4df446e8e024518 (patch) | |
| tree | 8067c5deaca5fd24a64aae65f53cd4a0d931536a /tests | |
| parent | 28c89a543cba26c8cc8fc310b6b7b914d1660445 (diff) | |
| parent | cd0674fa6894b8f9c6cdf866bc838935a9ee76bb (diff) | |
| download | cmd2-git-852093899d012939bc405f03c4df446e8e024518.tar.gz | |
Merge pull request #329 from python-cmd2/new_quoted_completion
Adding tab completion improvements
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_argparse.py | 93 | ||||
| -rw-r--r-- | tests/test_completion.py | 1010 |
2 files changed, 390 insertions, 713 deletions
diff --git a/tests/test_argparse.py b/tests/test_argparse.py index ae3bde98..02c1701b 100644 --- a/tests/test_argparse.py +++ b/tests/test_argparse.py @@ -3,13 +3,10 @@ Cmd2 testing for argument parsing """ import argparse -import functools import pytest -import sys import cmd2 import mock -import six from conftest import run_cmd, StdOut @@ -194,20 +191,9 @@ class SubcommandApp(cmd2.Cmd): self.poutput(args.x * args.y) def base_bar(self, args): - """bar sucommand of base command""" + """bar subcommand of base command""" self.poutput('((%s))' % args.z) - def base_sport(self, args): - """sport subcommand of base command""" - self.poutput('Sport is {}'.format(args.sport)) - - # noinspection PyUnusedLocal - def complete_base_sport(self, text, line, begidx, endidx): - """ Adds tab completion to base sport subcommand """ - sports = ['Football', 'Hockey', 'Soccer', 'Baseball'] - index_dict = {1: sports} - return cmd2.index_based_complete(text, line, begidx, endidx, index_dict) - # create the top-level parser for the base command base_parser = argparse.ArgumentParser(prog='base') base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help') @@ -223,26 +209,17 @@ class SubcommandApp(cmd2.Cmd): parser_bar.add_argument('z', help='string') parser_bar.set_defaults(func=base_bar) - # create the parser for the "sport" subcommand - parser_sport = base_subparsers.add_parser('sport', help='sport help') - parser_sport.add_argument('sport', help='Enter name of a sport') - parser_sport.set_defaults(func=base_sport) - - @cmd2.with_argparser_and_unknown_args(base_parser) - def do_base(self, args, arglist): + @cmd2.with_argparser(base_parser) + def do_base(self, args): """Base command help""" - try: + func = getattr(args, 'func', None) + if func is not None: # Call whatever subcommand function was selected - args.func(self, args) - except AttributeError: - # No subcommand was provided, so as called + func(self, args) + else: + # No subcommand was provided, so call help self.do_help('base') - # functools.partialmethod was added in Python 3.4 - if six.PY3: - # This makes sure correct tab completion functions are called based on the selected subcommand - complete_base = functools.partialmethod(cmd2.Cmd.cmd_with_subs_completer, base='base') - @pytest.fixture def subcommand_app(): app = SubcommandApp() @@ -283,57 +260,3 @@ def test_subcommand_invalid_help(subcommand_app): out = run_cmd(subcommand_app, 'help base baz') assert out[0].startswith('usage: base') assert out[1].startswith("base: error: invalid choice: 'baz'") - -@pytest.mark.skipif(sys.version_info < (3,0), reason="functools.partialmethod requires Python 3.4+") -def test_subcommand_tab_completion(subcommand_app): - # This makes sure the correct completer for the sport subcommand is called - text = 'Foot' - line = 'base sport Foot' - endidx = len(line) - begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = subcommand_app.complete(text, state) - - # It is at end of line, so extra space is present - assert first_match is not None and subcommand_app.completion_matches == ['Football '] - -@pytest.mark.skipif(sys.version_info < (3,0), reason="functools.partialmethod requires Python 3.4+") -def test_subcommand_tab_completion_with_no_completer(subcommand_app): - # This tests what happens when a subcommand has no completer - # In this case, the foo subcommand has no completer defined - text = 'Foot' - line = 'base foo Foot' - endidx = len(line) - begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = subcommand_app.complete(text, state) - - assert first_match is None diff --git a/tests/test_completion.py b/tests/test_completion.py index daeb94bf..e779e44b 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -16,8 +16,6 @@ import cmd2 import mock import pytest -from cmd2 import path_complete, basic_complete, flag_based_complete, index_based_complete - # Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit) try: import gnureadline as readline @@ -36,27 +34,47 @@ def cmd2_app(): c = cmd2.Cmd() return c -@pytest.fixture -def cs_app(): - c = cmd2.Cmd() - return c +# List of strings used with completion functions +food_item_strs = ['Pizza', 'Hamburger', 'Ham', 'Potato'] +sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] +delimited_strs = ['/home/user/file.txt', '/home/user/prog.c', '/home/otheruser/maps'] -def test_cmd2_command_completion_single_end(cmd2_app): - text = 'he' - line = 'he' - endidx = len(line) - begidx = endidx - len(text) - # It is at end of line, so extra space is present - assert cmd2_app.completenames(text, line, begidx, endidx) == ['help '] +# Dictionary used with flag based completion functions +flag_dict = \ + { + # Tab-complete food items after -f and --food flag in command line + '-f': food_item_strs, + '--food': food_item_strs, -def test_complete_command_single_end(cmd2_app): - text = 'he' - line = 'he' - state = 0 - endidx = len(line) - begidx = endidx - len(text) + # Tab-complete sport items after -s and --sport flag in command line + '-s': sport_item_strs, + '--sport': sport_item_strs, + } + +# Dictionary used with index based completion functions +index_dict = \ + { + 1: food_item_strs, # Tab-complete food items at index 1 in command line + 2: sport_item_strs, # Tab-complete sport items at index 2 in command line + } +def complete_tester(text, line, begidx, endidx, app): + """ + This is a convenience function to test cmd2.complete() since + in a unit test environment there is no actual console readline + is monitoring. Therefore we use mock to provide readline data + to complete(). + + :param text: str - the string prefix we are attempting to match + :param line: str - the current input line with leading whitespace removed + :param begidx: int - the beginning index of the prefix text + :param endidx: int - the ending index of the prefix text + :param app: the cmd2 app that will run completions + :return: The first matched string or None if there are no matches + Matches are stored in app.completion_matches + These matches have been sorted by complete() + """ def get_line(): return line @@ -66,169 +84,128 @@ def test_complete_command_single_end(cmd2_app): def get_endidx(): return endidx + first_match = None with mock.patch.object(readline, 'get_line_buffer', get_line): with mock.patch.object(readline, 'get_begidx', get_begidx): with mock.patch.object(readline, 'get_endidx', get_endidx): # Run the readline tab-completion function with readline mocks in place - first_match = cmd2_app.complete(text, state) + first_match = app.complete(text, 0) + + return first_match - assert first_match is not None and cmd2_app.completion_matches == ['help '] -def test_complete_command_invalid_state(cmd2_app): +def test_cmd2_command_completion_single(cmd2_app): text = 'he' - line = 'he' - state = 1 + line = text endidx = len(line) begidx = endidx - len(text) + assert cmd2_app.completenames(text, line, begidx, endidx) == ['help'] - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place get None - first_match = cmd2_app.complete(text, state) +def test_complete_command_single(cmd2_app): + text = 'he' + line = text + endidx = len(line) + begidx = endidx - len(text) - assert first_match is None + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and cmd2_app.completion_matches == ['help '] def test_complete_empty_arg(cmd2_app): text = '' - line = 'help ' - state = 0 + line = 'help {}'.format(text) endidx = len(line) begidx = endidx - len(text) - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = cmd2_app.complete(text, state) + expected = cmd2_app.complete_help(text, line, begidx, endidx) + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) assert first_match is not None and \ - cmd2_app.completion_matches == cmd2_app.complete_help(text, line, begidx, endidx) + cmd2_app.completion_matches == expected def test_complete_bogus_command(cmd2_app): text = '' - line = 'fizbuzz ' - state = 0 + line = 'fizbuzz {}'.format(text) endidx = len(line) begidx = endidx - len(text) - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = cmd2_app.complete(text, state) - + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) assert first_match is None -def test_cmd2_command_completion_is_case_sensitive(cmd2_app): - text = 'HE' - line = 'HE' + +def test_cmd2_command_completion_single(cmd2_app): + text = 'hel' + line = text endidx = len(line) begidx = endidx - len(text) - # It is at end of line, so extra space is present - assert cmd2_app.completenames(text, line, begidx, endidx) == [] - -def test_cmd2_command_completion_single_mid(cmd2_app): - text = 'he' - line = 'he' - begidx = 0 - endidx = 1 - # It is not at end of line, so no extra space assert cmd2_app.completenames(text, line, begidx, endidx) == ['help'] def test_cmd2_command_completion_multiple(cmd2_app): text = 'h' - line = 'h' + line = text endidx = len(line) begidx = endidx - len(text) - # It is not at end of line, so no extra space assert cmd2_app.completenames(text, line, begidx, endidx) == ['help', 'history'] def test_cmd2_command_completion_nomatch(cmd2_app): - text = 'z' - line = 'z' + text = 'fakecommand' + line = text endidx = len(line) begidx = endidx - len(text) assert cmd2_app.completenames(text, line, begidx, endidx) == [] -def test_cmd2_help_completion_single_end(cmd2_app): + +def test_cmd2_help_completion_single(cmd2_app): text = 'he' - line = 'help he' + line = 'help {}'.format(text) endidx = len(line) begidx = endidx - len(text) - # Even though it is at end of line, no extra space is present when tab completing a command name to get help on - assert cmd2_app.complete_help(text, line, begidx, endidx) == ['help'] - -def test_cmd2_help_completion_single_mid(cmd2_app): - text = 'he' - line = 'help he' - begidx = 5 - endidx = 6 assert cmd2_app.complete_help(text, line, begidx, endidx) == ['help'] def test_cmd2_help_completion_multiple(cmd2_app): text = 'h' - line = 'help h' + line = 'help {}'.format(text) endidx = len(line) begidx = endidx - len(text) + assert cmd2_app.complete_help(text, line, begidx, endidx) == ['help', 'history'] def test_cmd2_help_completion_nomatch(cmd2_app): - text = 'z' - line = 'help z' + text = 'fakecommand' + line = 'help {}'.format(text) endidx = len(line) begidx = endidx - len(text) assert cmd2_app.complete_help(text, line, begidx, endidx) == [] -def test_shell_command_completion(cmd2_app): + +def test_shell_command_completion_shortcut(cmd2_app): + # Made sure ! runs a shell command and all matches start with ! since there + # isn't a space between ! and the shell command. Display matches won't + # begin with the !. if sys.platform == "win32": - text = 'calc' - line = 'shell {}'.format(text) - expected = ['calc.exe '] + text = '!calc' + expected = ['!calc.exe '] + expected_display = ['calc.exe'] else: - text = 'egr' - line = 'shell {}'.format(text) - expected = ['egrep '] + text = '!egr' + expected = ['!egrep '] + expected_display = ['egrep'] + line = text endidx = len(line) - begidx = endidx - len(text) - assert cmd2_app.complete_shell(text, line, begidx, endidx) == expected + begidx = 0 + + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and \ + cmd2_app.completion_matches == expected and \ + cmd2_app.display_matches == expected_display def test_shell_command_completion_doesnt_match_wildcards(cmd2_app): if sys.platform == "win32": text = 'c*' - line = 'shell {}'.format(text) else: text = 'e*' - line = 'shell {}'.format(text) + line = 'shell {}'.format(text) endidx = len(line) begidx = endidx - len(text) assert cmd2_app.complete_shell(text, line, begidx, endidx) == [] @@ -236,100 +213,82 @@ def test_shell_command_completion_doesnt_match_wildcards(cmd2_app): def test_shell_command_completion_multiple(cmd2_app): if sys.platform == "win32": text = 'c' - line = 'shell {}'.format(text) expected = 'calc.exe' else: text = 'l' - line = 'shell {}'.format(text) expected = 'ls' + line = 'shell {}'.format(text) endidx = len(line) begidx = endidx - len(text) assert expected in cmd2_app.complete_shell(text, line, begidx, endidx) def test_shell_command_completion_nomatch(cmd2_app): text = 'zzzz' - line = 'shell zzzz' + line = 'shell {}'.format(text) endidx = len(line) begidx = endidx - len(text) assert cmd2_app.complete_shell(text, line, begidx, endidx) == [] def test_shell_command_completion_doesnt_complete_when_just_shell(cmd2_app): text = '' - line = 'shell' - + line = 'shell {}'.format(text) endidx = len(line) - begidx = 0 + begidx = endidx - len(text) assert cmd2_app.complete_shell(text, line, begidx, endidx) == [] def test_shell_command_completion_does_path_completion_when_after_command(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'c' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 'conftest') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert cmd2_app.complete_shell(text, line, begidx, endidx) == ['conftest.py '] + assert cmd2_app.complete_shell(text, line, begidx, endidx) == [text + '.py'] -def test_path_completion_single_end(request): +def test_path_completion_single_end(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'c' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 'conftest') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx) == ['conftest.py '] + assert cmd2_app.path_complete(text, line, begidx, endidx) == [text + '.py'] -def test_path_completion_single_mid(request): +def test_path_completion_multiple(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'tes' - path = os.path.join(test_dir, 'c') - line = 'shell cat {}'.format(path) - - begidx = line.find(text) - endidx = begidx + len(text) - - assert path_complete(text, line, begidx, endidx) == ['tests' + os.path.sep] - -def test_path_completion_multiple(request): - test_dir = os.path.dirname(request.module.__file__) - - text = 's' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 's') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx) == ['script.py', 'script.txt', 'scripts' + os.path.sep] + expected = [text + 'cript.py', text + 'cript.txt', text + 'cripts' + os.path.sep] + assert expected == cmd2_app.path_complete(text, line, begidx, endidx) -def test_path_completion_nomatch(request): +def test_path_completion_nomatch(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'z' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 'fakepath') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx) == [] + assert cmd2_app.path_complete(text, line, begidx, endidx) == [] def test_default_to_shell_completion(cmd2_app, request): cmd2_app.default_to_shell = True test_dir = os.path.dirname(request.module.__file__) - text = 'c' - path = os.path.join(test_dir, text) + text = os.path.join(test_dir, 'conftest') if sys.platform == "win32": command = 'calc.exe' @@ -337,329 +296,310 @@ def test_default_to_shell_completion(cmd2_app, request): command = 'egrep' # Make sure the command is on the testing system - assert command in cmd2.Cmd._get_exes_in_path(command) - line = '{} {}'.format(command, path) + assert command in cmd2_app.get_exes_in_path(command) + line = '{} {}'.format(command, text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - def get_begidx(): - return begidx + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and cmd2_app.completion_matches == [text + '.py '] - def get_endidx(): - return endidx - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = cmd2_app.complete(text, state) - - assert first_match is not None and cmd2_app.completion_matches == ['conftest.py '] - - -def test_path_completion_cwd(): - # Run path complete with no path and no search text +def test_path_completion_cwd(cmd2_app): + # Run path complete with no search text text = '' line = 'shell ls {}'.format(text) endidx = len(line) begidx = endidx - len(text) - completions_empty = path_complete(text, line, begidx, endidx) + completions_no_text = cmd2_app.path_complete(text, line, begidx, endidx) # Run path complete with path set to the CWD - cwd = os.getcwd() + os.path.sep - line = 'shell ls {}'.format(cwd) + text = os.getcwd() + os.path.sep + line = 'shell ls {}'.format(text) endidx = len(line) begidx = endidx - len(text) - completions_cwd = path_complete(text, line, begidx, endidx) - # Verify that the results are the same in both cases and that there is something there - assert completions_empty == completions_cwd + # We have to strip off the text from the beginning since the matches are entire paths + completions_cwd = [match.replace(text, '', 1) for match in cmd2_app.path_complete(text, line, begidx, endidx)] + + # Verify that the first test gave results for entries in the cwd + assert completions_no_text == completions_cwd assert completions_cwd -def test_path_completion_doesnt_match_wildcards(request): +def test_path_completion_doesnt_match_wildcards(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'c*' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 'c*') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) # Currently path completion doesn't accept wildcards, so will always return empty results - assert path_complete(text, line, begidx, endidx) == [] + assert cmd2_app.path_complete(text, line, begidx, endidx) == [] -def test_path_completion_invalid_syntax(): +def test_path_completion_invalid_syntax(cmd2_app): # Test a missing separator between a ~ and path - text = '' - line = 'shell fake ~Desktop' + text = '~Desktop' + line = 'shell fake {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx) == [] + assert cmd2_app.path_complete(text, line, begidx, endidx) == [] -def test_path_completion_just_tilde(): +def test_path_completion_just_tilde(cmd2_app): # Run path with just a tilde - text = '' - line = 'shell fake ~' + text = '~' + line = 'shell fake {}'.format(text) endidx = len(line) begidx = endidx - len(text) - completions_tilde = path_complete(text, line, begidx, endidx) + completions_tilde = cmd2_app.path_complete(text, line, begidx, endidx) - # Path complete should return a slash - assert completions_tilde == [os.path.sep] + # Path complete should complete the tilde with a slash + assert completions_tilde == [text + os.path.sep] -def test_path_completion_user_expansion(): +def test_path_completion_user_expansion(cmd2_app): # Run path with a tilde and a slash - text = '' if sys.platform.startswith('win'): cmd = 'dir' else: cmd = 'ls' - line = 'shell {} ~{}'.format(cmd, os.path.sep) + # Use a ~ which will be expanded into the user's home directory + text = '~{}'.format(os.path.sep) + line = 'shell {} {}'.format(cmd, text) endidx = len(line) begidx = endidx - len(text) - completions_tilde_slash = path_complete(text, line, begidx, endidx) + completions_tilde_slash = [match.replace(text, '', 1) for match in cmd2_app.path_complete(text, line, + begidx, endidx)] # Run path complete on the user's home directory - user_dir = os.path.expanduser('~') + os.path.sep - line = 'shell {} {}'.format(cmd, user_dir) + text = os.path.expanduser('~') + os.path.sep + line = 'shell {} {}'.format(cmd, text) endidx = len(line) begidx = endidx - len(text) - completions_home = path_complete(text, line, begidx, endidx) + completions_home = [match.replace(text, '', 1) for match in cmd2_app.path_complete(text, line, begidx, endidx)] - # Verify that the results are the same in both cases assert completions_tilde_slash == completions_home -def test_path_completion_directories_only(request): +def test_path_completion_directories_only(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 's' - path = os.path.join(test_dir, text) - line = 'shell cat {}'.format(path) + text = os.path.join(test_dir, 's') + line = 'shell cat {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx, dir_only=True) == ['scripts' + os.path.sep] - -def test_path_completion_syntax_err(request): - test_dir = os.path.dirname(request.module.__file__) + expected = [text + 'cripts' + os.path.sep] - text = 'c' - path = os.path.join(test_dir, text) - line = 'shell cat " {}'.format(path) + assert cmd2_app.path_complete(text, line, begidx, endidx, dir_only=True) == expected +def test_basic_completion_single(cmd2_app): + text = 'Pi' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert path_complete(text, line, begidx, endidx) == [] + assert cmd2_app.basic_complete(text, line, begidx, endidx, food_item_strs) == ['Pizza'] -def test_path_completion_no_tokens(): +def test_basic_completion_multiple(cmd2_app): text = '' - line = 'shell' - endidx = len(line) - begidx = 0 - assert path_complete(text, line, begidx, endidx) == [] - - -# List of strings used with basic, flag, and index based completion functions -food_item_strs = ['Pizza', 'Hamburger', 'Ham', 'Potato'] -sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football'] - -# Dictionary used with flag based completion functions -flag_dict = \ - { - '-f': food_item_strs, # Tab-complete food items after -f flag in command line - '--food': food_item_strs, # Tab-complete food items after --food flag in command line - '-s': sport_item_strs, # Tab-complete sport items after -s flag in command line - '--sport': sport_item_strs, # Tab-complete sport items after --sport flag in command line - '-o': path_complete, # Tab-complete using path_complete function after -o flag in command line - '--other': path_complete, # Tab-complete using path_complete function after --other flag in command line - } - -def test_basic_completion_single_end(): - text = 'Pi' - line = 'list_food -f Pi' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert basic_complete(text, line, begidx, endidx, food_item_strs) == ['Pizza '] - -def test_basic_completion_single_mid(): - text = 'Pi' - line = 'list_food -f Pi' - begidx = len(line) - len(text) - endidx = begidx + 1 - - assert basic_complete(text, line, begidx, endidx, food_item_strs) == ['Pizza'] + assert cmd2_app.basic_complete(text, line, begidx, endidx, food_item_strs) == sorted(food_item_strs) -def test_basic_completion_multiple(): - text = '' - line = 'list_food -f ' +def test_basic_completion_nomatch(cmd2_app): + text = 'q' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert basic_complete(text, line, begidx, endidx, food_item_strs) == sorted(food_item_strs) + assert cmd2_app.basic_complete(text, line, begidx, endidx, food_item_strs) == [] -def test_basic_completion_nomatch(): - text = 'q' - line = 'list_food -f q' +def test_delimiter_completion(cmd2_app): + text = '/home/' + line = 'load {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert basic_complete(text, line, begidx, endidx, food_item_strs) == [] + cmd2_app.delimiter_complete(text, line, begidx, endidx, delimited_strs, '/') + + # Remove duplicates from display_matches and sort it. This is typically done in the display function. + display_set = set(cmd2_app.display_matches) + display_list = list(display_set) + display_list.sort() + assert display_list == ['otheruser', 'user'] -def test_flag_based_completion_single_end(): +def test_flag_based_completion_single(cmd2_app): text = 'Pi' - line = 'list_food -f Pi' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == ['Pizza '] - -def test_flag_based_completion_single_mid(): - text = 'Pi' - line = 'list_food -f Pi' - begidx = len(line) - len(text) - endidx = begidx + 1 - - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == ['Pizza'] + assert cmd2_app.flag_based_complete(text, line, begidx, endidx, flag_dict) == ['Pizza'] -def test_flag_based_completion_multiple(): +def test_flag_based_completion_multiple(cmd2_app): text = '' - line = 'list_food -f ' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == sorted(food_item_strs) + assert cmd2_app.flag_based_complete(text, line, begidx, endidx, flag_dict) == sorted(food_item_strs) -def test_flag_based_completion_nomatch(): +def test_flag_based_completion_nomatch(cmd2_app): text = 'q' - line = 'list_food -f q' + line = 'list_food -f {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == [] + assert cmd2_app.flag_based_complete(text, line, begidx, endidx, flag_dict) == [] -def test_flag_based_default_completer(request): +def test_flag_based_default_completer(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'c' - path = os.path.join(test_dir, text) - line = 'list_food {}'.format(path) + text = os.path.join(test_dir, 'c') + line = 'list_food {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict, path_complete) == ['conftest.py '] + assert cmd2_app.flag_based_complete(text, line, begidx, endidx, + flag_dict, cmd2_app.path_complete) == [text + 'onftest.py'] -def test_flag_based_callable_completer(request): +def test_flag_based_callable_completer(cmd2_app, request): test_dir = os.path.dirname(request.module.__file__) - text = 'c' - path = os.path.join(test_dir, text) - line = 'list_food -o {}'.format(path) + text = os.path.join(test_dir, 'c') + line = 'list_food -o {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict, path_complete) == ['conftest.py '] + flag_dict['-o'] = cmd2_app.path_complete + assert cmd2_app.flag_based_complete(text, line, begidx, endidx, + flag_dict) == [text + 'onftest.py'] -def test_flag_based_completion_syntax_err(): - text = 'Pi' - line = 'list_food -f " Pi' + +def test_index_based_completion_single(cmd2_app): + text = 'Foo' + line = 'command Pizza {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == [] + assert cmd2_app.index_based_complete(text, line, begidx, endidx, index_dict) == ['Football'] -def test_flag_based_completion_no_tokens(): +def test_index_based_completion_multiple(cmd2_app): text = '' - line = 'list_food' + line = 'command Pizza {}'.format(text) endidx = len(line) - begidx = 0 + begidx = endidx - len(text) - assert flag_based_complete(text, line, begidx, endidx, flag_dict) == [] + assert cmd2_app.index_based_complete(text, line, begidx, endidx, index_dict) == sorted(sport_item_strs) +def test_index_based_completion_nomatch(cmd2_app): + text = 'q' + line = 'command {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + assert cmd2_app.index_based_complete(text, line, begidx, endidx, index_dict) == [] -# Dictionary used with index based completion functions -index_dict = \ - { - 1: food_item_strs, # Tab-complete food items at index 1 in command line - 2: sport_item_strs, # Tab-complete sport items at index 2 in command line - 3: path_complete, # Tab-complete using path_complete function at index 3 in command line - } +def test_index_based_default_completer(cmd2_app, request): + test_dir = os.path.dirname(request.module.__file__) + + text = os.path.join(test_dir, 'c') + line = 'command Pizza Bat Computer {}'.format(text) -def test_index_based_completion_single_end(): - text = 'Foo' - line = 'command Pizza Foo' endidx = len(line) begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict) == ['Football '] + assert cmd2_app.index_based_complete(text, line, begidx, endidx, + index_dict, cmd2_app.path_complete) == [text + 'onftest.py'] -def test_index_based_completion_single_mid(): - text = 'Foo' - line = 'command Pizza Foo' - begidx = len(line) - len(text) - endidx = begidx + 1 +def test_index_based_callable_completer(cmd2_app, request): + test_dir = os.path.dirname(request.module.__file__) - assert index_based_complete(text, line, begidx, endidx, index_dict) == ['Football'] + text = os.path.join(test_dir, 'c') + line = 'command Pizza Bat {}'.format(text) -def test_index_based_completion_multiple(): - text = '' - line = 'command Pizza ' endidx = len(line) begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict) == sorted(sport_item_strs) -def test_index_based_completion_nomatch(): - text = 'q' - line = 'command q' + index_dict[3] = cmd2_app.path_complete + assert cmd2_app.index_based_complete(text, line, begidx, endidx, index_dict) == [text + 'onftest.py'] + + +def test_tokens_for_completion_quoted(cmd2_app): + text = 'Pi' + line = 'list_food "{}"'.format(text) endidx = len(line) - begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict) == [] + begidx = endidx -def test_index_based_default_completer(request): - test_dir = os.path.dirname(request.module.__file__) + expected_tokens = ['list_food', 'Pi', ''] + expected_raw_tokens = ['list_food', '"Pi"', ''] - text = 'c' - path = os.path.join(test_dir, text) - line = 'command Pizza Bat Computer {}'.format(path) + tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx) + assert expected_tokens == tokens + assert expected_raw_tokens == raw_tokens +def test_tokens_for_completion_unclosed_quote(cmd2_app): + text = 'Pi' + line = 'list_food "{}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict, path_complete) == ['conftest.py '] + expected_tokens = ['list_food', 'Pi'] + expected_raw_tokens = ['list_food', '"Pi'] -def test_index_based_callable_completer(request): - test_dir = os.path.dirname(request.module.__file__) + tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx) + assert expected_tokens == tokens + assert expected_raw_tokens == raw_tokens + +def test_tokens_for_completion_redirect(cmd2_app): + text = '>>file' + line = 'command | < {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) - text = 'c' - path = os.path.join(test_dir, text) - line = 'command Pizza Bat {}'.format(path) + cmd2_app.allow_redirection = True + expected_tokens = ['command', '|', '<', '>>', 'file'] + expected_raw_tokens = ['command', '|', '<', '>>', 'file'] + tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx) + assert expected_tokens == tokens + assert expected_raw_tokens == raw_tokens + +def test_tokens_for_completion_quoted_redirect(cmd2_app): + text = '>file' + line = 'command "{}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict) == ['conftest.py '] + cmd2_app.allow_redirection = True + expected_tokens = ['command', '>file'] + expected_raw_tokens = ['command', '">file'] -def test_index_based_completion_syntax_err(): - text = 'Foo' - line = 'command "Pizza Foo' + tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx) + assert expected_tokens == tokens + assert expected_raw_tokens == raw_tokens + +def test_tokens_for_completion_redirect_off(cmd2_app): + text = '>file' + line = 'command {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert index_based_complete(text, line, begidx, endidx, index_dict) == [] + cmd2_app.allow_redirection = False + expected_tokens = ['command', '>file'] + expected_raw_tokens = ['command', '>file'] + tokens, raw_tokens = cmd2_app.tokens_for_completion(line, begidx, endidx) + assert expected_tokens == tokens + assert expected_raw_tokens == raw_tokens def test_parseline_command_and_args(cmd2_app): line = 'help history' @@ -691,12 +631,15 @@ def test_parseline_expands_shortcuts(cmd2_app): class SubcommandsExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" + """ + Example cmd2 application where we a base command which has a couple subcommands + and the "sport" subcommand has tab completion enabled. + """ def __init__(self): cmd2.Cmd.__init__(self) - # sub-command functions for the base command + # subcommand functions for the base command def base_foo(self, args): """foo subcommand of base command""" self.poutput(args.x * args.y) @@ -705,21 +648,38 @@ class SubcommandsExample(cmd2.Cmd): """bar subcommand of base command""" self.poutput('((%s))' % args.z) + def base_sport(self, args): + """sport subcommand of base command""" + self.poutput('Sport is {}'.format(args.sport)) + + # noinspection PyUnusedLocal + def complete_base_sport(self, text, line, begidx, endidx): + """ Adds tab completion to base sport subcommand """ + index_dict = {1: sport_item_strs} + return self.index_based_complete(text, line, begidx, endidx, index_dict) + # create the top-level parser for the base command base_parser = argparse.ArgumentParser(prog='base') base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help') - # create the parser for the "foo" sub-command + # create the parser for the "foo" subcommand parser_foo = base_subparsers.add_parser('foo', help='foo help') parser_foo.add_argument('-x', type=int, default=1, help='integer') parser_foo.add_argument('y', type=float, help='float') parser_foo.set_defaults(func=base_foo) - # create the parser for the "bar" sub-command + # create the parser for the "bar" subcommand parser_bar = base_subparsers.add_parser('bar', help='bar help') parser_bar.add_argument('z', help='string') parser_bar.set_defaults(func=base_bar) + # create the parser for the "sport" subcommand + parser_sport = base_subparsers.add_parser('sport', help='sport help') + parser_sport.add_argument('sport', help='Enter name of a sport') + + # Set both a function and tab completer for the "sport" subcommand + parser_sport.set_defaults(func=base_sport, completer=complete_base_sport) + @cmd2.with_argparser(base_parser) def do_base(self, args): """Base command help""" @@ -728,9 +688,12 @@ class SubcommandsExample(cmd2.Cmd): # Call whatever subcommand function was selected func(self, args) else: - # No sub-command was provided, so as called + # No subcommand was provided, so call help self.do_help('base') + # Enable tab completion of base to make sure the subcommands' completers get called. + complete_base = cmd2.Cmd.cmd_with_subs_completer + @pytest.fixture def sc_app(): @@ -740,159 +703,104 @@ def sc_app(): def test_cmd2_subcommand_completion_single_end(sc_app): text = 'f' - line = 'base f' + line = 'base {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sc_app.complete(text, state) + first_match = complete_tester(text, line, begidx, endidx, sc_app) # It is at end of line, so extra space is present assert first_match is not None and sc_app.completion_matches == ['foo '] -def test_cmd2_subcommand_completion_single_mid(sc_app): - text = 'f' - line = 'base fo' - endidx = len(line) - 1 - begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sc_app.complete(text, state) - - assert first_match is not None and sc_app.completion_matches == ['foo'] - def test_cmd2_subcommand_completion_multiple(sc_app): text = '' - line = 'base ' + line = 'base {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sc_app.complete(text, state) - - assert first_match is not None and sc_app.completion_matches == ['bar', 'foo'] + first_match = complete_tester(text, line, begidx, endidx, sc_app) + assert first_match is not None and sc_app.completion_matches == ['bar', 'foo', 'sport'] def test_cmd2_subcommand_completion_nomatch(sc_app): text = 'z' - line = 'base z' + line = 'base {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sc_app.complete(text, state) + first_match = complete_tester(text, line, begidx, endidx, sc_app) assert first_match is None -def test_cmd2_subcommand_completion_after_subcommand(sc_app): - text = 'f' - line = 'base foo f' + +def test_cmd2_help_subcommand_completion_single(sc_app): + text = 'base' + line = 'help {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx + assert sc_app.complete_help(text, line, begidx, endidx) == ['base'] - def get_endidx(): - return endidx +def test_cmd2_help_subcommand_completion_multiple(sc_app): + text = '' + line = 'help base {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sc_app.complete(text, state) + assert sc_app.complete_help(text, line, begidx, endidx) == ['bar', 'foo', 'sport'] - assert first_match is None +def test_cmd2_help_subcommand_completion_nomatch(sc_app): + text = 'z' + line = 'help base {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + assert sc_app.complete_help(text, line, begidx, endidx) == [] -def test_cmd2_help_subcommand_completion_single_end(sc_app): - text = 'base' - line = 'help base' +def test_subcommand_tab_completion(sc_app): + # This makes sure the correct completer for the sport subcommand is called + text = 'Foot' + line = 'base sport {}'.format(text) endidx = len(line) begidx = endidx - len(text) - # Commands with subcommands have a space at the end when the cursor is at the end of the line - assert sc_app.complete_help(text, line, begidx, endidx) == ['base '] + first_match = complete_tester(text, line, begidx, endidx, sc_app) + # It is at end of line, so extra space is present + assert first_match is not None and sc_app.completion_matches == ['Football '] -def test_cmd2_help_subcommand_completion_single_mid(sc_app): - text = 'ba' - line = 'help base' - begidx = 5 - endidx = 6 - assert sc_app.complete_help(text, line, begidx, endidx) == ['base'] +def test_subcommand_tab_completion_with_no_completer(sc_app): + # This tests what happens when a subcommand has no completer + # In this case, the foo subcommand has no completer defined + text = 'Foot' + line = 'base foo {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + first_match = complete_tester(text, line, begidx, endidx, sc_app) + assert first_match is None -def test_cmd2_help_subcommand_completion_multiple(sc_app): - text = '' - line = 'help base ' +def test_subcommand_tab_completion_add_quote(sc_app): + # This makes sure an opening quote is added to the readline line buffer + text = 'Space' + line = 'base sport {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert sc_app.complete_help(text, line, begidx, endidx) == ['bar', 'foo'] + first_match = complete_tester(text, line, begidx, endidx, sc_app) -def test_cmd2_help_subcommand_completion_nomatch(sc_app): - text = 'z' - line = 'help base z' + # No matches are returned when an opening quote is added to the screen + assert first_match is None + assert readline.get_line_buffer() == 'base sport "Space Ball" ' + +def test_subcommand_tab_completion_space_in_text(sc_app): + text = 'B' + line = 'base sport "Space {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert sc_app.complete_help(text, line, begidx, endidx) == [] + first_match = complete_tester(text, line, begidx, endidx, sc_app) + + assert first_match is not None and \ + sc_app.completion_matches == ['Ball" '] and \ + sc_app.display_matches == ['Space Ball'] class SecondLevel(cmd2.Cmd): """To be used as a second level command class. """ @@ -933,233 +841,79 @@ def sb_app(): def test_cmd2_submenu_completion_single_end(sb_app): text = 'f' - line = 'second f' + line = 'second {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) + first_match = complete_tester(text, line, begidx, endidx, sb_app) # It is at end of line, so extra space is present assert first_match is not None and sb_app.completion_matches == ['foo '] -def test_cmd2_submenu_completion_single_mid(sb_app): - text = 'f' - line = 'second fo' - endidx = len(line) - 1 - begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) - - assert first_match is not None and sb_app.completion_matches == ['foo'] - - def test_cmd2_submenu_completion_multiple(sb_app): - text = '' - line = 'second ' + text = 'e' + line = 'second {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - def get_line(): - return line + expected = ['edit', 'eof', 'eos'] + first_match = complete_tester(text, line, begidx, endidx, sb_app) - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) - - assert first_match is not None and sb_app.completion_matches == [ - '_relative_load', - 'alias', - 'edit', - 'eof', - 'eos', - 'foo', - 'help', - 'history', - 'load', - 'py', - 'pyscript', - 'quit', - 'set', - 'shell', - 'shortcuts', - 'unalias' - ] + assert first_match is not None and sb_app.completion_matches == expected def test_cmd2_submenu_completion_nomatch(sb_app): text = 'z' - line = 'second z' + line = 'second {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) + first_match = complete_tester(text, line, begidx, endidx, sb_app) assert first_match is None def test_cmd2_submenu_completion_after_submenu_match(sb_app): text = 'a' - line = 'second foo a' + line = 'second foo {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) - assert first_match is not None and sb_app.completion_matches == ['asd'] + first_match = complete_tester(text, line, begidx, endidx, sb_app) + assert first_match is not None and sb_app.completion_matches == ['asd '] def test_cmd2_submenu_completion_after_submenu_nomatch(sb_app): text = 'b' - line = 'second foo b' + line = 'second foo {}'.format(text) endidx = len(line) begidx = endidx - len(text) - state = 0 - - def get_line(): - return line - - def get_begidx(): - return begidx - - def get_endidx(): - return endidx - - with mock.patch.object(readline, 'get_line_buffer', get_line): - with mock.patch.object(readline, 'get_begidx', get_begidx): - with mock.patch.object(readline, 'get_endidx', get_endidx): - # Run the readline tab-completion function with readline mocks in place - first_match = sb_app.complete(text, state) + first_match = complete_tester(text, line, begidx, endidx, sb_app) assert first_match is None -def test_cmd2_help_submenu_completion_single_mid(sb_app): - text = 'sec' - line = 'help sec' - begidx = 5 - endidx = 8 - assert sb_app.complete_help(text, line, begidx, endidx) == ['second'] - - def test_cmd2_help_submenu_completion_multiple(sb_app): - text = '' - line = 'help second ' + text = 'p' + line = 'help second {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert sb_app.complete_help(text, line, begidx, endidx) == [ - '_relative_load', - 'alias', - 'edit', - 'eof', - 'eos', - 'foo', - 'help', - 'history', - 'load', - 'py', - 'pyscript', - 'quit', - 'set', - 'shell', - 'shortcuts', - 'unalias' - ] + + assert sb_app.complete_help(text, line, begidx, endidx) == ['py', 'pyscript'] def test_cmd2_help_submenu_completion_nomatch(sb_app): - text = 'b' - line = 'help second b' + text = 'fake' + line = 'help second {}'.format(text) endidx = len(line) begidx = endidx - len(text) assert sb_app.complete_help(text, line, begidx, endidx) == [] def test_cmd2_help_submenu_completion_subcommands(sb_app): - text = '' - line = 'help second ' + text = 'p' + line = 'help second {}'.format(text) endidx = len(line) begidx = endidx - len(text) - assert sb_app.complete_help(text, line, begidx, endidx) == [ - '_relative_load', - 'alias', - 'edit', - 'eof', - 'eos', - 'foo', - 'help', - 'history', - 'load', - 'py', - 'pyscript', - 'quit', - 'set', - 'shell', - 'shortcuts', - 'unalias' - ] + + assert sb_app.complete_help(text, line, begidx, endidx) == ['py', 'pyscript'] |
