diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_bashcompletion.py | 257 | ||||
-rw-r--r-- | tests/test_completion.py | 28 |
2 files changed, 27 insertions, 258 deletions
diff --git a/tests/test_bashcompletion.py b/tests/test_bashcompletion.py deleted file mode 100644 index b99c3fea..00000000 --- a/tests/test_bashcompletion.py +++ /dev/null @@ -1,257 +0,0 @@ -# coding=utf-8 -# flake8: noqa E302 -""" -Unit/functional testing for argparse completer in cmd2 - -Copyright 2018 Eric Lin <anselor@gmail.com> -Released under MIT license, see LICENSE file -""" -import os -import pytest -import shlex -import sys -from typing import List - -from cmd2.argparse_completer import ACArgumentParser, AutoCompleter - - -try: - from cmd2.argcomplete_bridge import CompletionFinder, tokens_for_completion - skip_no_argcomplete = False - skip_reason = '' -except ImportError: - # Don't test if argcomplete isn't present (likely on Windows) - skip_no_argcomplete = True - skip_reason = "argcomplete isn't installed\n" - -skip_travis = "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true" -if skip_travis: - skip_reason += 'These tests cannot run on TRAVIS\n' - -skip_windows = sys.platform.startswith('win') -if skip_windows: - skip_reason = 'argcomplete doesn\'t support Windows' - -skip = skip_no_argcomplete or skip_travis or skip_windows - -skip_mac = sys.platform.startswith('dar') - - -actors = ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', 'Alec Guinness', 'Peter Mayhew', - 'Anthony Daniels', 'Adam Driver', 'Daisy Ridley', 'John Boyega', 'Oscar Isaac', - 'Lupita Nyong\'o', 'Andy Serkis', 'Liam Neeson', 'Ewan McGregor', 'Natalie Portman', - 'Jake Lloyd', 'Hayden Christensen', 'Christopher Lee'] - - -def query_actors() -> List[str]: - """Simulating a function that queries and returns a completion values""" - return actors - - -@pytest.fixture -def parser1(): - """creates a argparse object to test completion against""" - ratings_types = ['G', 'PG', 'PG-13', 'R', 'NC-17'] - - def _do_media_movies(self, args) -> None: - if not args.command: - self.do_help('media movies') - else: - print('media movies ' + str(args.__dict__)) - - def _do_media_shows(self, args) -> None: - if not args.command: - self.do_help('media shows') - - if not args.command: - self.do_help('media shows') - else: - print('media shows ' + str(args.__dict__)) - - media_parser = ACArgumentParser(prog='media') - - media_types_subparsers = media_parser.add_subparsers(title='Media Types', dest='type') - - movies_parser = media_types_subparsers.add_parser('movies') - movies_parser.set_defaults(func=_do_media_movies) - - movies_commands_subparsers = movies_parser.add_subparsers(title='Commands', dest='command') - - movies_list_parser = movies_commands_subparsers.add_parser('list') - - movies_list_parser.add_argument('-t', '--title', help='Title Filter') - movies_list_parser.add_argument('-r', '--rating', help='Rating Filter', nargs='+', - choices=ratings_types) - movies_list_parser.add_argument('-d', '--director', help='Director Filter') - movies_list_parser.add_argument('-a', '--actor', help='Actor Filter', action='append') - - movies_add_parser = movies_commands_subparsers.add_parser('add') - movies_add_parser.add_argument('title', help='Movie Title') - movies_add_parser.add_argument('rating', help='Movie Rating', choices=ratings_types) - movies_add_parser.add_argument('-d', '--director', help='Director', nargs=(1, 2), required=True) - movies_add_parser.add_argument('actor', help='Actors', nargs='*') - - movies_commands_subparsers.add_parser('delete') - - shows_parser = media_types_subparsers.add_parser('shows') - shows_parser.set_defaults(func=_do_media_shows) - - shows_commands_subparsers = shows_parser.add_subparsers(title='Commands', dest='command') - - shows_commands_subparsers.add_parser('list') - - return media_parser - - -# noinspection PyShadowingNames -@pytest.mark.skipif(skip_no_argcomplete or skip_windows, reason=skip_reason) -def test_bash_nocomplete(parser1): - completer = CompletionFinder() - result = completer(parser1, AutoCompleter(parser1)) - assert result is None - - -# save the real os.fdopen -os_fdopen = os.fdopen - - -def my_fdopen(fd, mode, *args): - """mock fdopen that redirects 8 and 9 from argcomplete to stdin/stdout for testing""" - if fd > 7: - return os_fdopen(fd - 7, mode, *args) - return os_fdopen(fd, mode) - - -# noinspection PyShadowingNames -@pytest.mark.skipif(skip_no_argcomplete or skip_windows, reason=skip_reason) -def test_invalid_ifs(parser1, mocker): - completer = CompletionFinder() - - mocker.patch.dict(os.environ, {'_ARGCOMPLETE': '1', - '_ARGCOMPLETE_IFS': '\013\013'}) - - mocker.patch.object(os, 'fdopen', my_fdopen) - - with pytest.raises(SystemExit): - completer(parser1, AutoCompleter(parser1), exit_method=sys.exit) - - -# noinspection PyShadowingNames -@pytest.mark.skipif(skip or skip_mac, reason=skip_reason) -@pytest.mark.parametrize('comp_line, exp_out, exp_err', [ - ('media ', 'movies\013shows', ''), - ('media mo', 'movies', ''), - ('media movies list -a "J', '"John Boyega"\013"Jake Lloyd"', ''), - ('media movies list ', '', ''), - ('media movies add ', '\013\013 ', ''' -Hint: - TITLE Movie Title'''), -]) -def test_commands(parser1, capfd, mock, comp_line, exp_out, exp_err): - mock.patch.dict(os.environ, {'_ARGCOMPLETE': '1', - '_ARGCOMPLETE_IFS': '\013', - 'COMP_TYPE': '63', - 'COMP_LINE': comp_line, - 'COMP_POINT': str(len(comp_line))}) - - mock.patch.object(os, 'fdopen', my_fdopen) - - with pytest.raises(SystemExit): - completer = CompletionFinder() - - choices = {'actor': query_actors, # function - } - autocompleter = AutoCompleter(parser1, arg_choices=choices) - completer(parser1, autocompleter, exit_method=sys.exit) - - out, err = capfd.readouterr() - assert out == exp_out - assert err == exp_err - - -def fdopen_fail_8(fd, mode, *args): - """mock fdopen that forces failure if fd == 8""" - if fd == 8: - raise IOError() - return my_fdopen(fd, mode, *args) - - -# noinspection PyShadowingNames -@pytest.mark.skipif(skip_no_argcomplete or skip_windows, reason=skip_reason) -def test_fail_alt_stdout(parser1, mocker): - completer = CompletionFinder() - - comp_line = 'media movies list ' - mocker.patch.dict(os.environ, {'_ARGCOMPLETE': '1', - '_ARGCOMPLETE_IFS': '\013', - 'COMP_TYPE': '63', - 'COMP_LINE': comp_line, - 'COMP_POINT': str(len(comp_line))}) - mocker.patch.object(os, 'fdopen', fdopen_fail_8) - - try: - choices = {'actor': query_actors, # function - } - autocompleter = AutoCompleter(parser1, arg_choices=choices) - completer(parser1, autocompleter, exit_method=sys.exit) - except SystemExit as err: - assert err.code == 1 - - -def fdopen_fail_9(fd, mode, *args): - """mock fdopen that forces failure if fd == 9""" - if fd == 9: - raise IOError() - return my_fdopen(fd, mode, *args) - - -# noinspection PyShadowingNames -@pytest.mark.skipif(skip or skip_mac, reason=skip_reason) -def test_fail_alt_stderr(parser1, capfd, mock): - completer = CompletionFinder() - - comp_line = 'media movies add ' - exp_out = '\013\013 ' - exp_err = ''' -Hint: - TITLE Movie Title''' - - mock.patch.dict(os.environ, {'_ARGCOMPLETE': '1', - '_ARGCOMPLETE_IFS': '\013', - 'COMP_TYPE': '63', - 'COMP_LINE': comp_line, - 'COMP_POINT': str(len(comp_line))}) - mock.patch.object(os, 'fdopen', fdopen_fail_9) - - with pytest.raises(SystemExit): - choices = {'actor': query_actors, # function - } - autocompleter = AutoCompleter(parser1, arg_choices=choices) - completer(parser1, autocompleter, exit_method=sys.exit) - - out, err = capfd.readouterr() - assert out == exp_out - assert err == exp_err - -@pytest.mark.skipif(skip_no_argcomplete, reason=skip_reason) -def test_argcomplete_tokens_for_completion_simple(): - line = 'this is "a test"' - endidx = len(line) - - tokens, raw_tokens, begin_idx, end_idx = tokens_for_completion(line, endidx) - assert tokens == shlex.split(line) - assert raw_tokens == ['this', 'is', '"a test"'] - assert begin_idx == line.rfind("is ") + len("is ") - assert end_idx == end_idx - -@pytest.mark.skipif(skip_no_argcomplete, reason=skip_reason) -def test_argcomplete_tokens_for_completion_unclosed_quotee_exception(): - line = 'this is "a test' - endidx = len(line) - - tokens, raw_tokens, begin_idx, end_idx = tokens_for_completion(line, endidx) - - assert tokens == ['this', 'is', 'a test'] - assert raw_tokens == ['this', 'is', '"a test'] - assert begin_idx == line.rfind("is ") + len("is ") + 1 - assert end_idx == end_idx diff --git a/tests/test_completion.py b/tests/test_completion.py index 2a418cd6..da7fae65 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -70,6 +70,13 @@ class CompletionsExample(cmd2.Cmd): def complete_test_delimited(self, text, line, begidx, endidx): return self.delimiter_complete(text, line, begidx, endidx, delimited_strs, '/') + def do_test_sort_key(self, args): + pass + + def complete_test_sort_key(self, text, line, begidx, endidx): + num_strs = ['2', '11', '1'] + return self.basic_complete(text, line, begidx, endidx, num_strs) + @pytest.fixture def cmd2_app(): @@ -129,7 +136,26 @@ def test_complete_macro(base_app, request): expected = [text + 'cript.py', text + 'cript.txt', text + 'cripts' + os.path.sep] first_match = complete_tester(text, line, begidx, endidx, base_app) - assert first_match is not None and base_app.completion_matches + assert first_match is not None and base_app.completion_matches == expected + + +def test_matches_sort_key(cmd2_app): + text = '' + line = 'test_sort_key {}'.format(text) + endidx = len(line) + begidx = endidx - len(text) + + # First do alphabetical sorting + cmd2_app.matches_sort_key = cmd2.cmd2.ALPHABETICAL_SORT_KEY + expected = ['1', '11', '2'] + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and cmd2_app.completion_matches == expected + + # Now switch to natural sorting + cmd2_app.matches_sort_key = cmd2.cmd2.NATURAL_SORT_KEY + expected = ['1', '2', '11'] + first_match = complete_tester(text, line, begidx, endidx, cmd2_app) + assert first_match is not None and cmd2_app.completion_matches == expected def test_cmd2_command_completion_multiple(cmd2_app): |