Skip to content

Commit d0dc732

Browse files
committed
Add more tests for Ctrl+D behavior of pyrep in multiline mode
1 parent cfd5a68 commit d0dc732

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

Lib/test/test_pyrepl/test_pyrepl.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,16 @@ def test_detect_pip_usage_in_repl(self):
17681768
" outside of the Python REPL"
17691769
)
17701770
self.assertIn(hint, output)
1771+
17711772
class TestPyReplCtrlD(TestCase):
1773+
"""Test Ctrl+D behavior in _pyrepl to match old pre-3.13 REPL behavior.
1774+
1775+
Ctrl+D should:
1776+
- Exit on empty buffer
1777+
- Delete character when cursor is in middle of line
1778+
- Perform no operation when cursor is at end of line without newline
1779+
- Exit multiline mode when cursor is at end with trailing newline
1780+
"""
17721781
def prepare_reader(self, events):
17731782
console = FakeConsole(events)
17741783
config = ReadlineConfig(readline_completer=None)
@@ -1784,17 +1793,44 @@ def test_ctrl_d_empty_buffer(self):
17841793
with self.assertRaises(EOFError):
17851794
multiline_input(reader)
17861795

1787-
def test_ctrl_d_multiline_mode(self):
1788-
"""Test that pressing Ctrl+D in multiline mode exits multiline mode"""
1796+
def test_ctrl_d_multiline_with_new_line(self):
1797+
"""Test that pressing Ctrl+D in multiline mode with trailing newline exits multiline mode"""
17891798
events = itertools.chain(
1790-
code_to_events("def f():\n"), # Enter multiline mode
1799+
code_to_events("def f():\n pass\n"), # Enter multiline mode with trailing newline
17911800
[
17921801
Event(evt="key", data="\x04", raw=bytearray(b"\x04")), # Ctrl+D
17931802
],
17941803
)
1795-
reader = self.prepare_reader(events)
1796-
output = multiline_input(reader)
1797-
self.assertEqual(output, "def f():\n ") # Should return current input
1804+
reader, _ = handle_all_events(events)
1805+
self.assertTrue(reader.finished)
1806+
self.assertEqual("def f():\n pass\n", "".join(reader.buffer))
1807+
1808+
def test_ctrl_d_multiline_middle_of_line(self):
1809+
"""Test that pressing Ctrl+D in multiline mode with cursor in middle deletes character"""
1810+
events = itertools.chain(
1811+
code_to_events("def f():\n hello world"), # Enter multiline mode
1812+
[
1813+
Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))
1814+
] * 5, # move cursor to 'w' in "world"
1815+
[
1816+
Event(evt="key", data="\x04", raw=bytearray(b"\x04"))
1817+
], # Ctrl+D should delete 'w'
1818+
)
1819+
reader, _ = handle_all_events(events)
1820+
self.assertFalse(reader.finished)
1821+
self.assertEqual("def f():\n hello orld", "".join(reader.buffer))
1822+
1823+
def test_ctrl_d_multiline_end_of_line_no_newline(self):
1824+
"""Test that pressing Ctrl+D at end of line without newline performs no operation"""
1825+
events = itertools.chain(
1826+
code_to_events("def f():\n hello"), # Enter multiline mode, no trailing newline
1827+
[
1828+
Event(evt="key", data="\x04", raw=bytearray(b"\x04"))
1829+
], # Ctrl+D should be no-op
1830+
)
1831+
reader, _ = handle_all_events(events)
1832+
self.assertFalse(reader.finished)
1833+
self.assertEqual("def f():\n hello", "".join(reader.buffer))
17981834

17991835
def test_ctrl_d_single_line(self):
18001836
"""Test that pressing Ctrl+D in single line mode deletes current character"""
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
Fixed Ctrl+D (^D) behavior in _pyrepl module: Now properly exits multiline
2-
mode when pressed in multiline section. Added test cases to verify the
3-
behavior in both multiline and single line modes.
1+
Fixed Ctrl+D (^D) behavior in _pyrepl module to match old pre-3.13 REPL behavior.

0 commit comments

Comments
 (0)