summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2019-11-17 15:13:46 -0500
committerGitHub <noreply@github.com>2019-11-17 15:13:46 -0500
commit73535e1ff82b49c594fc694ef0ea898d46742750 (patch)
tree66ed54cf0a73ef86c5c861c6c5122bf269fad9dc /tests
parent0fc04d2091069ddabf776bd9fddf0408b81e57af (diff)
parentc474c4cb7a910f033cd53764dcf45c68c6b939d2 (diff)
downloadcmd2-git-73535e1ff82b49c594fc694ef0ea898d46742750.tar.gz
Merge pull request #810 from python-cmd2/read_input
cmd2-specific input() function
Diffstat (limited to 'tests')
-rwxr-xr-xtests/test_cmd2.py288
1 files changed, 138 insertions, 150 deletions
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index cb66ac9b..f9c3e61d 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -847,6 +847,18 @@ 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")
+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)):
+ # Mock out the subprocess.Popen call so we don't actually run stty sane
+ m = mock.MagicMock(name='Popen')
+ monkeypatch.setattr("subprocess.Popen", m)
+
+ 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)
@@ -1092,10 +1104,10 @@ def select_app():
app = SelectApp()
return app
-def test_select_options(select_app):
- # 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='2')
- builtins.input = m
+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')
+ monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
food = 'bacon'
out, err = run_cmd(select_app, "eat {}".format(food))
@@ -1106,17 +1118,18 @@ def test_select_options(select_app):
""".format(food))
# Make sure our mock was called with the expected arguments
- m.assert_called_once_with('Sauce? ')
+ read_input_mock.assert_called_once_with('Sauce? ')
# And verify the expected output to stdout
assert out == expected
-def test_select_invalid_option_too_big(select_app):
+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
- m = mock.MagicMock(name='input')
+ read_input_mock = mock.MagicMock(name='read_input')
+
# If side_effect is an iterable then each call to the mock will return the next value from the iterable.
- m.side_effect = ['3', '1'] # First pass an invalid selection, then pass a valid one
- builtins.input = m
+ read_input_mock.side_effect = ['3', '1'] # First pass an invalid selection, then pass a valid one
+ monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
food = 'fish'
out, err = run_cmd(select_app, "eat {}".format(food))
@@ -1130,18 +1143,19 @@ def test_select_invalid_option_too_big(select_app):
# Make sure our mock was called exactly twice with the expected arguments
arg = 'Sauce? '
calls = [mock.call(arg), mock.call(arg)]
- m.assert_has_calls(calls)
- assert m.call_count == 2
+ read_input_mock.assert_has_calls(calls)
+ assert read_input_mock.call_count == 2
# And verify the expected output to stdout
assert out == expected
-def test_select_invalid_option_too_small(select_app):
+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
- m = mock.MagicMock(name='input')
+ read_input_mock = mock.MagicMock(name='read_input')
+
# If side_effect is an iterable then each call to the mock will return the next value from the iterable.
- m.side_effect = ['0', '1'] # First pass an invalid selection, then pass a valid one
- builtins.input = m
+ read_input_mock.side_effect = ['0', '1'] # First pass an invalid selection, then pass a valid one
+ monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
food = 'fish'
out, err = run_cmd(select_app, "eat {}".format(food))
@@ -1155,16 +1169,16 @@ def test_select_invalid_option_too_small(select_app):
# Make sure our mock was called exactly twice with the expected arguments
arg = 'Sauce? '
calls = [mock.call(arg), mock.call(arg)]
- m.assert_has_calls(calls)
- assert m.call_count == 2
+ read_input_mock.assert_has_calls(calls)
+ assert read_input_mock.call_count == 2
# And verify the expected output to stdout
assert out == expected
-def test_select_list_of_strings(select_app):
+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
- m = mock.MagicMock(name='input', return_value='2')
- builtins.input = m
+ 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("""
@@ -1174,15 +1188,15 @@ Good luck learning {}!
""".format('science'))
# Make sure our mock was called with the expected arguments
- m.assert_called_once_with('Subject? ')
+ read_input_mock.assert_called_once_with('Subject? ')
# And verify the expected output to stdout
assert out == expected
-def test_select_list_of_tuples(select_app):
+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
- m = mock.MagicMock(name='input', return_value='2')
- builtins.input = m
+ 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("""
@@ -1192,16 +1206,16 @@ Have fun procrasinating with {}!
""".format('YouTube'))
# Make sure our mock was called with the expected arguments
- m.assert_called_once_with('How would you like to procrastinate? ')
+ read_input_mock.assert_called_once_with('How would you like to procrastinate? ')
# And verify the expected output to stdout
assert out == expected
-def test_select_uneven_list_of_tuples(select_app):
+def test_select_uneven_list_of_tuples(select_app, monkeypatch):
# 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='2')
- builtins.input = m
+ 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, "play")
expected = normalize("""
@@ -1211,15 +1225,15 @@ Charm us with the {}...
""".format('Drums'))
# Make sure our mock was called with the expected arguments
- m.assert_called_once_with('Instrument? ')
+ read_input_mock.assert_called_once_with('Instrument? ')
# And verify the expected output to stdout
assert out == expected
-def test_select_eof(select_app):
+def test_select_eof(select_app, monkeypatch):
# Ctrl-D during select causes an EOFError that just reprompts the user
- m = mock.MagicMock(name='input', side_effect=[EOFError, 2])
- builtins.input = m
+ read_input_mock = mock.MagicMock(name='read_input', side_effect=[EOFError, 2])
+ monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
food = 'fish'
out, err = run_cmd(select_app, "eat {}".format(food))
@@ -1227,8 +1241,19 @@ def test_select_eof(select_app):
# Make sure our mock was called exactly twice with the expected arguments
arg = 'Sauce? '
calls = [mock.call(arg), mock.call(arg)]
- m.assert_has_calls(calls)
- assert m.call_count == 2
+ 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)
+ monkeypatch.setattr("cmd2.Cmd.read_input", read_input_mock)
+
+ with pytest.raises(KeyboardInterrupt):
+ outsim_app.select([('Guitar', 'Electric Guitar'), ('Drums',)], 'Instrument? ')
+
+ out = outsim_app.stdout.getvalue()
+ assert out.rstrip().endswith('^C')
class HelpNoDocstringApp(cmd2.Cmd):
greet_parser = argparse.ArgumentParser()
@@ -1419,131 +1444,94 @@ def test_echo(capsys):
out, err = capsys.readouterr()
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
- # we dont use decorators because we need m_input for the assertion
- 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(allow_cli_args=False)
- app.use_rawinput = True
- app._cmdloop()
- # because we mocked the input() call, we won't get the prompt
- # or the name of the command in the output, so we can't check
- # if its there. We assume that if input got called twice, once
- # for the 'set' command, and once for the 'quit' command,
- # that the rest of it worked
- assert m_input.call_count == 2
-
-def test_pseudo_raw_input_tty_rawinput_false():
- # gin up some input like it's coming from a tty
- fakein = io.StringIO(u'{}'.format('set\n'))
- mtty = mock.MagicMock(name='isatty', return_value=True)
- fakein.isatty = mtty
- mreadline = mock.MagicMock(name='readline', wraps=fakein.readline)
- fakein.readline = mreadline
-
- # run the cmdloop, telling it where to get input from
- app = cmd2.Cmd(stdin=fakein, allow_cli_args=False)
- app.use_rawinput = False
- app._cmdloop()
-
- # because we mocked the readline() call, we won't get the prompt
- # or the name of the command in the output, so we can't check
- # if its there. We assume that if readline() got called twice, once
- # for the 'set' command, and once for the 'quit' command,
- # that the rest of it worked
- assert mreadline.call_count == 2
-
-# 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(allow_cli_args=False)
- app.use_rawinput = True
- app.echo = echo
- # run the cmdloop, which should pull input from our mock
- app._cmdloop()
- out, err = capsys.readouterr()
- return app, out
-
-# using the decorator puts the original input function back when this unit test returns
-@mock.patch('builtins.input', mock.MagicMock(name='input', side_effect=['set', EOFError]))
-def test_pseudo_raw_input_piped_rawinput_true_echo_true(capsys):
- command = 'set'
- app, out = piped_rawinput_true(capsys, True, command)
- out = out.splitlines()
- assert out[0] == '{}{}'.format(app.prompt, command)
- assert out[1].startswith('allow_ansi:')
-
-# using the decorator puts the original input function back when this unit test returns
-@mock.patch('builtins.input', mock.MagicMock(name='input', side_effect=['set', EOFError]))
-def test_pseudo_raw_input_piped_rawinput_true_echo_false(capsys):
- command = 'set'
- app, out = piped_rawinput_true(capsys, False, command)
- firstline = out.splitlines()[0]
- assert firstline.startswith('allow_ansi:')
- assert not '{}{}'.format(app.prompt, command) in out
-
-# the next helper function and two tests check for piped
-# input when use_rawinput=False
-def piped_rawinput_false(capsys, echo, command):
- fakein = io.StringIO(u'{}'.format(command))
- app = cmd2.Cmd(stdin=fakein, allow_cli_args=False)
- app.use_rawinput = False
- app.echo = echo
- app._cmdloop()
- out, err = capsys.readouterr()
- return app, out
-
-def test_pseudo_raw_input_piped_rawinput_false_echo_true(capsys):
- command = 'set'
- app, out = piped_rawinput_false(capsys, True, command)
- out = out.splitlines()
- assert out[0] == '{}{}'.format(app.prompt, command)
- assert out[1].startswith('allow_ansi:')
+def test_read_input_rawinput_true(capsys, monkeypatch):
+ prompt_str = 'the_prompt'
+ input_str = 'some input'
-def test_pseudo_raw_input_piped_rawinput_false_echo_false(capsys):
- command = 'set'
- app, out = piped_rawinput_false(capsys, False, command)
- firstline = out.splitlines()[0]
- assert firstline.startswith('allow_ansi:')
- assert not '{}{}'.format(app.prompt, command) in out
-
-
-# other input tests
-def test_raw_input(base_app):
- base_app.use_raw_input = True
- fake_input = 'quit'
+ app = cmd2.Cmd()
+ app.use_rawinput = True
- # Mock out the input call so we don't actually wait for a user's response on stdin
- m = mock.Mock(name='input', return_value=fake_input)
- builtins.input = m
+ # Mock out input() to return input_str
+ monkeypatch.setattr("builtins.input", lambda *args: input_str)
- line = base_app._pseudo_raw_input('(cmd2)')
- assert line == fake_input
+ # isatty is True
+ with mock.patch('sys.stdin.isatty', mock.MagicMock(name='isatty', return_value=True)):
+ line = app.read_input(prompt_str)
+ assert line == input_str
+
+ # isatty is False
+ with mock.patch('sys.stdin.isatty', mock.MagicMock(name='isatty', return_value=False)):
+ # echo True
+ app.echo = True
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == input_str
+ assert out == "{}{}\n".format(prompt_str, input_str)
+
+ # echo False
+ app.echo = False
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == input_str
+ assert not out
+
+def test_read_input_rawinput_false(capsys, monkeypatch):
+ prompt_str = 'the_prompt'
+ input_str = 'some input'
+
+ def make_app(isatty: bool, empty_input: bool = False):
+ """Make a cmd2 app with a custom stdin"""
+ app_input_str = '' if empty_input else input_str
+
+ fakein = io.StringIO('{}'.format(app_input_str))
+ fakein.isatty = mock.MagicMock(name='isatty', return_value=isatty)
+
+ new_app = cmd2.Cmd(stdin=fakein)
+ new_app.use_rawinput = False
+ return new_app
+
+ # isatty True
+ app = make_app(isatty=True)
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == input_str
+ assert out == prompt_str
-def test_stdin_input():
- app = cmd2.Cmd()
- app.use_rawinput = False
- fake_input = 'quit'
+ # isatty True, empty input
+ app = make_app(isatty=True, empty_input=True)
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == 'eof'
+ assert out == prompt_str
- # Mock out the readline call so we don't actually read from stdin
- m = mock.Mock(name='readline', return_value=fake_input)
- app.stdin.readline = m
+ # isatty is False, echo is True
+ app = make_app(isatty=False)
+ app.echo = True
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == input_str
+ assert out == "{}{}\n".format(prompt_str, input_str)
- line = app._pseudo_raw_input('(cmd2)')
- assert line == fake_input
+ # isatty is False, echo is False
+ app = make_app(isatty=False)
+ app.echo = False
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == input_str
+ assert not out
-def test_empty_stdin_input():
- app = cmd2.Cmd()
- app.use_rawinput = False
- fake_input = ''
+ # isatty is False, empty input
+ app = make_app(isatty=False, empty_input=True)
+ line = app.read_input(prompt_str)
+ out, err = capsys.readouterr()
+ assert line == 'eof'
+ assert not out
- # Mock out the readline call so we don't actually read from stdin
- m = mock.Mock(name='readline', return_value=fake_input)
- app.stdin.readline = m
+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)
- line = app._pseudo_raw_input('(cmd2)')
+ line = base_app._read_command_line("Prompt> ")
assert line == 'eof'
def test_poutput_string(outsim_app):