summaryrefslogtreecommitdiff
path: root/tests/test_cmd2.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_cmd2.py')
-rwxr-xr-xtests/test_cmd2.py351
1 files changed, 290 insertions, 61 deletions
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 2f24f4d7..ae911474 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -40,15 +40,19 @@ def CreateOutsimApp():
c.stdout = utils.StdSim(c.stdout)
return c
+
@pytest.fixture
def outsim_app():
return CreateOutsimApp()
+
def test_version(base_app):
assert cmd2.__version__
+
def test_not_in_main_thread(base_app, capsys):
import threading
+
cli_thread = threading.Thread(name='cli_thread', target=base_app.cmdloop)
cli_thread.start()
@@ -56,15 +60,18 @@ def test_not_in_main_thread(base_app, capsys):
out, err = capsys.readouterr()
assert "cmdloop must be run in the main thread" in err
+
def test_empty_statement(base_app):
out, err = run_cmd(base_app, '')
expected = normalize('')
assert out == expected
+
def test_base_help(base_app):
out, err = run_cmd(base_app, 'help')
verify_help_text(base_app, out)
+
def test_base_help_verbose(base_app):
out, err = run_cmd(base_app, 'help -v')
verify_help_text(base_app, out)
@@ -78,6 +85,7 @@ def test_base_help_verbose(base_app):
verify_help_text(base_app, out)
assert ':param' not in ''.join(out)
+
def test_base_argparse_help(base_app):
# Verify that "set -h" gives the same output as "help set" and that it starts in a way that makes sense
out1, err1 = run_cmd(base_app, 'set -h')
@@ -88,21 +96,25 @@ def test_base_argparse_help(base_app):
assert out1[1] == ''
assert out1[2].startswith('Set a settable parameter')
+
def test_base_invalid_option(base_app):
out, err = run_cmd(base_app, 'set -z')
assert err[0] == 'Usage: set [-h] [-v] [param] [value]'
assert 'Error: unrecognized arguments: -z' in err[1]
+
def test_base_shortcuts(base_app):
out, err = run_cmd(base_app, 'shortcuts')
expected = normalize(SHORTCUTS_TXT)
assert out == expected
+
def test_command_starts_with_shortcut():
with pytest.raises(ValueError) as excinfo:
app = cmd2.Cmd(shortcuts={'help': 'fake'})
assert "Invalid command name 'help'" in str(excinfo.value)
+
def test_base_show(base_app):
# force editor to be 'vim' so test is repeatable across platforms
base_app.editor = 'vim'
@@ -121,30 +133,37 @@ def test_base_show_long(base_app):
def test_set(base_app):
out, err = run_cmd(base_app, 'set quiet True')
- expected = normalize("""
+ expected = normalize(
+ """
quiet - was: False
now: True
-""")
+"""
+ )
assert out == expected
out, err = run_cmd(base_app, 'set quiet')
assert out == ['quiet: True']
+
def test_set_val_empty(base_app):
base_app.editor = "fake"
out, err = run_cmd(base_app, 'set editor ""')
assert base_app.editor == ''
+
def test_set_val_is_flag(base_app):
base_app.editor = "fake"
out, err = run_cmd(base_app, 'set editor "-h"')
assert base_app.editor == '-h'
+
def test_set_not_supported(base_app):
out, err = run_cmd(base_app, 'set qqq True')
- expected = normalize("""
+ expected = normalize(
+ """
Parameter 'qqq' not supported (type 'set' for list of parameters).
-""")
+"""
+ )
assert err == expected
@@ -155,15 +174,18 @@ def test_set_no_settables(base_app):
assert err == expected
-@pytest.mark.parametrize('new_val, is_valid, expected', [
- (ansi.STYLE_NEVER, True, ansi.STYLE_NEVER),
- ('neVeR', True, ansi.STYLE_NEVER),
- (ansi.STYLE_TERMINAL, True, ansi.STYLE_TERMINAL),
- ('TeRMInal', True, ansi.STYLE_TERMINAL),
- (ansi.STYLE_ALWAYS, True, ansi.STYLE_ALWAYS),
- ('AlWaYs', True, ansi.STYLE_ALWAYS),
- ('invalid', False, ansi.STYLE_TERMINAL),
-])
+@pytest.mark.parametrize(
+ 'new_val, is_valid, expected',
+ [
+ (ansi.STYLE_NEVER, True, ansi.STYLE_NEVER),
+ ('neVeR', True, ansi.STYLE_NEVER),
+ (ansi.STYLE_TERMINAL, True, ansi.STYLE_TERMINAL),
+ ('TeRMInal', True, ansi.STYLE_TERMINAL),
+ (ansi.STYLE_ALWAYS, True, ansi.STYLE_ALWAYS),
+ ('AlWaYs', True, ansi.STYLE_ALWAYS),
+ ('invalid', False, ansi.STYLE_TERMINAL),
+ ],
+)
def test_set_allow_style(base_app, new_val, is_valid, expected):
# Initialize allow_style for this test
ansi.allow_style = ansi.STYLE_TERMINAL
@@ -190,18 +212,22 @@ class OnChangeHookApp(cmd2.Cmd):
"""Runs when quiet is changed via set command"""
self.poutput("You changed " + name)
+
@pytest.fixture
def onchange_app():
app = OnChangeHookApp()
return app
+
def test_set_onchange_hook(onchange_app):
out, err = run_cmd(onchange_app, 'set quiet True')
- expected = normalize("""
+ expected = normalize(
+ """
quiet - was: False
now: True
You changed quiet
-""")
+"""
+ )
assert out == expected
@@ -212,6 +238,7 @@ def test_base_shell(base_app, monkeypatch):
assert out == []
assert m.called
+
def test_shell_last_result(base_app):
base_app.last_result = None
run_cmd(base_app, 'shell fake')
@@ -220,11 +247,7 @@ def test_shell_last_result(base_app):
def test_shell_manual_call(base_app):
# Verifies crash from Issue #986 doesn't happen
- cmds = [
- 'echo "hi"',
- 'echo "there"',
- 'echo "cmd2!"'
- ]
+ cmds = ['echo "hi"', 'echo "there"', 'echo "cmd2!"']
cmd = ';'.join(cmds)
base_app.do_shell(cmd)
@@ -299,31 +322,37 @@ def test_run_script(base_app, request):
assert script_out == manual_out
assert script_err == manual_err
+
def test_run_script_with_empty_args(base_app):
out, err = run_cmd(base_app, 'run_script')
assert "the following arguments are required" in err[1]
+
def test_run_script_with_nonexistent_file(base_app, capsys):
out, err = run_cmd(base_app, 'run_script does_not_exist.txt')
assert "does not exist" in err[0]
+
def test_run_script_with_directory(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
out, err = run_cmd(base_app, 'run_script {}'.format(test_dir))
assert "is not a file" in err[0]
+
def test_run_script_with_empty_file(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'scripts', 'empty.txt')
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
assert not out and not err
+
def test_run_script_with_binary_file(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'scripts', 'binary.bin')
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
assert "is not an ASCII or UTF-8 encoded text file" in err[0]
+
def test_run_script_with_python_file(base_app, request):
m = mock.MagicMock(name='input', return_value='2')
builtins.input = m
@@ -333,6 +362,7 @@ def test_run_script_with_python_file(base_app, request):
out, err = run_cmd(base_app, 'run_script {}'.format(filename))
assert "appears to be a Python file" in err[0]
+
def test_run_script_with_utf8_file(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'scripts', 'utf8.txt')
@@ -360,6 +390,7 @@ def test_run_script_with_utf8_file(base_app, request):
assert script_out == manual_out
assert script_err == manual_err
+
def test_run_script_nested_run_scripts(base_app, request):
# Verify that running a script with nested run_script commands works correctly,
# and runs the nested script commands in the correct order.
@@ -371,43 +402,48 @@ def test_run_script_nested_run_scripts(base_app, request):
run_cmd(base_app, initial_run)
# Check that the right commands were executed.
- expected = """
+ expected = (
+ """
%s
_relative_run_script precmds.txt
set allow_style Always
help
shortcuts
_relative_run_script postcmds.txt
-set allow_style Never""" % initial_run
+set allow_style Never"""
+ % initial_run
+ )
out, err = run_cmd(base_app, 'history -s')
assert out == normalize(expected)
+
def test_runcmds_plus_hooks(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
prefilepath = os.path.join(test_dir, 'scripts', 'precmds.txt')
postfilepath = os.path.join(test_dir, 'scripts', 'postcmds.txt')
- base_app.runcmds_plus_hooks(['run_script ' + prefilepath,
- 'help',
- 'shortcuts',
- 'run_script ' + postfilepath])
+ base_app.runcmds_plus_hooks(['run_script ' + prefilepath, 'help', 'shortcuts', 'run_script ' + postfilepath])
expected = """
-run_script %s
+run_script {}
set allow_style Always
help
shortcuts
-run_script %s
-set allow_style Never""" % (prefilepath, postfilepath)
+run_script {}
+set allow_style Never""".format(
+ prefilepath, postfilepath,
+ )
out, err = run_cmd(base_app, 'history -s')
assert out == normalize(expected)
+
def test_runcmds_plus_hooks_ctrl_c(base_app, capsys):
"""Test Ctrl-C while in runcmds_plus_hooks"""
import types
def do_keyboard_interrupt(self, _):
raise KeyboardInterrupt('Interrupting this command')
+
setattr(base_app, 'do_keyboard_interrupt', types.MethodType(do_keyboard_interrupt, base_app))
# Default behavior is to stop command loop on Ctrl-C
@@ -424,6 +460,7 @@ def test_runcmds_plus_hooks_ctrl_c(base_app, capsys):
assert not err
assert len(base_app.history) == 3
+
def test_relative_run_script(base_app, request):
test_dir = os.path.dirname(request.module.__file__)
filename = os.path.join(test_dir, 'script.txt')
@@ -451,6 +488,7 @@ def test_relative_run_script(base_app, request):
assert script_out == manual_out
assert script_err == manual_err
+
@pytest.mark.parametrize('file_name', odd_file_names)
def test_relative_run_script_with_odd_file_names(base_app, file_name, monkeypatch):
"""Test file names with various patterns"""
@@ -461,10 +499,12 @@ def test_relative_run_script_with_odd_file_names(base_app, file_name, monkeypatc
run_cmd(base_app, "_relative_run_script {}".format(utils.quote_string(file_name)))
run_script_mock.assert_called_once_with(utils.quote_string(file_name))
+
def test_relative_run_script_requires_an_argument(base_app):
out, err = run_cmd(base_app, '_relative_run_script')
assert 'Error: the following arguments' in err[1]
+
def test_in_script(request):
class HookApp(cmd2.Cmd):
def __init__(self, *args, **kwargs):
@@ -483,17 +523,20 @@ def test_in_script(request):
assert "WE ARE IN SCRIPT" in out[-1]
+
def test_system_exit_in_command(base_app, capsys):
"""Test raising SystemExit from a command"""
import types
def do_system_exit(self, _):
raise SystemExit
+
setattr(base_app, 'do_system_exit', types.MethodType(do_system_exit, base_app))
stop = base_app.onecmd_plus_hooks('system_exit')
assert stop
+
def test_output_redirection(base_app):
fd, filename = tempfile.mkstemp(prefix='cmd2_test', suffix='.txt')
os.close(fd)
@@ -516,6 +559,7 @@ def test_output_redirection(base_app):
finally:
os.remove(filename)
+
def test_output_redirection_to_nonexistent_directory(base_app):
filename = '~/fakedir/this_does_not_exist.txt'
@@ -525,12 +569,15 @@ def test_output_redirection_to_nonexistent_directory(base_app):
out, err = run_cmd(base_app, 'help >> {}'.format(filename))
assert 'Failed to redirect' in err[0]
+
def test_output_redirection_to_too_long_filename(base_app):
- filename = '~/sdkfhksdjfhkjdshfkjsdhfkjsdhfkjdshfkjdshfkjshdfkhdsfkjhewfuihewiufhweiufhiweufhiuewhiuewhfiuwehfia' \
- 'ewhfiuewhfiuewhfiuewhiuewhfiuewhfiuewfhiuwehewiufhewiuhfiweuhfiuwehfiuewfhiuwehiuewfhiuewhiewuhfiueh' \
- 'fiuwefhewiuhewiufhewiufhewiufhewiufhewiufhewiufhewiufhewiuhewiufhewiufhewiuheiufhiuewheiwufhewiufheu' \
- 'fheiufhieuwhfewiuhfeiufhiuewfhiuewheiwuhfiuewhfiuewhfeiuwfhewiufhiuewhiuewhfeiuwhfiuwehfuiwehfiuehie' \
- 'whfieuwfhieufhiuewhfeiuwfhiuefhueiwhfw'
+ filename = (
+ '~/sdkfhksdjfhkjdshfkjsdhfkjsdhfkjdshfkjdshfkjshdfkhdsfkjhewfuihewiufhweiufhiweufhiuewhiuewhfiuwehfia'
+ 'ewhfiuewhfiuewhfiuewhiuewhfiuewhfiuewfhiuwehewiufhewiuhfiweuhfiuwehfiuewfhiuwehiuewfhiuewhiewuhfiueh'
+ 'fiuwefhewiuhewiufhewiufhewiufhewiufhewiufhewiufhewiufhewiuhewiufhewiufhewiuheiufhiuewheiwufhewiufheu'
+ 'fheiufhieuwhfewiuhfeiufhiuewfhiuewheiwuhfiuewhfiuewhfeiuwfhewiufhiuewhiuewhfeiuwhfiuwehfuiwehfiuehie'
+ 'whfieuwfhieufhiuewhfeiuwfhiuefhueiwhfw'
+ )
out, err = run_cmd(base_app, 'help > {}'.format(filename))
assert 'Failed to redirect' in err[0]
@@ -588,6 +635,7 @@ def test_disallow_redirection(base_app):
# Verify that no file got created
assert not os.path.exists(filename)
+
def test_pipe_to_shell(base_app):
if sys.platform == "win32":
# Windows
@@ -600,6 +648,7 @@ def test_pipe_to_shell(base_app):
out, err = run_cmd(base_app, command)
assert out and not err
+
def test_pipe_to_shell_and_redirect(base_app):
filename = 'out.txt'
if sys.platform == "win32":
@@ -615,14 +664,15 @@ def test_pipe_to_shell_and_redirect(base_app):
assert os.path.exists(filename)
os.remove(filename)
+
def test_pipe_to_shell_error(base_app):
# Try to pipe command output to a shell command that doesn't exist in order to produce an error
out, err = run_cmd(base_app, 'help | foobarbaz.this_does_not_exist')
assert not out
assert "Pipe process exited with code" in err[0]
-@pytest.mark.skipif(not clipboard.can_clip,
- reason="Pyperclip could not find a copy/paste mechanism for your system")
+
+@pytest.mark.skipif(not clipboard.can_clip, reason="Pyperclip could not find a copy/paste mechanism for your system")
def test_send_to_paste_buffer(base_app):
# Test writing to the PasteBuffer/Clipboard
run_cmd(base_app, 'help >')
@@ -639,9 +689,11 @@ def test_send_to_paste_buffer(base_app):
def test_base_timing(base_app):
base_app.feedback_to_output = False
out, err = run_cmd(base_app, 'set timing True')
- expected = normalize("""timing - was: False
+ expected = normalize(
+ """timing - was: False
now: True
-""")
+"""
+ )
assert out == expected
if sys.platform == 'win32':
@@ -656,13 +708,18 @@ def _expected_no_editor_error():
if hasattr(sys, "pypy_translation_info"):
expected_exception = 'EnvironmentError'
- expected_text = normalize("""
+ expected_text = normalize(
+ """
EXCEPTION of type '{}' occurred with message: 'Please use 'set editor' to specify your text editing program of choice.'
To enable full traceback, run the following command: 'set debug true'
-""".format(expected_exception))
+""".format(
+ expected_exception
+ )
+ )
return expected_text
+
def test_base_debug(base_app):
# Purposely set the editor to None
base_app.editor = None
@@ -675,16 +732,19 @@ def test_base_debug(base_app):
# Set debug true
out, err = run_cmd(base_app, 'set debug True')
- expected = normalize("""
+ expected = normalize(
+ """
debug - was: False
now: True
-""")
+"""
+ )
assert out == expected
# Verify that we now see the exception traceback
out, err = run_cmd(base_app, 'edit')
assert err[0].startswith('Traceback (most recent call last):')
+
def test_debug_not_settable(base_app):
# Set debug to False and make it unsettable
base_app.debug = False
@@ -696,10 +756,12 @@ def test_debug_not_settable(base_app):
# Since debug is unsettable, the user will not be given the option to enable a full traceback
assert err == ['Invalid syntax: No closing quotation']
+
def test_remove_settable_keyerror(base_app):
with pytest.raises(KeyError):
base_app.remove_settable('fake')
+
def test_edit_file(base_app, request, monkeypatch):
# Set a fake editor just to make sure we have one. We aren't really going to call it due to the mock
base_app.editor = 'fooedit'
@@ -716,6 +778,7 @@ def test_edit_file(base_app, request, monkeypatch):
# We think we have an editor, so should expect a Popen call
m.assert_called_once()
+
@pytest.mark.parametrize('file_name', odd_file_names)
def test_edit_file_with_odd_file_names(base_app, file_name, monkeypatch):
"""Test editor and file names with various patterns"""
@@ -728,6 +791,7 @@ def test_edit_file_with_odd_file_names(base_app, file_name, monkeypatch):
run_cmd(base_app, "edit {}".format(utils.quote_string(file_name)))
shell_mock.assert_called_once_with('"fooedit" {}'.format(utils.quote_string(file_name)))
+
def test_edit_file_with_spaces(base_app, request, monkeypatch):
# Set a fake editor just to make sure we have one. We aren't really going to call it due to the mock
base_app.editor = 'fooedit'
@@ -744,6 +808,7 @@ def test_edit_file_with_spaces(base_app, request, monkeypatch):
# We think we have an editor, so should expect a Popen call
m.assert_called_once()
+
def test_edit_blank(base_app, monkeypatch):
# Set a fake editor just to make sure we have one. We aren't really going to call it due to the mock
base_app.editor = 'fooedit'
@@ -830,8 +895,8 @@ def test_cmdloop_without_rawinput():
out = app.stdout.getvalue()
assert out == expected
-@pytest.mark.skipif(sys.platform.startswith('win'),
- reason="stty sane only run on Linux/Mac")
+
+@pytest.mark.skipif(sys.platform.startswith('win'), reason="stty sane only run on Linux/Mac")
def test_stty_sane(base_app, monkeypatch):
"""Make sure stty sane is run on Linux/Mac after each command if stdin is a terminal"""
with mock.patch('sys.stdin.isatty', mock.MagicMock(name='isatty', return_value=True)):
@@ -842,6 +907,7 @@ def test_stty_sane(base_app, monkeypatch):
base_app.onecmd_plus_hooks('help')
m.assert_called_once_with(['stty', 'sane'])
+
class HookFailureApp(cmd2.Cmd):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -853,11 +919,13 @@ class HookFailureApp(cmd2.Cmd):
data.stop = True
return data
+
@pytest.fixture
def hook_failure():
app = HookFailureApp()
return app
+
def test_precmd_hook_success(base_app):
out = base_app.onecmd_plus_hooks('help')
assert out is False
@@ -875,12 +943,14 @@ class SayApp(cmd2.Cmd):
def do_say(self, arg):
self.poutput(arg)
+
@pytest.fixture
def say_app():
app = SayApp(allow_cli_args=False)
app.stdout = utils.StdSim(app.stdout)
return app
+
def test_interrupt_quit(say_app):
say_app.quit_on_sigint = True
@@ -898,6 +968,7 @@ def test_interrupt_quit(say_app):
out = say_app.stdout.getvalue()
assert out == 'hello\n'
+
def test_interrupt_noquit(say_app):
say_app.quit_on_sigint = False
@@ -921,6 +992,7 @@ class ShellApp(cmd2.Cmd):
super().__init__(*args, **kwargs)
self.default_to_shell = True
+
def test_default_to_shell(base_app, monkeypatch):
if sys.platform.startswith('win'):
line = 'dir'
@@ -934,14 +1006,17 @@ def test_default_to_shell(base_app, monkeypatch):
assert out == []
assert m.called
+
def test_ansi_prompt_not_esacped(base_app):
from cmd2.rl_utils import rl_make_safe_prompt
+
prompt = '(Cmd) '
assert rl_make_safe_prompt(prompt) == prompt
def test_ansi_prompt_escaped():
from cmd2.rl_utils import rl_make_safe_prompt
+
app = cmd2.Cmd()
color = 'cyan'
prompt = 'InColor'
@@ -963,6 +1038,7 @@ def test_ansi_prompt_escaped():
class HelpApp(cmd2.Cmd):
"""Class for testing custom help_* methods which override docstring help."""
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -996,24 +1072,29 @@ def help_app():
app = HelpApp()
return app
+
def test_custom_command_help(help_app):
out, err = run_cmd(help_app, 'help squat')
expected = normalize('This command does diddly squat...')
assert out == expected
+
def test_custom_help_menu(help_app):
out, err = run_cmd(help_app, 'help')
verify_help_text(help_app, out)
+
def test_help_undocumented(help_app):
out, err = run_cmd(help_app, 'help undoc')
assert err[0].startswith("No help on undoc")
+
def test_help_overridden_method(help_app):
out, err = run_cmd(help_app, 'help edit')
expected = normalize('This overrides the edit command and does nothing.')
assert out == expected
+
def test_help_multiline_docstring(help_app):
out, err = run_cmd(help_app, 'help multiline_docstr')
expected = normalize('This documentation\nis multiple lines\nand there are no\ntabs')
@@ -1022,6 +1103,7 @@ def test_help_multiline_docstring(help_app):
class HelpCategoriesApp(cmd2.Cmd):
"""Class for testing custom help_* methods which override docstring help."""
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -1052,15 +1134,18 @@ class HelpCategoriesApp(cmd2.Cmd):
def do_undoc(self, arg):
pass
+
@pytest.fixture
def helpcat_app():
app = HelpCategoriesApp()
return app
+
def test_help_cat_base(helpcat_app):
out, err = run_cmd(helpcat_app, 'help')
verify_help_text(helpcat_app, out)
+
def test_help_cat_verbose(helpcat_app):
out, err = run_cmd(helpcat_app, 'help --verbose')
verify_help_text(helpcat_app, out)
@@ -1085,8 +1170,9 @@ class SelectApp(cmd2.Cmd):
def do_procrastinate(self, arg):
"""Waste time in your manner of choice."""
# Pass in a list of tuples for selections
- leisure_activity = self.select([('Netflix and chill', 'Netflix'), ('YouTube', 'WebSurfing')],
- 'How would you like to procrastinate? ')
+ leisure_activity = self.select(
+ [('Netflix and chill', 'Netflix'), ('YouTube', 'WebSurfing')], 'How would you like to procrastinate? '
+ )
result = 'Have fun procrasinating with {}!\n'.format(leisure_activity)
self.stdout.write(result)
@@ -1097,11 +1183,13 @@ class SelectApp(cmd2.Cmd):
result = 'Charm us with the {}...\n'.format(instrument)
self.stdout.write(result)
+
@pytest.fixture
def select_app():
app = SelectApp()
return app
+
def test_select_options(select_app, monkeypatch):
# Mock out the read_input call so we don't actually wait for a user's response on stdin
read_input_mock = mock.MagicMock(name='read_input', return_value='2')
@@ -1109,11 +1197,15 @@ def test_select_options(select_app, monkeypatch):
food = 'bacon'
out, err = run_cmd(select_app, "eat {}".format(food))
- expected = normalize("""
+ expected = normalize(
+ """
1. sweet
2. salty
{} with salty sauce, yum!
-""".format(food))
+""".format(
+ food
+ )
+ )
# Make sure our mock was called with the expected arguments
read_input_mock.assert_called_once_with('Sauce? ')
@@ -1121,6 +1213,7 @@ def test_select_options(select_app, monkeypatch):
# And verify the expected output to stdout
assert out == expected
+
def test_select_invalid_option_too_big(select_app, monkeypatch):
# Mock out the input call so we don't actually wait for a user's response on stdin
read_input_mock = mock.MagicMock(name='read_input')
@@ -1131,12 +1224,16 @@ def test_select_invalid_option_too_big(select_app, monkeypatch):
food = 'fish'
out, err = run_cmd(select_app, "eat {}".format(food))
- expected = normalize("""
+ expected = normalize(
+ """
1. sweet
2. salty
'3' isn't a valid choice. Pick a number between 1 and 2:
{} with sweet sauce, yum!
-""".format(food))
+""".format(
+ food
+ )
+ )
# Make sure our mock was called exactly twice with the expected arguments
arg = 'Sauce? '
@@ -1147,6 +1244,7 @@ def test_select_invalid_option_too_big(select_app, monkeypatch):
# And verify the expected output to stdout
assert out == expected
+
def test_select_invalid_option_too_small(select_app, monkeypatch):
# Mock out the input call so we don't actually wait for a user's response on stdin
read_input_mock = mock.MagicMock(name='read_input')
@@ -1157,12 +1255,16 @@ def test_select_invalid_option_too_small(select_app, monkeypatch):
food = 'fish'
out, err = run_cmd(select_app, "eat {}".format(food))
- expected = normalize("""
+ expected = normalize(
+ """
1. sweet
2. salty
'0' isn't a valid choice. Pick a number between 1 and 2:
{} with sweet sauce, yum!
-""".format(food))
+""".format(
+ food
+ )
+ )
# Make sure our mock was called exactly twice with the expected arguments
arg = 'Sauce? '
@@ -1173,17 +1275,22 @@ def test_select_invalid_option_too_small(select_app, monkeypatch):
# And verify the expected output to stdout
assert out == expected
+
def test_select_list_of_strings(select_app, monkeypatch):
# Mock out the input call so we don't actually wait for a user's response on stdin
read_input_mock = mock.MagicMock(name='read_input', return_value='2')
monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
out, err = run_cmd(select_app, "study")
- expected = normalize("""
+ expected = normalize(
+ """
1. math
2. science
Good luck learning {}!
-""".format('science'))
+""".format(
+ 'science'
+ )
+ )
# Make sure our mock was called with the expected arguments
read_input_mock.assert_called_once_with('Subject? ')
@@ -1191,17 +1298,22 @@ Good luck learning {}!
# And verify the expected output to stdout
assert out == expected
+
def test_select_list_of_tuples(select_app, monkeypatch):
# Mock out the input call so we don't actually wait for a user's response on stdin
read_input_mock = mock.MagicMock(name='read_input', return_value='2')
monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
out, err = run_cmd(select_app, "procrastinate")
- expected = normalize("""
+ expected = normalize(
+ """
1. Netflix
2. WebSurfing
Have fun procrasinating with {}!
-""".format('YouTube'))
+""".format(
+ 'YouTube'
+ )
+ )
# Make sure our mock was called with the expected arguments
read_input_mock.assert_called_once_with('How would you like to procrastinate? ')
@@ -1216,11 +1328,15 @@ def test_select_uneven_list_of_tuples(select_app, monkeypatch):
monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
out, err = run_cmd(select_app, "play")
- expected = normalize("""
+ expected = normalize(
+ """
1. Electric Guitar
2. Drums
Charm us with the {}...
-""".format('Drums'))
+""".format(
+ 'Drums'
+ )
+ )
# Make sure our mock was called with the expected arguments
read_input_mock.assert_called_once_with('Instrument? ')
@@ -1228,6 +1344,7 @@ Charm us with the {}...
# And verify the expected output to stdout
assert out == expected
+
def test_select_eof(select_app, monkeypatch):
# Ctrl-D during select causes an EOFError that just reprompts the user
read_input_mock = mock.MagicMock(name='read_input', side_effect=[EOFError, 2])
@@ -1242,6 +1359,7 @@ def test_select_eof(select_app, monkeypatch):
read_input_mock.assert_has_calls(calls)
assert read_input_mock.call_count == 2
+
def test_select_ctrl_c(outsim_app, monkeypatch, capsys):
# Ctrl-C during select prints ^C and raises a KeyboardInterrupt
read_input_mock = mock.MagicMock(name='read_input', side_effect=KeyboardInterrupt)
@@ -1253,9 +1371,11 @@ def test_select_ctrl_c(outsim_app, monkeypatch, capsys):
out = outsim_app.stdout.getvalue()
assert out.rstrip().endswith('^C')
+
class HelpNoDocstringApp(cmd2.Cmd):
greet_parser = argparse.ArgumentParser()
greet_parser.add_argument('-s', '--shout', action="store_true", help="N00B EMULATION MODE")
+
@cmd2.with_argparser(greet_parser, with_unknown_args=True)
def do_greet(self, opts, arg):
arg = ''.join(arg)
@@ -1263,17 +1383,22 @@ class HelpNoDocstringApp(cmd2.Cmd):
arg = arg.upper()
self.stdout.write(arg + '\n')
+
def test_help_with_no_docstring(capsys):
app = HelpNoDocstringApp()
app.onecmd_plus_hooks('greet -h')
out, err = capsys.readouterr()
assert err == ''
- assert out == """usage: greet [-h] [-s]
+ assert (
+ out
+ == """usage: greet [-h] [-s]
optional arguments:
-h, --help show this help message and exit
-s, --shout N00B EMULATION MODE
"""
+ )
+
class MultilineApp(cmd2.Cmd):
def __init__(self, *args, **kwargs):
@@ -1289,15 +1414,18 @@ class MultilineApp(cmd2.Cmd):
arg = arg.upper()
self.stdout.write(arg + '\n')
+
@pytest.fixture
def multiline_app():
app = MultilineApp()
return app
+
def test_multiline_complete_empty_statement_raises_exception(multiline_app):
with pytest.raises(exceptions.EmptyStatement):
multiline_app._complete_statement('')
+
def test_multiline_complete_statement_without_terminator(multiline_app):
# Mock out the input call so we don't actually wait for a user's response
# on stdin when it looks for more input
@@ -1312,6 +1440,7 @@ def test_multiline_complete_statement_without_terminator(multiline_app):
assert statement.command == command
assert statement.multiline_command == command
+
def test_multiline_complete_statement_with_unclosed_quotes(multiline_app):
# Mock out the input call so we don't actually wait for a user's response
# on stdin when it looks for more input
@@ -1325,6 +1454,7 @@ def test_multiline_complete_statement_with_unclosed_quotes(multiline_app):
assert statement.multiline_command == 'orate'
assert statement.terminator == ';'
+
def test_multiline_input_line_to_statement(multiline_app):
# Verify _input_line_to_statement saves the fully entered input line for multiline commands
@@ -1340,6 +1470,7 @@ def test_multiline_input_line_to_statement(multiline_app):
assert statement.command == 'orate'
assert statement.multiline_command == 'orate'
+
def test_clipboard_failure(base_app, capsys):
# Force cmd2 clipboard to be disabled
base_app._can_clip = False
@@ -1369,11 +1500,13 @@ class CommandResultApp(cmd2.Cmd):
def do_negative_no_data(self, arg):
self.last_result = cmd2.CommandResult('', arg)
+
@pytest.fixture
def commandresult_app():
app = CommandResultApp()
return app
+
def test_commandresult_truthy(commandresult_app):
arg = 'foo'
run_cmd(commandresult_app, 'affirmative {}'.format(arg))
@@ -1384,6 +1517,7 @@ def test_commandresult_truthy(commandresult_app):
assert commandresult_app.last_result
assert commandresult_app.last_result == cmd2.CommandResult(arg)
+
def test_commandresult_falsy(commandresult_app):
arg = 'bar'
run_cmd(commandresult_app, 'negative {}'.format(arg))
@@ -1409,6 +1543,7 @@ def test_eof(base_app):
# Only thing to verify is that it returns True
assert base_app.do_eof('')
+
def test_echo(capsys):
app = cmd2.Cmd()
app.echo = True
@@ -1419,6 +1554,7 @@ def test_echo(capsys):
out, err = capsys.readouterr()
assert out.startswith('{}{}\n'.format(app.prompt, commands[0]) + HELP_HISTORY.split()[0])
+
def test_read_input_rawinput_true(capsys, monkeypatch):
prompt_str = 'the_prompt'
input_str = 'some input'
@@ -1450,6 +1586,7 @@ def test_read_input_rawinput_true(capsys, monkeypatch):
assert line == input_str
assert not out
+
def test_read_input_rawinput_false(capsys, monkeypatch):
prompt_str = 'the_prompt'
input_str = 'some input'
@@ -1502,6 +1639,7 @@ def test_read_input_rawinput_false(capsys, monkeypatch):
assert line == 'eof'
assert not out
+
def test_read_command_line_eof(base_app, monkeypatch):
read_input_mock = mock.MagicMock(name='read_input', side_effect=EOFError)
monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
@@ -1509,6 +1647,7 @@ def test_read_command_line_eof(base_app, monkeypatch):
line = base_app._read_command_line("Prompt> ")
assert line == 'eof'
+
def test_poutput_string(outsim_app):
msg = 'This is a test'
outsim_app.poutput(msg)
@@ -1516,6 +1655,7 @@ def test_poutput_string(outsim_app):
expected = msg + '\n'
assert out == expected
+
def test_poutput_zero(outsim_app):
msg = 0
outsim_app.poutput(msg)
@@ -1523,6 +1663,7 @@ def test_poutput_zero(outsim_app):
expected = str(msg) + '\n'
assert out == expected
+
def test_poutput_empty_string(outsim_app):
msg = ''
outsim_app.poutput(msg)
@@ -1530,6 +1671,7 @@ def test_poutput_empty_string(outsim_app):
expected = '\n'
assert out == expected
+
def test_poutput_none(outsim_app):
msg = None
outsim_app.poutput(msg)
@@ -1537,6 +1679,7 @@ def test_poutput_none(outsim_app):
expected = 'None\n'
assert out == expected
+
def test_poutput_ansi_always(outsim_app):
msg = 'Hello World'
ansi.allow_style = ansi.STYLE_ALWAYS
@@ -1547,6 +1690,7 @@ def test_poutput_ansi_always(outsim_app):
assert colored_msg != msg
assert out == expected
+
def test_poutput_ansi_never(outsim_app):
msg = 'Hello World'
ansi.allow_style = ansi.STYLE_NEVER
@@ -1571,6 +1715,7 @@ invalid_command_name = [
'noembedded"quotes',
]
+
def test_get_alias_completion_items(base_app):
run_cmd(base_app, 'alias create fake run_pyscript')
run_cmd(base_app, 'alias create ls !ls -hal')
@@ -1582,6 +1727,7 @@ def test_get_alias_completion_items(base_app):
assert cur_res in base_app.aliases
assert cur_res.description == base_app.aliases[cur_res]
+
def test_get_macro_completion_items(base_app):
run_cmd(base_app, 'macro create foo !echo foo')
run_cmd(base_app, 'macro create bar !echo bar')
@@ -1593,17 +1739,20 @@ def test_get_macro_completion_items(base_app):
assert cur_res in base_app.macros
assert cur_res.description == base_app.macros[cur_res].value
+
def test_get_settable_completion_items(base_app):
results = base_app._get_settable_completion_items()
for cur_res in results:
assert cur_res in base_app.settables
assert cur_res.description == base_app.settables[cur_res].description
+
def test_alias_no_subcommand(base_app):
out, err = run_cmd(base_app, 'alias')
assert "Usage: alias [-h]" in err[0]
assert "Error: the following arguments are required: SUBCOMMAND" in err[1]
+
def test_alias_create(base_app):
# Create the alias
out, err = run_cmd(base_app, 'alias create fake run_pyscript')
@@ -1636,6 +1785,7 @@ def test_alias_create(base_app):
out, err = run_cmd(base_app, 'alias list --with_silent fake')
assert out == normalize('alias create --silent fake set')
+
def test_alias_create_with_quoted_tokens(base_app):
"""Demonstrate that quotes in alias value will be preserved"""
create_command = 'alias create fake help ">" "out file.txt" ";"'
@@ -1648,21 +1798,25 @@ def test_alias_create_with_quoted_tokens(base_app):
out, err = run_cmd(base_app, 'alias list fake')
assert out == normalize(create_command)
+
@pytest.mark.parametrize('alias_name', invalid_command_name)
def test_alias_create_invalid_name(base_app, alias_name, capsys):
out, err = run_cmd(base_app, 'alias create {} help'.format(alias_name))
assert "Invalid alias name" in err[0]
+
def test_alias_create_with_command_name(base_app):
out, err = run_cmd(base_app, 'alias create help stuff')
assert "Alias cannot have the same name as a command" in err[0]
+
def test_alias_create_with_macro_name(base_app):
macro = "my_macro"
run_cmd(base_app, 'macro create {} help'.format(macro))
out, err = run_cmd(base_app, 'alias create {} help'.format(macro))
assert "Alias cannot have the same name as a macro" in err[0]
+
def test_alias_that_resolves_into_comment(base_app):
# Create the alias
out, err = run_cmd(base_app, 'alias create fake ' + constants.COMMENT_CHAR + ' blah blah')
@@ -1673,11 +1827,13 @@ def test_alias_that_resolves_into_comment(base_app):
assert not out
assert not err
+
def test_alias_list_invalid_alias(base_app):
# Look up invalid alias
out, err = run_cmd(base_app, 'alias list invalid')
assert "Alias 'invalid' not found" in err[0]
+
def test_alias_delete(base_app):
# Create an alias
run_cmd(base_app, 'alias create fake run_pyscript')
@@ -1686,18 +1842,22 @@ def test_alias_delete(base_app):
out, err = run_cmd(base_app, 'alias delete fake')
assert out == normalize("Alias 'fake' deleted")
+
def test_alias_delete_all(base_app):
out, err = run_cmd(base_app, 'alias delete --all')
assert out == normalize("All aliases deleted")
+
def test_alias_delete_non_existing(base_app):
out, err = run_cmd(base_app, 'alias delete fake')
assert "Alias 'fake' does not exist" in err[0]
+
def test_alias_delete_no_name(base_app):
out, err = run_cmd(base_app, 'alias delete')
assert "Either --all or alias name(s)" in err[0]
+
def test_multiple_aliases(base_app):
alias1 = 'h1'
alias2 = 'h2'
@@ -1709,11 +1869,13 @@ def test_multiple_aliases(base_app):
out, err = run_cmd(base_app, alias2)
verify_help_text(base_app, out)
+
def test_macro_no_subcommand(base_app):
out, err = run_cmd(base_app, 'macro')
assert "Usage: macro [-h]" in err[0]
assert "Error: the following arguments are required: SUBCOMMAND" in err[1]
+
def test_macro_create(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake run_pyscript')
@@ -1746,6 +1908,7 @@ def test_macro_create(base_app):
out, err = run_cmd(base_app, 'macro list --with_silent fake')
assert out == normalize('macro create --silent fake set')
+
def test_macro_create_with_quoted_tokens(base_app):
"""Demonstrate that quotes in macro value will be preserved"""
create_command = 'macro create fake help ">" "out file.txt" ";"'
@@ -1758,21 +1921,25 @@ def test_macro_create_with_quoted_tokens(base_app):
out, err = run_cmd(base_app, 'macro list fake')
assert out == normalize(create_command)
+
@pytest.mark.parametrize('macro_name', invalid_command_name)
def test_macro_create_invalid_name(base_app, macro_name):
out, err = run_cmd(base_app, 'macro create {} help'.format(macro_name))
assert "Invalid macro name" in err[0]
+
def test_macro_create_with_command_name(base_app):
out, err = run_cmd(base_app, 'macro create help stuff')
assert "Macro cannot have the same name as a command" in err[0]
+
def test_macro_create_with_alias_name(base_app):
macro = "my_macro"
run_cmd(base_app, 'alias create {} help'.format(macro))
out, err = run_cmd(base_app, 'macro create {} help'.format(macro))
assert "Macro cannot have the same name as an alias" in err[0]
+
def test_macro_create_with_args(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake {1} {2}')
@@ -1782,6 +1949,7 @@ def test_macro_create_with_args(base_app):
out, err = run_cmd(base_app, 'fake help -v')
verify_help_text(base_app, out)
+
def test_macro_create_with_escaped_args(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake help {{1}}')
@@ -1791,6 +1959,7 @@ def test_macro_create_with_escaped_args(base_app):
out, err = run_cmd(base_app, 'fake')
assert err[0].startswith('No help on {1}')
+
def test_macro_usage_with_missing_args(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake help {1} {2}')
@@ -1800,6 +1969,7 @@ def test_macro_usage_with_missing_args(base_app):
out, err = run_cmd(base_app, 'fake arg1')
assert "expects at least 2 argument(s)" in err[0]
+
def test_macro_usage_with_exta_args(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake help {1}')
@@ -1809,16 +1979,19 @@ def test_macro_usage_with_exta_args(base_app):
out, err = run_cmd(base_app, 'fake alias create')
assert "Usage: alias create" in out[0]
+
def test_macro_create_with_missing_arg_nums(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake help {1} {3}')
assert "Not all numbers between 1 and 3" in err[0]
+
def test_macro_create_with_invalid_arg_num(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake help {1} {-1} {0}')
assert "Argument numbers must be greater than 0" in err[0]
+
def test_macro_create_with_unicode_numbered_arg(base_app):
# Create the macro expecting 1 argument
out, err = run_cmd(base_app, 'macro create fake help {\N{ARABIC-INDIC DIGIT ONE}}')
@@ -1828,10 +2001,12 @@ def test_macro_create_with_unicode_numbered_arg(base_app):
out, err = run_cmd(base_app, 'fake')
assert "expects at least 1 argument(s)" in err[0]
+
def test_macro_create_with_missing_unicode_arg_nums(base_app):
out, err = run_cmd(base_app, 'macro create fake help {1} {\N{ARABIC-INDIC DIGIT THREE}}')
assert "Not all numbers between 1 and 3" in err[0]
+
def test_macro_that_resolves_into_comment(base_app):
# Create the macro
out, err = run_cmd(base_app, 'macro create fake {1} blah blah')
@@ -1842,11 +2017,13 @@ def test_macro_that_resolves_into_comment(base_app):
assert not out
assert not err
+
def test_macro_list_invalid_macro(base_app):
# Look up invalid macro
out, err = run_cmd(base_app, 'macro list invalid')
assert "Macro 'invalid' not found" in err[0]
+
def test_macro_delete(base_app):
# Create an macro
run_cmd(base_app, 'macro create fake run_pyscript')
@@ -1855,18 +2032,22 @@ def test_macro_delete(base_app):
out, err = run_cmd(base_app, 'macro delete fake')
assert out == normalize("Macro 'fake' deleted")
+
def test_macro_delete_all(base_app):
out, err = run_cmd(base_app, 'macro delete --all')
assert out == normalize("All macros deleted")
+
def test_macro_delete_non_existing(base_app):
out, err = run_cmd(base_app, 'macro delete fake')
assert "Macro 'fake' does not exist" in err[0]
+
def test_macro_delete_no_name(base_app):
out, err = run_cmd(base_app, 'macro delete')
assert "Either --all or macro name(s)" in err[0]
+
def test_multiple_macros(base_app):
macro1 = 'h1'
macro2 = 'h2'
@@ -1879,8 +2060,10 @@ def test_multiple_macros(base_app):
verify_help_text(base_app, out2)
assert len(out2) > len(out)
+
def test_nonexistent_macro(base_app):
from cmd2.parsing import StatementParser
+
exception = None
try:
@@ -1890,6 +2073,7 @@ def test_nonexistent_macro(base_app):
assert exception is not None
+
def test_perror_style(base_app, capsys):
msg = 'testing...'
end = '\n'
@@ -1898,6 +2082,7 @@ def test_perror_style(base_app, capsys):
out, err = capsys.readouterr()
assert err == ansi.style_error(msg) + end
+
def test_perror_no_style(base_app, capsys):
msg = 'testing...'
end = '\n'
@@ -1906,6 +2091,7 @@ def test_perror_no_style(base_app, capsys):
out, err = capsys.readouterr()
assert err == msg + end
+
def test_pwarning_style(base_app, capsys):
msg = 'testing...'
end = '\n'
@@ -1914,6 +2100,7 @@ def test_pwarning_style(base_app, capsys):
out, err = capsys.readouterr()
assert err == ansi.style_warning(msg) + end
+
def test_pwarning_no_style(base_app, capsys):
msg = 'testing...'
end = '\n'
@@ -1922,6 +2109,7 @@ def test_pwarning_no_style(base_app, capsys):
out, err = capsys.readouterr()
assert err == msg + end
+
def test_ppaged(outsim_app):
msg = 'testing...'
end = '\n'
@@ -1929,18 +2117,21 @@ def test_ppaged(outsim_app):
out = outsim_app.stdout.getvalue()
assert out == msg + end
+
def test_ppaged_blank(outsim_app):
msg = ''
outsim_app.ppaged(msg)
out = outsim_app.stdout.getvalue()
assert not out
+
def test_ppaged_none(outsim_app):
msg = None
outsim_app.ppaged(msg)
out = outsim_app.stdout.getvalue()
assert not out
+
def test_ppaged_strips_ansi_when_redirecting(outsim_app):
msg = 'testing...'
end = '\n'
@@ -1950,6 +2141,7 @@ def test_ppaged_strips_ansi_when_redirecting(outsim_app):
out = outsim_app.stdout.getvalue()
assert out == msg + end
+
def test_ppaged_strips_ansi_when_redirecting_if_always(outsim_app):
msg = 'testing...'
end = '\n'
@@ -1960,6 +2152,7 @@ def test_ppaged_strips_ansi_when_redirecting_if_always(outsim_app):
out = outsim_app.stdout.getvalue()
assert out == colored_msg + end
+
# we override cmd.parseline() so we always get consistent
# command parsing by parent methods we don't override
# don't need to test all the parsing logic here, because
@@ -1971,6 +2164,7 @@ def test_parseline_empty(base_app):
assert not args
assert not line
+
def test_parseline(base_app):
statement = " command with 'partially completed quotes "
command, args, line = base_app.parseline(statement)
@@ -1986,6 +2180,7 @@ def test_onecmd_raw_str_continue(outsim_app):
assert not stop
verify_help_text(outsim_app, out)
+
def test_onecmd_raw_str_quit(outsim_app):
line = "quit"
stop = outsim_app.onecmd(line)
@@ -1993,6 +2188,7 @@ def test_onecmd_raw_str_quit(outsim_app):
assert stop
assert out == ''
+
def test_onecmd_add_to_history(outsim_app):
line = "help"
saved_hist_len = len(outsim_app.history)
@@ -2009,18 +2205,35 @@ def test_onecmd_add_to_history(outsim_app):
new_hist_len = len(outsim_app.history)
assert new_hist_len == saved_hist_len
+
def test_get_all_commands(base_app):
# Verify that the base app has the expected commands
commands = base_app.get_all_commands()
- expected_commands = ['_relative_run_script', 'alias', 'edit', 'eof', 'help', 'history', 'macro',
- 'py', 'quit', 'run_pyscript', 'run_script', 'set', 'shell', 'shortcuts']
+ expected_commands = [
+ '_relative_run_script',
+ 'alias',
+ 'edit',
+ 'eof',
+ 'help',
+ 'history',
+ 'macro',
+ 'py',
+ 'quit',
+ 'run_pyscript',
+ 'run_script',
+ 'set',
+ 'shell',
+ 'shortcuts',
+ ]
assert commands == expected_commands
+
def test_get_help_topics(base_app):
# Verify that the base app has no additional help_foo methods
custom_help = base_app.get_help_topics()
assert len(custom_help) == 0
+
def test_get_help_topics_hidden():
# Verify get_help_topics() filters out hidden commands
class TestApp(cmd2.Cmd):
@@ -2039,6 +2252,7 @@ def test_get_help_topics_hidden():
app.hidden_commands.append('my_cmd')
assert 'my_cmd' not in app.get_help_topics()
+
class ReplWithExitCode(cmd2.Cmd):
""" Example cmd2 application where we can specify an exit code when existing."""
@@ -2068,12 +2282,14 @@ Usage: exit [exit_code]
"""Hook method executed once when the cmdloop() method is about to return."""
self.poutput('exiting with code: {}'.format(self.exit_code))
+
@pytest.fixture
def exit_code_repl():
app = ReplWithExitCode()
app.stdout = utils.StdSim(app.stdout)
return app
+
def test_exit_code_default(exit_code_repl):
app = exit_code_repl
app.use_rawinput = True
@@ -2089,6 +2305,7 @@ def test_exit_code_default(exit_code_repl):
out = app.stdout.getvalue()
assert out == expected
+
def test_exit_code_nonzero(exit_code_repl):
app = exit_code_repl
app.use_rawinput = True
@@ -2118,6 +2335,7 @@ class AnsiApp(cmd2.Cmd):
# perror uses colors by default
self.perror(args)
+
def test_ansi_pouterr_always_tty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_ALWAYS
@@ -2140,6 +2358,7 @@ def test_ansi_pouterr_always_tty(mocker, capsys):
assert len(err) > len('oopsie\n')
assert 'oopsie' in err
+
def test_ansi_pouterr_always_notty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_ALWAYS
@@ -2162,6 +2381,7 @@ def test_ansi_pouterr_always_notty(mocker, capsys):
assert len(err) > len('oopsie\n')
assert 'oopsie' in err
+
def test_ansi_terminal_tty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_TERMINAL
@@ -2183,6 +2403,7 @@ def test_ansi_terminal_tty(mocker, capsys):
assert len(err) > len('oopsie\n')
assert 'oopsie' in err
+
def test_ansi_terminal_notty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_TERMINAL
@@ -2197,6 +2418,7 @@ def test_ansi_terminal_notty(mocker, capsys):
out, err = capsys.readouterr()
assert out == err == 'oopsie\n'
+
def test_ansi_never_tty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_NEVER
@@ -2211,6 +2433,7 @@ def test_ansi_never_tty(mocker, capsys):
out, err = capsys.readouterr()
assert out == err == 'oopsie\n'
+
def test_ansi_never_notty(mocker, capsys):
app = AnsiApp()
ansi.allow_style = ansi.STYLE_NEVER
@@ -2228,6 +2451,7 @@ def test_ansi_never_notty(mocker, capsys):
class DisableCommandsApp(cmd2.Cmd):
"""Class for disabling commands"""
+
category_name = "Test Category"
def __init__(self, *args, **kwargs):
@@ -2346,6 +2570,7 @@ def test_disable_and_enable_category(disable_commands_app):
help_topics = disable_commands_app.get_help_topics()
assert 'has_helper_funcs' in help_topics
+
def test_enable_enabled_command(disable_commands_app):
# Test enabling a command that is not disabled
saved_len = len(disable_commands_app.disabled_commands)
@@ -2354,10 +2579,12 @@ def test_enable_enabled_command(disable_commands_app):
# The number of disabled_commands should not have changed
assert saved_len == len(disable_commands_app.disabled_commands)
+
def test_disable_fake_command(disable_commands_app):
with pytest.raises(AttributeError):
disable_commands_app.disable_command('fake', 'fake message')
+
def test_disable_command_twice(disable_commands_app):
saved_len = len(disable_commands_app.disabled_commands)
message_to_print = 'These commands are currently disabled'
@@ -2373,6 +2600,7 @@ def test_disable_command_twice(disable_commands_app):
new_len = len(disable_commands_app.disabled_commands)
assert saved_len == new_len
+
def test_disabled_command_not_in_history(disable_commands_app):
message_to_print = 'These commands are currently disabled'
disable_commands_app.disable_command('has_helper_funcs', message_to_print)
@@ -2381,6 +2609,7 @@ def test_disabled_command_not_in_history(disable_commands_app):
run_cmd(disable_commands_app, 'has_helper_funcs')
assert saved_len == len(disable_commands_app.history)
+
def test_disabled_message_command_name(disable_commands_app):
message_to_print = '{} is currently disabled'.format(COMMAND_NAME)
disable_commands_app.disable_command('has_helper_funcs', message_to_print)