diff options
author | xNinjaKittyx <xNinjaKittyx@users.noreply.github.com> | 2020-12-15 17:21:33 -0800 |
---|---|---|
committer | xNinjaKittyx <xNinjaKittyx@users.noreply.github.com> | 2020-12-15 18:20:13 -0800 |
commit | 9aa54a5b27468d61337528cb1e1b5b9b11a80978 (patch) | |
tree | 567693115cc101efb9254a96d96d80e9f9ccd557 /tests/test_cmd2.py | |
parent | 03c65c60b39e369958b056c5c844d36d515c8a63 (diff) | |
download | cmd2-git-ci_improvements.tar.gz |
Adds pre-commit config to run various lintersci_improvements
This ads black, isort, pyupgrade, and flake8 to pre-commit-config.yaml
There are also some small changes to travis.yml and tasks.py to reduce
some repeated configurations that should be consolidated into
setup.cfg. Most other changes are automated by the linter scripts.
Diffstat (limited to 'tests/test_cmd2.py')
-rwxr-xr-x | tests/test_cmd2.py | 351 |
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) |