diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2019-06-14 17:36:44 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-14 17:36:44 -0400 |
commit | ddd07f9cd6d72baca1232ae98856cf3b3d564706 (patch) | |
tree | 8e03d435730baf1cc16ccc016e594d0b64d8e04a /tests | |
parent | f64f9d559caa08b5649b9bd356af2812acf103bd (diff) | |
parent | 756d8d38502e934ea180c4cfb8dea3efd124a3bf (diff) | |
download | cmd2-git-ddd07f9cd6d72baca1232ae98856cf3b3d564706.tar.gz |
Merge pull request #696 from python-cmd2/script_refactor
Script refactor
Diffstat (limited to 'tests')
-rw-r--r-- | tests/conftest.py | 3 | ||||
-rw-r--r-- | tests/pyscript/stop.py | 9 | ||||
-rw-r--r-- | tests/test_acargparse.py | 3 | ||||
-rw-r--r-- | tests/test_autocompletion.py | 3 | ||||
-rw-r--r-- | tests/test_cmd2.py | 259 | ||||
-rw-r--r-- | tests/test_completion.py | 3 | ||||
-rw-r--r-- | tests/test_parsing.py | 3 | ||||
-rw-r--r-- | tests/test_plugin.py | 47 | ||||
-rw-r--r-- | tests/test_pyscript.py | 14 | ||||
-rw-r--r-- | tests/test_transcript.py | 89 | ||||
-rw-r--r-- | tests/test_utils.py | 3 | ||||
-rw-r--r-- | tests/transcripts/from_cmdloop.txt | 1 |
12 files changed, 248 insertions, 189 deletions
diff --git a/tests/conftest.py b/tests/conftest.py index dc5c1ab1..517e2865 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,9 +1,6 @@ # coding=utf-8 """ Cmd2 unit/functional testing - -Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> -Released under MIT license, see LICENSE file """ import sys from typing import Optional diff --git a/tests/pyscript/stop.py b/tests/pyscript/stop.py new file mode 100644 index 00000000..e731218e --- /dev/null +++ b/tests/pyscript/stop.py @@ -0,0 +1,9 @@ +# flake8: noqa F821 +app.cmd_echo = True +app('help') + +# This will set stop to True in the PyscriptBridge +app('quit') + +# Exercise py_quit() in unit test +quit() diff --git a/tests/test_acargparse.py b/tests/test_acargparse.py index 64612737..436158db 100644 --- a/tests/test_acargparse.py +++ b/tests/test_acargparse.py @@ -1,9 +1,6 @@ # flake8: noqa E302 """ Unit/functional testing for argparse customizations in cmd2 - -Copyright 2018 Eric Lin <anselor@gmail.com> -Released under MIT license, see LICENSE file """ import pytest from cmd2.argparse_completer import ACArgumentParser, is_potential_flag diff --git a/tests/test_autocompletion.py b/tests/test_autocompletion.py index 005eee81..4e1ceff0 100644 --- a/tests/test_autocompletion.py +++ b/tests/test_autocompletion.py @@ -2,9 +2,6 @@ # flake8: noqa E302 """ Unit/functional testing for argparse completer in cmd2 - -Copyright 2018 Eric Lin <anselor@gmail.com> -Released under MIT license, see LICENSE file """ import pytest diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 1aafefc2..0dc8c7c2 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -2,9 +2,6 @@ # flake8: noqa E302 """ Cmd2 unit/functional testing - -Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> -Released under MIT license, see LICENSE file """ import argparse import builtins @@ -28,13 +25,15 @@ from cmd2 import clipboard, constants, utils from .conftest import run_cmd, normalize, BASE_HELP, BASE_HELP_VERBOSE, \ HELP_HISTORY, SHORTCUTS_TXT, SHOW_TXT, SHOW_LONG - -@pytest.fixture -def outsim_app(): +def CreateOutsimApp(): c = cmd2.Cmd() c.stdout = utils.StdSim(c.stdout) return c +@pytest.fixture +def outsim_app(): + return CreateOutsimApp() + def test_version(base_app): assert cmd2.__version__ @@ -112,9 +111,8 @@ def test_base_show_readonly(base_app): out, err = run_cmd(base_app, 'set -a') expected = normalize(SHOW_TXT + '\nRead only settings:' + """ Commands may be terminated with: {} - Arguments at invocation allowed: {} Output redirection and pipes allowed: {} -""".format(base_app.statement_parser.terminators, base_app.allow_cli_args, base_app.allow_redirection)) +""".format(base_app.statement_parser.terminators, base_app.allow_redirection)) assert out == expected @@ -297,17 +295,28 @@ def test_base_load(base_app, request): test_dir = os.path.dirname(request.module.__file__) filename = os.path.join(test_dir, 'script.txt') - assert base_app.cmdqueue == [] assert base_app._script_dir == [] assert base_app._current_script_dir is None - # Run the load command, which populates the command queue and sets the script directory - run_cmd(base_app, 'load {}'.format(filename)) + # Get output out the script + script_out, script_err = run_cmd(base_app, 'load {}'.format(filename)) + + assert base_app._script_dir == [] + assert base_app._current_script_dir is None - assert base_app.cmdqueue == ['help history', 'eos'] - sdir = os.path.dirname(filename) - assert base_app._script_dir == [sdir] - assert base_app._current_script_dir == sdir + # Now run the commands manually and compare their output to script's + with open(filename, encoding='utf-8') as file: + script_commands = file.read().splitlines() + + manual_out = [] + manual_err = [] + for cmdline in script_commands: + out, err = run_cmd(base_app, cmdline) + manual_out.extend(out) + manual_err.extend(err) + + assert script_out == manual_out + assert script_err == manual_err def test_load_with_empty_args(base_app): # The way the load command works, we can't directly capture its stdout or stderr @@ -315,7 +324,6 @@ def test_load_with_empty_args(base_app): # The load command requires a file path argument, so we should get an error message assert "the following arguments are required" in err[1] - assert base_app.cmdqueue == [] def test_load_with_nonexistent_file(base_app, capsys): @@ -324,7 +332,6 @@ def test_load_with_nonexistent_file(base_app, capsys): # The load command requires a path to an existing file assert "does not exist" in err[0] - assert base_app.cmdqueue == [] def test_load_with_directory(base_app, request): test_dir = os.path.dirname(request.module.__file__) @@ -333,7 +340,6 @@ def test_load_with_directory(base_app, request): out, err = run_cmd(base_app, 'load {}'.format(test_dir)) assert "is not a file" in err[0] - assert base_app.cmdqueue == [] def test_load_with_empty_file(base_app, request): test_dir = os.path.dirname(request.module.__file__) @@ -344,7 +350,6 @@ def test_load_with_empty_file(base_app, request): # The load command requires non-empty script files assert "is empty" in err[0] - assert base_app.cmdqueue == [] def test_load_with_binary_file(base_app, request): @@ -356,42 +361,45 @@ def test_load_with_binary_file(base_app, request): # The load command requires non-empty scripts files assert "is not an ASCII or UTF-8 encoded text file" in err[0] - assert base_app.cmdqueue == [] def test_load_with_utf8_file(base_app, request): test_dir = os.path.dirname(request.module.__file__) filename = os.path.join(test_dir, 'scripts', 'utf8.txt') - assert base_app.cmdqueue == [] assert base_app._script_dir == [] assert base_app._current_script_dir is None - # Run the load command, which populates the command queue and sets the script directory - run_cmd(base_app, 'load {}'.format(filename)) + # Get output out the script + script_out, script_err = run_cmd(base_app, 'load {}'.format(filename)) + + assert base_app._script_dir == [] + assert base_app._current_script_dir is None - assert base_app.cmdqueue == ['!echo γνωρίζω', 'eos'] - sdir = os.path.dirname(filename) - assert base_app._script_dir == [sdir] - assert base_app._current_script_dir == sdir + # Now run the commands manually and compare their output to script's + with open(filename, encoding='utf-8') as file: + script_commands = file.read().splitlines() + + manual_out = [] + manual_err = [] + for cmdline in script_commands: + out, err = run_cmd(base_app, cmdline) + manual_out.extend(out) + manual_err.extend(err) + + assert script_out == manual_out + assert script_err == manual_err def test_load_nested_loads(base_app, request): # Verify that loading a script with nested load commands works correctly, - # and loads the nested script commands in the correct order. The recursive - # loads don't happen all at once, but as the commands are interpreted. So, - # we will need to drain the cmdqueue and inspect the stdout to see if all - # steps were executed in the expected order. + # and loads the nested script commands in the correct order. test_dir = os.path.dirname(request.module.__file__) filename = os.path.join(test_dir, 'scripts', 'nested.txt') - assert base_app.cmdqueue == [] - # Load the top level script and then run the command queue until all - # commands have been exhausted. + # Load the top level script initial_load = 'load ' + filename run_cmd(base_app, initial_load) - while base_app.cmdqueue: - base_app.onecmd_plus_hooks(base_app.cmdqueue.pop(0)) # Check that the right commands were executed. expected = """ @@ -407,12 +415,9 @@ set colors Never""" % initial_load def test_base_runcmds_plus_hooks(base_app, request): - # Make sure that runcmds_plus_hooks works as intended. I.E. to run multiple - # commands and process any commands added, by them, to the command queue. 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') - assert base_app.cmdqueue == [] base_app.runcmds_plus_hooks(['load ' + prefilepath, 'help', @@ -429,27 +434,36 @@ set colors Never""" % (prefilepath, postfilepath) out, err = run_cmd(base_app, 'history -s') assert out == normalize(expected) - def test_base_relative_load(base_app, request): test_dir = os.path.dirname(request.module.__file__) filename = os.path.join(test_dir, 'script.txt') - assert base_app.cmdqueue == [] assert base_app._script_dir == [] assert base_app._current_script_dir is None - # Run the load command, which populates the command queue and sets the script directory - run_cmd(base_app, '_relative_load {}'.format(filename)) + # Get output out the script + script_out, script_err = run_cmd(base_app, 'load {}'.format(filename)) + + assert base_app._script_dir == [] + assert base_app._current_script_dir is None + + # Now run the commands manually and compare their output to script's + with open(filename, encoding='utf-8') as file: + script_commands = file.read().splitlines() - assert base_app.cmdqueue == ['help history', 'eos'] - sdir = os.path.dirname(filename) - assert base_app._script_dir == [sdir] - assert base_app._current_script_dir == sdir + manual_out = [] + manual_err = [] + for cmdline in script_commands: + out, err = run_cmd(base_app, cmdline) + manual_out.extend(out) + manual_err.extend(err) + + assert script_out == manual_out + assert script_err == manual_err def test_relative_load_requires_an_argument(base_app): out, err = run_cmd(base_app, '_relative_load') assert 'Error: the following arguments' in err[1] - assert base_app.cmdqueue == [] def test_output_redirection(base_app): @@ -495,7 +509,11 @@ def test_output_redirection_to_nonexistent_directory(base_app): assert content == expected def test_output_redirection_to_too_long_filename(base_app): - filename = '~/sdkfhksdjfhkjdshfkjsdhfkjsdhfkjdshfkjdshfkjshdfkhdsfkjhewfuihewiufhweiufhiweufhiuewhiuewhfiuwehfiuewhfiuewhfiuewhfiuewhiuewhfiuewhfiuewfhiuwehewiufhewiuhfiweuhfiuwehfiuewfhiuwehiuewfhiuewhiewuhfiuewhfiuwefhewiuhewiufhewiufhewiufhewiufhewiufhewiufhewiufhewiuhewiufhewiufhewiuheiufhiuewheiwufhewiufheiufheiufhieuwhfewiuhfeiufhiuewfhiuewheiwuhfiuewhfiuewhfeiuwfhewiufhiuewhiuewhfeiuwhfiuwehfuiwehfiuehiuewhfieuwfhieufhiuewhfeiuwfhiuefhueiwhfw' + filename = '~/sdkfhksdjfhkjdshfkjsdhfkjsdhfkjdshfkjdshfkjshdfkhdsfkjhewfuihewiufhweiufhiweufhiuewhiuewhfiuwehfia' \ + 'ewhfiuewhfiuewhfiuewhiuewhfiuewhfiuewfhiuwehewiufhewiuhfiweuhfiuwehfiuewfhiuwehiuewfhiuewhiewuhfiueh' \ + 'fiuwefhewiuhewiufhewiufhewiufhewiufhewiufhewiufhewiufhewiuhewiufhewiufhewiuheiufhiuewheiwufhewiufheu' \ + 'fheiufhieuwhfewiuhfeiufhiuewfhiuewheiwuhfiuewhfiuewhfeiuwfhewiufhiuewhiuewhfeiuwhfiuwehfuiwehfiuehie' \ + 'whfieuwfhieufhiuewhfeiuwfhiuefhueiwhfw' # Verify that writing to a file in a non-existent directory doesn't work run_cmd(base_app, 'help > {}'.format(filename)) @@ -717,60 +735,66 @@ def test_base_py_interactive(base_app): m.assert_called_once() -def test_base_cmdloop_with_queue(outsim_app): - # Create a cmd2.Cmd() instance and make sure basic settings are like we want for test - outsim_app.use_rawinput = True +def test_base_cmdloop_with_startup_commands(): intro = 'Hello World, this is an intro ...' - outsim_app.cmdqueue.append('quit\n') # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args - testargs = ["prog"] + testargs = ["prog", 'quit'] expected = intro + '\n' + with mock.patch.object(sys, 'argv', testargs): - # Run the command loop with custom intro - outsim_app.cmdloop(intro=intro) - out = outsim_app.stdout.getvalue() + app = CreateOutsimApp() + + app.use_rawinput = True + + # Run the command loop with custom intro + app.cmdloop(intro=intro) + + out = app.stdout.getvalue() assert out == expected -def test_base_cmdloop_without_queue(outsim_app): - # Create a cmd2.Cmd() instance and make sure basic settings are like we want for test - outsim_app.use_rawinput = True - outsim_app.intro = 'Hello World, this is an intro ...' +def test_base_cmdloop_without_startup_commands(): + # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args + testargs = ["prog"] + with mock.patch.object(sys, 'argv', testargs): + app = CreateOutsimApp() + + app.use_rawinput = True + app.intro = 'Hello World, this is an intro ...' # Mock out the input call so we don't actually wait for a user's response on stdin m = mock.MagicMock(name='input', return_value='quit') builtins.input = m + expected = app.intro + '\n' + + # Run the command loop + app.cmdloop() + out = app.stdout.getvalue() + assert out == expected + + +def test_cmdloop_without_rawinput(): # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args testargs = ["prog"] - expected = outsim_app.intro + '\n' with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - outsim_app.cmdloop() - out = outsim_app.stdout.getvalue() - assert out == expected + app = CreateOutsimApp() - -def test_cmdloop_without_rawinput(outsim_app): - # Create a cmd2.Cmd() instance and make sure basic settings are like we want for test - outsim_app.use_rawinput = False - outsim_app.echo = False - outsim_app.intro = 'Hello World, this is an intro ...' + app.use_rawinput = False + app.echo = False + app.intro = 'Hello World, this is an intro ...' # Mock out the input call so we don't actually wait for a user's response on stdin m = mock.MagicMock(name='input', return_value='quit') builtins.input = m - # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args - testargs = ["prog"] - expected = outsim_app.intro + '\n' - with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - outsim_app.cmdloop() - out = outsim_app.stdout.getvalue() - assert out == expected + expected = app.intro + '\n' + with pytest.raises(OSError): + app.cmdloop() + out = app.stdout.getvalue() + assert out == expected class HookFailureApp(cmd2.Cmd): def __init__(self, *args, **kwargs): @@ -807,8 +831,7 @@ class SayApp(cmd2.Cmd): @pytest.fixture def say_app(): - app = SayApp() - app.allow_cli_args = False + app = SayApp(allow_cli_args=False) app.stdout = utils.StdSim(app.stdout) return app @@ -820,7 +843,10 @@ def test_interrupt_quit(say_app): m.side_effect = ['say hello', KeyboardInterrupt(), 'say goodbye', 'eof'] builtins.input = m - say_app.cmdloop() + try: + say_app.cmdloop() + except KeyboardInterrupt: + pass # And verify the expected output to stdout out = say_app.stdout.getvalue() @@ -834,7 +860,10 @@ def test_interrupt_noquit(say_app): m.side_effect = ['say hello', KeyboardInterrupt(), 'say goodbye', 'eof'] builtins.input = m - say_app.cmdloop() + try: + say_app.cmdloop() + except KeyboardInterrupt: + pass # And verify the expected output to stdout out = say_app.stdout.getvalue() @@ -1358,36 +1387,15 @@ def test_eof(base_app): # Only thing to verify is that it returns True assert base_app.do_eof('') -def test_eos(base_app): - sdir = 'dummy_dir' - base_app._script_dir.append(sdir) - assert len(base_app._script_dir) == 1 - - # Assert that it does NOT return true - assert not base_app.do_eos('') - - # And make sure it reduced the length of the script dir list - assert len(base_app._script_dir) == 0 - def test_echo(capsys): app = cmd2.Cmd() - # Turn echo on and pre-stage some commands in the queue, simulating like we are in the middle of a script app.echo = True - command = 'help history' - app.cmdqueue = [command, 'quit', 'eos'] - app._script_dir.append('some_dir') - - assert app._current_script_dir is not None + commands = ['help history'] - # Run the inner _cmdloop - app._cmdloop() + app.runcmds_plus_hooks(commands) out, err = capsys.readouterr() - - # Check the output - assert app.cmdqueue == [] - assert app._current_script_dir is None - assert out.startswith('{}{}\n'.format(app.prompt, command) + HELP_HISTORY.split()[0]) + assert out.startswith('{}{}\n'.format(app.prompt, commands[0]) + HELP_HISTORY.split()[0]) def test_pseudo_raw_input_tty_rawinput_true(): # use context managers so original functions get put back when we are done @@ -1395,7 +1403,7 @@ def test_pseudo_raw_input_tty_rawinput_true(): with mock.patch('sys.stdin.isatty', mock.MagicMock(name='isatty', return_value=True)): with mock.patch('builtins.input', mock.MagicMock(name='input', side_effect=['set', EOFError])) as m_input: # run the cmdloop, which should pull input from our mocks - app = cmd2.Cmd() + app = cmd2.Cmd(allow_cli_args=False) app.use_rawinput = True app._cmdloop() # because we mocked the input() call, we won't get the prompt @@ -1414,7 +1422,7 @@ def test_pseudo_raw_input_tty_rawinput_false(): fakein.readline = mreadline # run the cmdloop, telling it where to get input from - app = cmd2.Cmd(stdin=fakein) + app = cmd2.Cmd(stdin=fakein, allow_cli_args=False) app.use_rawinput = False app._cmdloop() @@ -1428,7 +1436,7 @@ def test_pseudo_raw_input_tty_rawinput_false(): # the next helper function and two tests check for piped # input when use_rawinput is True. def piped_rawinput_true(capsys, echo, command): - app = cmd2.Cmd() + app = cmd2.Cmd(allow_cli_args=False) app.use_rawinput = True app.echo = echo # run the cmdloop, which should pull input from our mock @@ -1458,8 +1466,7 @@ def test_pseudo_raw_input_piped_rawinput_true_echo_false(capsys): # input when use_rawinput=False def piped_rawinput_false(capsys, echo, command): fakein = io.StringIO(u'{}'.format(command)) - # run the cmdloop, telling it where to get input from - app = cmd2.Cmd(stdin=fakein) + app = cmd2.Cmd(stdin=fakein, allow_cli_args=False) app.use_rawinput = False app.echo = echo app._cmdloop() @@ -1913,7 +1920,7 @@ def test_onecmd_raw_str_quit(outsim_app): 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_load', 'alias', 'edit', 'eof', 'eos', 'help', 'history', 'load', 'macro', + expected_commands = ['_relative_load', 'alias', 'edit', 'eof', 'help', 'history', 'load', 'macro', 'py', 'pyscript', 'quit', 'set', 'shell', 'shortcuts'] assert commands == expected_commands @@ -1927,7 +1934,7 @@ class ReplWithExitCode(cmd2.Cmd): """ Example cmd2 application where we can specify an exit code when existing.""" def __init__(self): - super().__init__() + super().__init__(allow_cli_args=False) @cmd2.with_argument_list def do_exit(self, arg_list) -> bool: @@ -1945,8 +1952,8 @@ Usage: exit [exit_code] self.perror("{} isn't a valid integer exit code".format(arg_list[0])) self.exit_code = -1 - self._should_quit = True - return self._STOP_AND_EXIT + # Return True to stop the command loop + return True def postloop(self) -> None: """Hook method executed once when the cmdloop() method is about to return.""" @@ -1959,7 +1966,6 @@ def exit_code_repl(): return app def test_exit_code_default(exit_code_repl): - # Create a cmd2.Cmd() instance and make sure basic settings are like we want for test app = exit_code_repl app.use_rawinput = True @@ -1967,17 +1973,14 @@ def test_exit_code_default(exit_code_repl): m = mock.MagicMock(name='input', return_value='exit') builtins.input = m - # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args - testargs = ["prog"] expected = 'exiting with code: 0\n' - with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - app.cmdloop() + + # Run the command loop + app.cmdloop() out = app.stdout.getvalue() assert out == expected def test_exit_code_nonzero(exit_code_repl): - # Create a cmd2.Cmd() instance and make sure basic settings are like we want for test app = exit_code_repl app.use_rawinput = True @@ -1985,12 +1988,10 @@ def test_exit_code_nonzero(exit_code_repl): m = mock.MagicMock(name='input', return_value='exit 23') builtins.input = m - # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args - testargs = ["prog"] expected = 'exiting with code: 23\n' - with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - app.cmdloop() + + # Run the command loop + app.cmdloop() out = app.stdout.getvalue() assert out == expected diff --git a/tests/test_completion.py b/tests/test_completion.py index 6fd45ff9..0a16bc28 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -5,9 +5,6 @@ Unit/functional testing for readline tab-completion functions in the cmd2.py mod These are primarily tests related to readline completer functions which handle tab-completion of cmd2/cmd commands, file system paths, and shell commands. - -Copyright 2017 Todd Leonhardt <todd.leonhardt@gmail.com> -Released under MIT license, see LICENSE file """ import argparse import os diff --git a/tests/test_parsing.py b/tests/test_parsing.py index de8d67af..5ba02a95 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -2,9 +2,6 @@ # flake8: noqa E302 """ Test the parsing logic in parsing.py - -Copyright 2017 Todd Leonhardt <todd.leonhardt@gmail.com> -Released under MIT license, see LICENSE file """ import attr import pytest diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 242b0d25..f7065db5 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2,12 +2,17 @@ # flake8: noqa E302 """ Test plugin infrastructure and hooks. - -Copyright 2018 Jared Crapo <jared@kotfu.net> -Released under MIT license, see LICENSE file """ +import sys + import pytest +# Python 3.5 had some regressions in the unitest.mock module, so use 3rd party mock if available +try: + import mock +except ImportError: + from unittest import mock + import cmd2 from cmd2 import plugin @@ -265,21 +270,27 @@ def test_register_preloop_hook_with_return_annotation(): app.register_preloop_hook(app.prepost_hook_with_wrong_return_annotation) def test_preloop_hook(capsys): - app = PluggedApp() + # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args + testargs = ["prog", "say hello", 'quit'] + + with mock.patch.object(sys, 'argv', testargs): + app = PluggedApp() + app.register_preloop_hook(app.prepost_hook_one) - app.cmdqueue.append('say hello') - app.cmdqueue.append('quit') app.cmdloop() out, err = capsys.readouterr() assert out == 'one\nhello\n' assert not err def test_preloop_hooks(capsys): - app = PluggedApp() + # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args + testargs = ["prog", "say hello", 'quit'] + + with mock.patch.object(sys, 'argv', testargs): + app = PluggedApp() + app.register_preloop_hook(app.prepost_hook_one) app.register_preloop_hook(app.prepost_hook_two) - app.cmdqueue.append('say hello') - app.cmdqueue.append('quit') app.cmdloop() out, err = capsys.readouterr() assert out == 'one\ntwo\nhello\n' @@ -296,21 +307,27 @@ def test_register_postloop_hook_with_wrong_return_annotation(): app.register_postloop_hook(app.prepost_hook_with_wrong_return_annotation) def test_postloop_hook(capsys): - app = PluggedApp() + # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args + testargs = ["prog", "say hello", 'quit'] + + with mock.patch.object(sys, 'argv', testargs): + app = PluggedApp() + app.register_postloop_hook(app.prepost_hook_one) - app.cmdqueue.append('say hello') - app.cmdqueue.append('quit') app.cmdloop() out, err = capsys.readouterr() assert out == 'hello\none\n' assert not err def test_postloop_hooks(capsys): - app = PluggedApp() + # Need to patch sys.argv so cmd2 doesn't think it was called with arguments equal to the py.test args + testargs = ["prog", "say hello", 'quit'] + + with mock.patch.object(sys, 'argv', testargs): + app = PluggedApp() + app.register_postloop_hook(app.prepost_hook_one) app.register_postloop_hook(app.prepost_hook_two) - app.cmdqueue.append('say hello') - app.cmdqueue.append('quit') app.cmdloop() out, err = capsys.readouterr() assert out == 'hello\none\ntwo\n' diff --git a/tests/test_pyscript.py b/tests/test_pyscript.py index 4866548b..8da4b35a 100644 --- a/tests/test_pyscript.py +++ b/tests/test_pyscript.py @@ -40,3 +40,17 @@ def test_pyscript_stdout_capture(base_app, request): assert out[0] == "PASSED" assert out[1] == "PASSED" + +def test_pyscript_stop(base_app, request): + # Verify onecmd_plus_hooks() returns True if any commands in a pyscript return True for stop + test_dir = os.path.dirname(request.module.__file__) + + # help.py doesn't run any commands that returns True for stop + python_script = os.path.join(test_dir, 'pyscript', 'help.py') + stop = base_app.onecmd_plus_hooks('pyscript {}'.format(python_script)) + assert not stop + + # stop.py runs the quit command which does return True for stop + python_script = os.path.join(test_dir, 'pyscript', 'stop.py') + stop = base_app.onecmd_plus_hooks('pyscript {}'.format(python_script)) + assert stop diff --git a/tests/test_transcript.py b/tests/test_transcript.py index 70c9119c..5dd39e1b 100644 --- a/tests/test_transcript.py +++ b/tests/test_transcript.py @@ -2,9 +2,6 @@ # flake8: noqa E302 """ Cmd2 functional testing based on transcript - -Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> -Released under MIT license, see LICENSE file """ import argparse import os @@ -90,10 +87,11 @@ def test_commands_at_invocation(): expected = "This is an intro banner ...\nhello\nGracie\n" with mock.patch.object(sys, 'argv', testargs): app = CmdLineApp() - app.stdout = StdSim(app.stdout) - app.cmdloop() - out = app.stdout.getvalue() - assert out == expected + + app.stdout = StdSim(app.stdout) + app.cmdloop() + out = app.stdout.getvalue() + assert out == expected @pytest.mark.parametrize('filename,feedback_to_output', [ ('bol_eol.txt', False), @@ -113,11 +111,6 @@ def test_commands_at_invocation(): ('word_boundaries.txt', False), ]) def test_transcript(request, capsys, filename, feedback_to_output): - # Create a cmd2.Cmd() instance and make sure basic settings are - # like we want for test - app = CmdLineApp() - app.feedback_to_output = feedback_to_output - # Get location of the transcript test_dir = os.path.dirname(request.module.__file__) transcript_file = os.path.join(test_dir, 'transcripts', filename) @@ -126,9 +119,15 @@ def test_transcript(request, capsys, filename, feedback_to_output): # arguments equal to the py.test args testargs = ['prog', '-t', transcript_file] with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - sys_exit_code = app.cmdloop() - assert sys_exit_code == 0 + # Create a cmd2.Cmd() instance and make sure basic settings are + # like we want for test + app = CmdLineApp() + + app.feedback_to_output = feedback_to_output + + # Run the command loop + sys_exit_code = app.cmdloop() + assert sys_exit_code == 0 # Check for the unittest "OK" condition for the 1 test which ran expected_start = ".\n----------------------------------------------------------------------\nRan 1 test in" @@ -195,7 +194,6 @@ def test_load_record_transcript(base_app, request): test_dir = os.path.dirname(request.module.__file__) filename = os.path.join(test_dir, 'scripts', 'help.txt') - assert base_app.cmdqueue == [] assert base_app._script_dir == [] assert base_app._current_script_dir is None @@ -206,7 +204,6 @@ def test_load_record_transcript(base_app, request): # Run the load command with the -r option to generate a transcript run_cmd(base_app, 'load {} -t {}'.format(filename, transcript_fname)) - assert base_app.cmdqueue == [] assert base_app._script_dir == [] assert base_app._current_script_dir is None @@ -219,6 +216,27 @@ def test_load_record_transcript(base_app, request): assert xscript == expected +def test_generate_transcript_stop(capsys): + # Verify transcript generation stops when a command returns True for stop + app = CmdLineApp() + + # Make a tmp file to use as a transcript + fd, transcript_fname = tempfile.mkstemp(prefix='', suffix='.trn') + os.close(fd) + + # This should run all commands + commands = ['help', 'alias'] + app._generate_transcript(commands, transcript_fname) + _, err = capsys.readouterr() + assert err.startswith("2 commands") + + # Since quit returns True for stop, only the first 2 commands will run + commands = ['help', 'quit', 'alias'] + app._generate_transcript(commands, transcript_fname) + _, err = capsys.readouterr() + assert err.startswith("Command 2 triggered a stop") + + @pytest.mark.parametrize('expected, transformed', [ # strings with zero or one slash or with escaped slashes means no regular # expression present, so the result should just be what re.escape returns. @@ -251,11 +269,6 @@ def test_parse_transcript_expected(expected, transformed): def test_transcript_failure(request, capsys): - # Create a cmd2.Cmd() instance and make sure basic settings are - # like we want for test - app = CmdLineApp() - app.feedback_to_output = False - # Get location of the transcript test_dir = os.path.dirname(request.module.__file__) transcript_file = os.path.join(test_dir, 'transcripts', 'failure.txt') @@ -264,13 +277,37 @@ def test_transcript_failure(request, capsys): # arguments equal to the py.test args testargs = ['prog', '-t', transcript_file] with mock.patch.object(sys, 'argv', testargs): - # Run the command loop - sys_exit_code = app.cmdloop() - assert sys_exit_code != 0 + # Create a cmd2.Cmd() instance and make sure basic settings are + # like we want for test + app = CmdLineApp() + + app.feedback_to_output = False + + # Run the command loop + sys_exit_code = app.cmdloop() + assert sys_exit_code != 0 - # Check for the unittest "OK" condition for the 1 test which ran expected_start = "File " expected_end = "s\n\nFAILED (failures=1)\n\n" _, err = capsys.readouterr() assert err.startswith(expected_start) assert err.endswith(expected_end) + + +def test_transcript_no_file(request, capsys): + # Need to patch sys.argv so cmd2 doesn't think it was called with + # arguments equal to the py.test args + testargs = ['prog', '-t'] + with mock.patch.object(sys, 'argv', testargs): + app = CmdLineApp() + + app.feedback_to_output = False + + # Run the command loop + sys_exit_code = app.cmdloop() + assert sys_exit_code != 0 + + # Check for the unittest "OK" condition for the 1 test which ran + expected = 'No test files found - nothing to test\n' + _, err = capsys.readouterr() + assert err == expected diff --git a/tests/test_utils.py b/tests/test_utils.py index c0b16990..b43eb10c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,9 +2,6 @@ # flake8: noqa E302 """ Unit testing for cmd2/utils.py module. - -Copyright 2018 Todd Leonhardt <todd.leonhardt@gmail.com> -Released under MIT license, see LICENSE file """ import signal import sys diff --git a/tests/transcripts/from_cmdloop.txt b/tests/transcripts/from_cmdloop.txt index 871b71f1..84d7f8fc 100644 --- a/tests/transcripts/from_cmdloop.txt +++ b/tests/transcripts/from_cmdloop.txt @@ -42,7 +42,6 @@ OODNIGHT, GRACIEGAY 5 set maxrepeats 5 6 say -ps --repeat=5 goodnight, Gracie (Cmd) history -r 4 -say -ps --repeat=5 goodnight, Gracie OODNIGHT, GRACIEGAY OODNIGHT, GRACIEGAY OODNIGHT, GRACIEGAY |