Skip to content

Commit

Permalink
Fix signed integers. Make numeric input return 0 if it can't return a…
Browse files Browse the repository at this point in the history
… valid number, for consistency with other SPL implementations
  • Loading branch information
sy-python committed Dec 1, 2024
1 parent 9495ffb commit 5bf4629
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 24 deletions.
20 changes: 17 additions & 3 deletions shakespearelang/_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,39 @@ def consume_numeric_input(self):
try:
self._ensure_input_buffer()
except EOFError:
raise ShakespeareRuntimeError("End of file encountered.") from None
return 0

sign = self._consume_sign_if_present()
number = self._consume_digits()

if number is None:
if sign:
self._input_buffer = sign + self._input_buffer
return 0

self._consume_newline_if_present()

return number
return -number if sign == "-" else number

def _consume_newline_if_present(self):
if self._input_buffer and self._input_buffer[0] == "\n":
self._input_buffer = self._input_buffer[1:]

def _consume_sign_if_present(self):
if self._input_buffer and (sign := self._input_buffer[0]) in ["+", "-"]:
self._input_buffer = self._input_buffer[1:]
return sign

return ""

def _consume_digits(self):
number_input = ""
while self._input_buffer and self._input_buffer[0].isdigit():
number_input += self._input_buffer[0]
self._input_buffer = self._input_buffer[1:]

if len(number_input) == 0:
raise ShakespeareRuntimeError("No numeric input was given.")
return None

return int(number_input)

Expand Down
41 changes: 20 additions & 21 deletions shakespearelang/tests/test_numeric_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ def test_correctly_parses_number(monkeypatch, capsys):
s.run_event("[Enter Romeo and Juliet]")
s.run_sentence("Listen to your heart!", "Juliet")
assert s.state.character_by_name("Romeo").value == 4257

monkeypatch.setattr("sys.stdin", StringIO("-3211"))
s = Shakespeare("Foo. Juliet, a test. Romeo, a test.")
s.run_event("[Enter Romeo and Juliet]")
s.run_sentence("Listen to your heart!", "Juliet")
assert s.state.character_by_name("Romeo").value == -3211

monkeypatch.setattr("sys.stdin", StringIO("+2"))
s = Shakespeare("Foo. Juliet, a test. Romeo, a test.")
s.run_event("[Enter Romeo and Juliet]")
s.run_sentence("Listen to your heart!", "Juliet")
assert s.state.character_by_name("Romeo").value == 2

captured = capsys.readouterr()
assert captured.out == ""
assert captured.err == ""
Expand Down Expand Up @@ -42,39 +55,24 @@ def test_consumes_trailing_newline(monkeypatch, capsys):
assert s.state.character_by_name("Romeo").value == -1


def test_errors_without_digits(monkeypatch, capsys):
def test_no_digits_consumed(monkeypatch, capsys):
monkeypatch.setattr("sys.stdin", StringIO("a123"))
s = Shakespeare("Foo. Juliet, a test. Romeo, a test.")
s.run_event("[Enter Romeo and Juliet]")

with pytest.raises(ShakespeareRuntimeError) as exc:
s.run_sentence("Listen to your heart!", "Juliet")
assert "no numeric input" in str(exc.value).lower()
assert ">>Listen to your heart!<<" in str(exc.value)
assert exc.value.interpreter == s
assert s.state.character_by_name("Romeo").value == 0

monkeypatch.setattr("sys.stdin", StringIO("a123"))
with pytest.raises(ShakespeareRuntimeError) as exc:
s.run_sentence("Listen to your heart!", "Juliet")
assert "no numeric input" in str(exc.value).lower()
assert ">>Listen to your heart!<<" in str(exc.value)
assert exc.value.interpreter == s
s.state.character_by_name("Romeo").value = 24
s.run_sentence("Listen to your heart!", "Juliet")
assert s.state.character_by_name("Romeo").value == 0
captured = capsys.readouterr()
assert captured.out == ""
assert captured.err == ""


def test_errors_on_eof(monkeypatch, capsys):
def test_eof(monkeypatch, capsys):
monkeypatch.setattr("sys.stdin", StringIO(""))
s = Shakespeare("Foo. Juliet, a test. Romeo, a test.")
s.run_event("[Enter Romeo and Juliet]")
with pytest.raises(ShakespeareRuntimeError) as exc:
s.run_sentence("Listen to your heart!", "Juliet")
assert "end of file" in str(exc.value).lower()
assert ">>Listen to your heart!<<" in str(exc.value)
assert exc.value.interpreter == s
s.state.character_by_name("Romeo").value = 42
s.run_sentence("Listen to your heart!", "Juliet")
assert s.state.character_by_name("Romeo").value == 0
captured = capsys.readouterr()
assert captured.out == ""
Expand Down Expand Up @@ -106,6 +104,7 @@ def test_conditional(monkeypatch, capsys):
assert captured.out == ""
assert captured.err == ""


def test_interactive_style(monkeypatch, capsys):
monkeypatch.setattr("sys.stdin", StringIO("4257\n3211"))
s = Shakespeare("Foo. Juliet, a test. Romeo, a test.", input_style="interactive")
Expand Down

0 comments on commit 5bf4629

Please sign in to comment.