Skip to content

Commit f2f9123

Browse files
committed
Added more unit tests for the cmd2.Cmd.select() method
Also - Moved the existing tests for select to a more appropriate location - Minor tweak to working in README for readability
1 parent 0b6edb1 commit f2f9123

3 files changed

Lines changed: 137 additions & 29 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ cmd2
77
[![codecov](https://codecov.io/gh/python-cmd2/cmd2/branch/master/graph/badge.svg)](https://codecov.io/gh/python-cmd2/cmd2)
88
[![License](https://img.shields.io/pypi/l/cmd2.svg)](https://pypi.python.org/pypi/cmd2/)
99

10-
cmd2 is a tool for writing command-line interactive applications for Python 2.7 and Python 3.3+. It is based on the
10+
cmd2 is a tool for writing interactive command-line applications for Python 2.7 and Python 3.3+. It is based on the
1111
Python Standard Library's [cmd](https://docs.python.org/3/library/cmd.html) module, and can be used any place cmd is used simply by importing cmd2 instead. It is
1212
pure Python code with the only 3rd-party dependencies being on [six](https://pypi.python.org/pypi/six), [pyparsing](http://pyparsing.wikispaces.com),
1313
and [pyperclip](https://github.com/asweigart/pyperclip).

tests/test_cmd2.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,3 +813,139 @@ def test_help_overridden_method(help_app):
813813
out = run_cmd(help_app, 'help pause')
814814
expected = normalize('This overrides the pause command and does nothing.')
815815
assert out == expected
816+
817+
818+
class SelectApp(cmd2.Cmd):
819+
def do_eat(self, arg):
820+
"""Eat something, with a selection of sauces to choose from."""
821+
# Pass in a single string of space-separated selections
822+
sauce = self.select('sweet salty', 'Sauce? ')
823+
result = '{food} with {sauce} sauce, yum!'
824+
result = result.format(food=arg, sauce=sauce)
825+
self.stdout.write(result + '\n')
826+
827+
def do_study(self, arg):
828+
"""Learn something, with a selection of subjects to choose from."""
829+
# Pass in a list of strings for selections
830+
subject = self.select(['math', 'science'], 'Subject? ')
831+
result = 'Good luck learning {}!\n'.format(subject)
832+
self.stdout.write(result)
833+
834+
def do_procrastinate(self, arg):
835+
"""Waste time in your manner of choice."""
836+
# Pass in a list of tuples for selections
837+
leisure_activity = self.select([('Netflix and chill', 'Netflix'), ('Porn', 'WebSurfing')],
838+
'How would you like to procrastinate? ')
839+
result = 'Have fun procrasinating with {}!\n'.format(leisure_activity)
840+
self.stdout.write(result)
841+
842+
def do_play(self, arg):
843+
"""Play your favorite musical instrument."""
844+
# Pass in an uneven list of tuples for selections
845+
instrument = self.select([('Guitar', 'Electric Guitar'), ('Drums',)], 'Instrument? ')
846+
result = 'Charm us with the {}...\n'.format(instrument)
847+
self.stdout.write(result)
848+
849+
@pytest.fixture
850+
def select_app():
851+
app = SelectApp()
852+
app.stdout = StdOut()
853+
return app
854+
855+
def test_select_options(select_app):
856+
# Mock out the input call so we don't actually wait for a user's response on stdin
857+
m = mock.MagicMock(name='input', return_value='2')
858+
sm.input = m
859+
860+
food = 'bacon'
861+
out = run_cmd(select_app, "eat {}".format(food))
862+
expected = normalize("""
863+
1. sweet
864+
2. salty
865+
{} with salty sauce, yum!
866+
""".format(food))
867+
868+
# Make sure our mock was called with the expected arguments
869+
m.assert_called_once_with('Sauce? ')
870+
871+
# And verify the expected output to stdout
872+
assert out == expected
873+
874+
def test_select_invalid_option(select_app):
875+
# Mock out the input call so we don't actually wait for a user's response on stdin
876+
m = mock.MagicMock(name='input')
877+
# If side_effect is an iterable then each call to the mock will return the next value from the iterable.
878+
m.side_effect = ['3', '1'] # First pass and invalid selection, then pass a valid one
879+
sm.input = m
880+
881+
food = 'fish'
882+
out = run_cmd(select_app, "eat {}".format(food))
883+
expected = normalize("""
884+
1. sweet
885+
2. salty
886+
3 isn't a valid choice. Pick a number between 1 and 2:
887+
{} with sweet sauce, yum!
888+
""".format(food))
889+
890+
# Make sure our mock was called exactly twice with the expected arguments
891+
arg = 'Sauce? '
892+
calls = [mock.call(arg), mock.call(arg)]
893+
m.assert_has_calls(calls)
894+
895+
# And verify the expected output to stdout
896+
assert out == expected
897+
898+
def test_select_list_of_strings(select_app):
899+
# Mock out the input call so we don't actually wait for a user's response on stdin
900+
m = mock.MagicMock(name='input', return_value='2')
901+
sm.input = m
902+
903+
out = run_cmd(select_app, "study")
904+
expected = normalize("""
905+
1. math
906+
2. science
907+
Good luck learning {}!
908+
""".format('science'))
909+
910+
# Make sure our mock was called with the expected arguments
911+
m.assert_called_once_with('Subject? ')
912+
913+
# And verify the expected output to stdout
914+
assert out == expected
915+
916+
def test_select_list_of_tuples(select_app):
917+
# Mock out the input call so we don't actually wait for a user's response on stdin
918+
m = mock.MagicMock(name='input', return_value='2')
919+
sm.input = m
920+
921+
out = run_cmd(select_app, "procrastinate")
922+
expected = normalize("""
923+
1. Netflix
924+
2. WebSurfing
925+
Have fun procrasinating with {}!
926+
""".format('Porn'))
927+
928+
# Make sure our mock was called with the expected arguments
929+
m.assert_called_once_with('How would you like to procrastinate? ')
930+
931+
# And verify the expected output to stdout
932+
assert out == expected
933+
934+
935+
def test_select_uneven_list_of_tuples(select_app):
936+
# Mock out the input call so we don't actually wait for a user's response on stdin
937+
m = mock.MagicMock(name='input', return_value='2')
938+
sm.input = m
939+
940+
out = run_cmd(select_app, "play")
941+
expected = normalize("""
942+
1. Electric Guitar
943+
2. Drums
944+
Charm us with the {}...
945+
""".format('Drums'))
946+
947+
# Make sure our mock was called with the expected arguments
948+
m.assert_called_once_with('Instrument? ')
949+
950+
# And verify the expected output to stdout
951+
assert out == expected

tests/test_transcript.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,6 @@ def do_hello(self, arg, opts):
6868
else:
6969
self.stdout.write('Hello Nobody\n')
7070

71-
def do_eat(self, arg):
72-
"""Eat something, with a selection of sauces to choose from."""
73-
sauce = self.select('sweet salty', 'Sauce? ')
74-
result = '{food} with {sauce} sauce, yum!'
75-
result = result.format(food=arg, sauce=sauce)
76-
self.stdout.write(result + '\n')
77-
7871

7972
@pytest.fixture
8073
def _cmdline_app():
@@ -240,27 +233,6 @@ def test_commands_at_invocation():
240233
assert out == expected
241234

242235

243-
def test_select_options(_demo_app):
244-
# Mock out the input call so we don't actually wait for a user's response on stdin
245-
m = mock.MagicMock(name='input', return_value='2')
246-
sm.input = m
247-
248-
food = 'bacon'
249-
run_cmd(_demo_app, "set debug true")
250-
out = run_cmd(_demo_app, "eat {}".format(food))
251-
expected = normalize("""
252-
1. sweet
253-
2. salty
254-
{} with salty sauce, yum!
255-
""".format(food))
256-
257-
# Make sure our mock was called with the expected arguments
258-
m.assert_called_once_with('Sauce? ')
259-
260-
# And verify the expected output to stdout
261-
assert out == expected
262-
263-
264236
def test_transcript_from_cmdloop(request, capsys):
265237
# Create a cmd2.Cmd() instance and make sure basic settings are like we want for test
266238
app = CmdLineApp()

0 commit comments

Comments
 (0)