Skip to content

Commit 526217d

Browse files
committed
Fixed bug in cmd2.Cmd.select() when user enters 0 or negative number
1 parent 3efb3f1 commit 526217d

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

cmd2/cmd2.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,8 @@ def select(self, opts: Union[str, List[str], List[Tuple[Any, Optional[str]]]], p
27802780

27812781
try:
27822782
choice = int(response)
2783+
if choice < 1:
2784+
raise IndexError
27832785
result = fulloptions[choice - 1][0]
27842786
break
27852787
except (ValueError, IndexError):

tests/test_cmd2.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ def test_select_options(select_app):
13441344
# And verify the expected output to stdout
13451345
assert out == expected
13461346

1347-
def test_select_invalid_option(select_app):
1347+
def test_select_invalid_option_too_big(select_app):
13481348
# Mock out the input call so we don't actually wait for a user's response on stdin
13491349
m = mock.MagicMock(name='input')
13501350
# If side_effect is an iterable then each call to the mock will return the next value from the iterable.
@@ -1368,6 +1368,30 @@ def test_select_invalid_option(select_app):
13681368
# And verify the expected output to stdout
13691369
assert out == expected
13701370

1371+
def test_select_invalid_option_too_small(select_app):
1372+
# Mock out the input call so we don't actually wait for a user's response on stdin
1373+
m = mock.MagicMock(name='input')
1374+
# If side_effect is an iterable then each call to the mock will return the next value from the iterable.
1375+
m.side_effect = ['0', '1'] # First pass and invalid selection, then pass a valid one
1376+
builtins.input = m
1377+
1378+
food = 'fish'
1379+
out = run_cmd(select_app, "eat {}".format(food))
1380+
expected = normalize("""
1381+
1. sweet
1382+
2. salty
1383+
'0' isn't a valid choice. Pick a number between 1 and 2:
1384+
{} with sweet sauce, yum!
1385+
""".format(food))
1386+
1387+
# Make sure our mock was called exactly twice with the expected arguments
1388+
arg = 'Sauce? '
1389+
calls = [mock.call(arg), mock.call(arg)]
1390+
m.assert_has_calls(calls)
1391+
1392+
# And verify the expected output to stdout
1393+
assert out == expected
1394+
13711395
def test_select_list_of_strings(select_app):
13721396
# Mock out the input call so we don't actually wait for a user's response on stdin
13731397
m = mock.MagicMock(name='input', return_value='2')

0 commit comments

Comments
 (0)