8000 gh-111201: Add tests for unix console class in pyrepl (#118653) · python/cpython@fe92193 · GitHub
[go: up one dir, main page]

Skip to content
Sign in

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fe92193

Browse files
authored
gh-111201: Add tests for unix console class in pyrepl (#118653)
1 parent 9257731 commit fe92193

File tree

1 file changed

+290
-2
lines changed

1 file changed

+290
-2
lines changed

Lib/test/test_pyrepl.py

Lines changed: 290 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from code import InteractiveConsole
88
from functools import partial
99
from unittest import TestCase
10-
from unittest.mock import MagicMock, patch
10+
from unittest.mock import MagicMock, call, patch, ANY
1111

1212
from test.support import requires
1313
from test.support.import_helper import import_module
@@ -22,6 +22,7 @@
2222
from _pyrepl.console import Console, Event
2323
from _pyrepl.readline import ReadlineAlikeReader, ReadlineConfig
2424
from _pyrepl.simple_interact import _strip_final_indent
25+
from _pyrepl.unix_console import UnixConsole
2526
from _pyrepl.unix_eventqueue import EventQueue
2627
from _pyrepl.input import KeymapTranslator
2728
from _pyrepl.keymap import parse_keys, compile_keymap
@@ -105,7 +106,8 @@ def handle_all_events(
105106

106107

107108
handle_events_narrow_console = partial(
108-
handle_all_events, prepare_console=partial(prepare_mock_console, width=10)
109+
handle_all_events,
110+
prepare_console=partial(prepare_mock_console, width=10),
109111
)
110112

111113

@@ -1198,5 +1200,291 @@ def test_nested_multiple_keymaps(self):
11981200
self.assertEqual(result, {b"a": {b"b": {b"c": "action"}}})
11991201

12001202

1203+
def unix_console(events, **kwargs):
1204+
console = UnixConsole()
1205+
console.get_event = MagicMock(side_effect=events)
1206+
1207+
height = kwargs.get("height", 25)
1208+
width = kwargs.get("width", 80)
1209+
console.getheightwidth = MagicMock(side_effect=lambda: (height, width))
1210+
1211+
console.prepare()
1212+
for key, val in kwargs.items():
1213+
setattr(console, key, val)
1214+
return console
1215+
1216+
1217+
handle_events_unix_console = partial(
1218+
handle_all_events,
1219+
prepare_console=partial(unix_console),
1220+
)
1221+
handle_events_narrow_unix_console = partial(
1222+
handle_all_events,
1223+
prepare_console=partial(unix_console, width=5),
1224+
)
1225+
handle_events_short_unix_console = partial(
1226+
handle_all_events,
1227+
prepare_console=partial(unix_console, height=1),
1228+
)
1229+
handle_events_unix_console_height_3 = partial(
1230+
handle_all_events, prepare_console=partial(unix_console, height=3)
1231+
)
1232+
1233+
1234+
TERM_CAPABILITIES = {
1235+
"bel": b"\x07",
1236+
"civis": b"\x1b[?25l",
1237+
"clear": b"\x1b[H\x1b[2J",
1238+
"cnorm": b"\x1b[?12l\x1b[?25h",
1239+
"cub": b"\x1b[%p1%dD",
1240+
"cub1": b"\x08",
1241+
"cud": b"\x1b[%p1%dB",
1242+
"cud1": b"\n",
1243+
"cuf": b"\x1b[%p1%dC",
1244+
"cuf1": b"\x1b[C",
1245+
"cup": b"\x1b[%i%p1%d;%p2%dH",
1246+
"cuu": b"\x1b[%p1%dA",
1247+
"cuu1": b"\x1b[A",
1248+
"dch1": b"\x1b[P",
1249+
"dch": b"\x1b[%p1%dP",
1250+
"el": b"\x1b[K",
1251+
"hpa": b"\x1b[%i%p1%dG",
1252+
"ich": b"\x1b[%p1%d@",
1253+
"ich1": None,
1254+
"ind": b"\n",
1255+
"pad": None,
1256+
"ri": b"\x1bM",
1257+
"rmkx": b"\x1b[?1l\x1b>",
1258+
"smkx": b"\x1b[?1h\x1b=",
1259+
}
1260+
1261+
1262+
@patch("_pyrepl.curses.tigetstr", lambda s: TERM_CAPABILITIES.get(s))
1263+
@patch(
1264+
"_pyrepl.curses.tparm",
1265+
lambda s, *args: s + b":" + b",".join(str(i).encode() for i in args),
1266+
)
1267+
@patch("_pyrepl.curses.setupterm", lambda a, b: None)
1268+
@patch(
1269+
"termios.tcgetattr",
1270+
lambda _: [
1271+
27394,
1272+
3,
1273+
19200,
1274+
536872399,
1275+
38400,
1276+
38400,
1277+
[
1278+
b"\x04",
1279+
b"\xff",
1280+
b"\xff",
1281+
b"\x7f",
1282+
b"\x17",
1283+
b"\x15",
1284+
b"\x12",
1285+
b"\x00",
1286+
b"\x03",
1287+
b"\x1c",
1288+
b"\x1a",
1289+
b"\x19",
1290+
b"\x11",
1291+
b"\x13",
1292+
b"\x16",
1293+
b"\x0f",
1294+
b"\x01",
1295+
b"\x00",
1296+
b"\x14",
1297+
b"\x00",
1298+
],
1299+
],
1300+
)
1301+
@patch("termios.tcsetattr", lambda a, b, c: None)
1302+
@patch("os.write")
1303+
class TestConsole(TestCase):
1304+
def test_simple_addition(self, _os_write):
1305+
code = "12+34"
1306+
events = code_to_events(code)
1307+
_, _ = handle_events_unix_console(events)
1308+
_os_write.assert_any_call(ANY, b"1")
1309+
_os_write.assert_any_call(ANY, b"2")
1310+
_os_write.assert_any_call(ANY, b"+")
1311+
_os_write.assert_any_call(ANY, b"3")
1312+
_os_write.assert_any_call(ANY, b"4")
1313+
1314+
def test_wrap(self, _os_write):
1315+
code = "12+34"
1316+
events = code_to_events(code)
1317+
_, _ = handle_events_narrow_unix_console(events)
1318+
_os_write.assert_any_call(ANY, b"1")
1319+
_os_write.assert_any_call(ANY, b"2")
1320+
_os_write.assert_any_call(ANY, b"+")
1321+
_os_write.assert_any_call(ANY, b"3")
1322+
_os_write.assert_any_call(ANY, b"\\")
1323+
_os_write.assert_any_call(ANY, b"\n")
1324+
_os_write.assert_any_call(ANY, b"4")
1325+
1326+
def test_cursor_left(self, _os_write):
1327+
code = "1"
1328+
events = itertools.chain(
1329+
code_to_events(code),
1330+
[Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))],
1331+
)
1332+
_, _ = handle_events_unix_console(events)
1333+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cub"] + b":1")
1334+
1335+
def test_cursor_left_right(self, _os_write):
1336+
code = "1"
1337+
events = itertools.chain(
1338+
code_to_events(code),
1339+
[
1340+
Event(evt="key", data="left", raw=bytearray(b"\x1bOD")),
1341+
Event(evt="key", data="right", raw=bytearray(b"\x1bOC")),
1342+
],
1343+
)
1344+
_, _ = handle_events_unix_console(events)
1345+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cub"] + b":1")
1346+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cuf"] + b":1")
1347+
1348+
def test_cursor_up(self, _os_write):
1349+
code = "1\n2+3"
1350+
events = itertools.chain(
1351+
code_to_events(code),
1352+
[Event(evt="key", data="up", raw=bytearray(b"\x1bOA"))],
1353+
)
1354+
_, _ = handle_events_unix_console(events)
1355+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cuu"] + b":1")
1356+
1357+
def test_cursor_up_down(self, _os_write):
1358+
code = "1\n2+3"
1359+
events = itertools.chain(
1360+
code_to_events(code),
1361+
[
1362+
Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
1363+
Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
1364+
],
1365+
)
1366+
_, _ = handle_events_unix_console(events)
1367+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cuu"] + b":1")
1368+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cud"] + b":1")
1369+
1370+
def test_cursor_back_write(self, _os_write):
1371+
events = itertools.chain(
1372+
code_to_events("1"),
1373+
[Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))],
1374+
code_to_events("2"),
1375+
)
1376+
_, _ = handle_events_unix_console(events)
1377+
_os_write.assert_any_call(ANY, b"1")
1378+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["cub"] + b":1")
1379+
_os_write.assert_any_call(ANY, b"2")
1380+
1381+
def test_multiline_function_move_up_short_terminal(self, _os_write):
1382+
# fmt: off
1383+
code = (
1384+
"def f():\n"
1385+
" foo"
1386+
)
1387+
# fmt: on
1388+
1389+
events = itertools.chain(
1390+
code_to_events(code),
1391+
[
1392+
Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
1393+
Event(evt="scroll", data=None),
1394+
],
1395+
)
1396+
_, _ = handle_events_short_unix_console(events)
1397+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["ri"] + b":")
1398+
1399+
def test_multiline_function_move_up_down_short_terminal(self, _os_write):
1400+
# fmt: off
1401+
code = (
1402+
"def f():\n"
1403+
" foo"
1404+
)
1405+
# fmt: on
1406+
1407+
events = itertools.chain(
1408+
code_to_events(code),
1409+
[
1410+
Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
1411+
Event(evt="scroll", data=None),
1412+
Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
1413+
Event(evt="scroll", data=None),
1414+
],
1415+
)
1416+
_, _ = handle_events_short_unix_console(events)
1417+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["ri"] + b":")
1418+
_os_write.assert_any_call(ANY, TERM_CAPABILITIES["ind"] + b":")
1419+
1420+
def test_resize_bigger_on_multiline_function(self, _os_write):
1421+
# fmt: off
1422+
code = (
1423+
"def f():\n"
1424+
" foo"
1425+
)
1426+
# fmt: on
1427+
1428+
events = itertools.chain(code_to_events(code))
1429+
reader, console = handle_events_short_unix_console(events)
1430+
1431+
console.height = 2
1432+
console.getheightwidth = MagicMock(lambda _: (2, 80))
1433+
1434+
def same_reader(_):
1435+
return reader
1436+
1437+
def same_console(events):
1438+
console.get_event = MagicMock(side_effect=events)
1439+
return console
1440+
1441+
_, _ = handle_all_events(
1442+
[Event(evt="resize", data=None)],
1443+
prepare_reader=same_reader,
1444+
prepare_console=same_console,
1445+
)
1446+
_os_write.assert_has_calls(
1447+
[
1448+
call(ANY, TERM_CAPABILITIES["ri"] + b":"),
1449+
call(ANY, TERM_CAPABILITIES["cup"] + b":0,0"),
1450+
call(ANY, b"def f():"),
1451+
]
1452+
)
1453+
1454+
def test_resize_smaller_on_multiline_function(self, _os_write):
1455+
# fmt: off
1456+
code = (
1457+
"def f():\n"
1458+
" foo"
1459+
)
1460+
# fmt: on
1461+
1462+
events = itertools.chain(code_to_events(code))
1463+
reader, console = handle_events_unix_console_height_3(events)
1464+
1465+
console.height = 1
1466+
console.getheightwidth = MagicMock(lambda _: (1, 80))
1467+
1468+
def same_reader(_):
1469+
return reader
1470+
1471+
def same_console(events):
1472+
console.get_event = MagicMock(side_effect=events)
1473 ACFB +
return console
1474+
1475+
_, _ = handle_all_events(
1476+
[Event(evt="resize", data=None)],
1477+
prepare_reader=same_reader,
1478+
prepare_console=same_console,
1479+
)
1480+
_os_write.assert_has_calls(
1481+
[
1482+
call(ANY, TERM_CAPABILITIES["ind"] + b":"),
1483+
call(ANY, TERM_CAPABILITIES["cup"] + b":0,0"),
1484+
call(ANY, b" foo"),
1485+
]
1486+
)
1487+
1488+
12011489
if __name__ == "__main__":
12021490
unittest.main()

0 commit comments

Comments
 (0)
0