diff options
author | Eric Lin <anselor@gmail.com> | 2020-07-21 16:36:31 -0400 |
---|---|---|
committer | anselor <anselor@gmail.com> | 2020-08-04 13:38:08 -0400 |
commit | 372676d479dff8bb07f9361deddd63b17ce7c9d3 (patch) | |
tree | 6e10d6de68c693928c045a57f369c65aac6014e5 | |
parent | 65136e9222ada9485f1313fc7bb3e189f060b8d5 (diff) | |
download | cmd2-git-372676d479dff8bb07f9361deddd63b17ce7c9d3.tar.gz |
Moved commandset tests into an isolated test
-rw-r--r-- | isolated_tests/test_commandset/__init__.py | 3 | ||||
-rw-r--r-- | isolated_tests/test_commandset/conftest.py | 196 | ||||
-rw-r--r-- | isolated_tests/test_commandset/test_commandset.py (renamed from tests/test_commandset.py) | 0 | ||||
-rw-r--r-- | tasks.py | 11 |
4 files changed, 208 insertions, 2 deletions
diff --git a/isolated_tests/test_commandset/__init__.py b/isolated_tests/test_commandset/__init__.py new file mode 100644 index 00000000..037f3866 --- /dev/null +++ b/isolated_tests/test_commandset/__init__.py @@ -0,0 +1,3 @@ +# +# -*- coding: utf-8 -*- +# diff --git a/isolated_tests/test_commandset/conftest.py b/isolated_tests/test_commandset/conftest.py new file mode 100644 index 00000000..5b1a6f05 --- /dev/null +++ b/isolated_tests/test_commandset/conftest.py @@ -0,0 +1,196 @@ +# coding=utf-8 +""" +Cmd2 unit/functional testing +""" +import sys +from contextlib import redirect_stderr, redirect_stdout +from typing import List, Optional, Union +from unittest import mock + +from pytest import fixture + +import cmd2 +from cmd2.utils import StdSim + +# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit) +try: + import gnureadline as readline +except ImportError: + # Try to import readline, but allow failure for convenience in Windows unit testing + # Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows + try: + # noinspection PyUnresolvedReferences + import readline + except ImportError: + pass + + +def verify_help_text(cmd2_app: cmd2.Cmd, + help_output: Union[str, List[str]], + verbose_strings: Optional[List[str]] = None) -> None: + """This function verifies that all expected commands are present in the help text. + + :param cmd2_app: instance of cmd2.Cmd + :param help_output: output of help, either as a string or list of strings + :param verbose_strings: optional list of verbose strings to search for + """ + if isinstance(help_output, str): + help_text = help_output + else: + help_text = ''.join(help_output) + commands = cmd2_app.get_visible_commands() + for command in commands: + assert command in help_text + + if verbose_strings: + for verbose_string in verbose_strings: + assert verbose_string in help_text + + +# Help text for the history command +HELP_HISTORY = """Usage: history [-h] [-r | -e | -o FILE | -t TRANSCRIPT_FILE | -c] [-s] [-x] + [-v] [-a] + [arg] + +View, run, edit, save, or clear previously entered commands + +positional arguments: + arg empty all history items + a one history item by number + a..b, a:b, a:, ..b items by indices (inclusive) + string items containing string + /regex/ items matching regular expression + +optional arguments: + -h, --help show this help message and exit + -r, --run run selected history items + -e, --edit edit and then run selected history items + -o, --output_file FILE + output commands to a script file, implies -s + -t, --transcript TRANSCRIPT_FILE + output commands and results to a transcript file, + implies -s + -c, --clear clear all history + +formatting: + -s, --script output commands in script format, i.e. without command + numbers + -x, --expanded output fully parsed commands with any aliases and + macros expanded, instead of typed commands + -v, --verbose display history and include expanded commands if they + differ from the typed command + -a, --all display all commands, including ones persisted from + previous sessions +""" + +# Output from the shortcuts command with default built-in shortcuts +SHORTCUTS_TXT = """Shortcuts for other commands: +!: shell +?: help +@: run_script +@@: _relative_run_script +""" + +# Output from the show command with default settings +SHOW_TXT = """allow_style: 'Terminal' +debug: False +echo: False +editor: 'vim' +feedback_to_output: False +max_completion_items: 50 +quiet: False +timing: False +""" + +SHOW_LONG = """ +allow_style: 'Terminal' # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never) +debug: False # Show full traceback on exception +echo: False # Echo command issued into output +editor: 'vim' # Program used by 'edit' +feedback_to_output: False # Include nonessentials in '|', '>' results +max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion +quiet: False # Don't print nonessential feedback +timing: False # Report execution times +""" + + +def normalize(block): + """ Normalize a block of text to perform comparison. + + Strip newlines from the very beginning and very end Then split into separate lines and strip trailing whitespace + from each line. + """ + assert isinstance(block, str) + block = block.strip('\n') + return [line.rstrip() for line in block.splitlines()] + + +def run_cmd(app, cmd): + """ Clear out and err StdSim buffers, run the command, and return out and err """ + saved_sysout = sys.stdout + sys.stdout = app.stdout + + # This will be used to capture app.stdout and sys.stdout + copy_cmd_stdout = StdSim(app.stdout) + + # This will be used to capture sys.stderr + copy_stderr = StdSim(sys.stderr) + + try: + app.stdout = copy_cmd_stdout + with redirect_stdout(copy_cmd_stdout): + with redirect_stderr(copy_stderr): + app.onecmd_plus_hooks(cmd) + finally: + app.stdout = copy_cmd_stdout.inner_stream + sys.stdout = saved_sysout + + out = copy_cmd_stdout.getvalue() + err = copy_stderr.getvalue() + return normalize(out), normalize(err) + + +@fixture +def base_app(): + return cmd2.Cmd() + + +# These are odd file names for testing quoting of them +odd_file_names = [ + 'nothingweird', + 'has spaces', + '"is_double_quoted"', + "'is_single_quoted'" +] + + +def complete_tester(text: str, line: str, begidx: int, endidx: int, app) -> Optional[str]: + """ + 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: the string prefix we are attempting to match + :param line: the current input line with leading whitespace removed + :param begidx: the beginning index of the prefix text + :param endidx: 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 also have been sorted by complete() + """ + def get_line(): + return line + + def get_begidx(): + return begidx + + def get_endidx(): + return endidx + + # Run the readline tab completion function with readline mocks in place + 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): + return app.complete(text, 0) diff --git a/tests/test_commandset.py b/isolated_tests/test_commandset/test_commandset.py index eedf51de..eedf51de 100644 --- a/tests/test_commandset.py +++ b/isolated_tests/test_commandset/test_commandset.py @@ -58,8 +58,15 @@ def pytest(context, junit=False, pty=True): command_str = 'pytest --cov=cmd2 --cov-report=term --cov-report=html ' if junit: command_str += ' --junitxml=junit/test-results.xml ' - command_str += ' tests' - context.run(command_str, pty=pty) + tests_cmd = command_str + ' tests' + context.run(tests_cmd, pty=pty) + + command_str += ' --cov-append' + + for root, dirnames, _ in os.walk(TASK_ROOT/'isolated_tests'): + for dir in dirnames: + if dir.startswith('test_'): + context.run(command_str + ' isolated_tests/' + dir) namespace.add_task(pytest) |