mirror of
				https://github.com/python/cpython.git
				synced 2025-10-27 03:34:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			334 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import sys
 | |
| import unittest
 | |
| 
 | |
| if sys.platform != "win32":
 | |
|     raise unittest.SkipTest("test only relevant on win32")
 | |
| 
 | |
| 
 | |
| import itertools
 | |
| from functools import partial
 | |
| from typing import Iterable
 | |
| from unittest import TestCase
 | |
| from unittest.mock import MagicMock, call
 | |
| 
 | |
| from .support import handle_all_events, code_to_events
 | |
| 
 | |
| try:
 | |
|     from _pyrepl.console import Event, Console
 | |
|     from _pyrepl.windows_console import (
 | |
|         WindowsConsole,
 | |
|         MOVE_LEFT,
 | |
|         MOVE_RIGHT,
 | |
|         MOVE_UP,
 | |
|         MOVE_DOWN,
 | |
|         ERASE_IN_LINE,
 | |
|     )
 | |
| except ImportError:
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class WindowsConsoleTests(TestCase):
 | |
|     def console(self, events, **kwargs) -> Console:
 | |
|         console = WindowsConsole()
 | |
|         console.get_event = MagicMock(side_effect=events)
 | |
|         console._scroll = MagicMock()
 | |
|         console._hide_cursor = MagicMock()
 | |
|         console._show_cursor = MagicMock()
 | |
|         console._getscrollbacksize = MagicMock(42)
 | |
|         console.out = MagicMock()
 | |
| 
 | |
|         height = kwargs.get("height", 25)
 | |
|         width = kwargs.get("width", 80)
 | |
|         console.getheightwidth = MagicMock(side_effect=lambda: (height, width))
 | |
| 
 | |
|         console.prepare()
 | |
|         for key, val in kwargs.items():
 | |
|             setattr(console, key, val)
 | |
|         return console
 | |
| 
 | |
|     def handle_events(self, events: Iterable[Event], **kwargs):
 | |
|         return handle_all_events(events, partial(self.console, **kwargs))
 | |
| 
 | |
|     def handle_events_narrow(self, events):
 | |
|         return self.handle_events(events, width=5)
 | |
| 
 | |
|     def handle_events_short(self, events):
 | |
|         return self.handle_events(events, height=1)
 | |
| 
 | |
|     def handle_events_height_3(self, events):
 | |
|         return self.handle_events(events, height=3)
 | |
| 
 | |
|     def test_simple_addition(self):
 | |
|         code = "12+34"
 | |
|         events = code_to_events(code)
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(b"1")
 | |
|         con.out.write.assert_any_call(b"2")
 | |
|         con.out.write.assert_any_call(b"+")
 | |
|         con.out.write.assert_any_call(b"3")
 | |
|         con.out.write.assert_any_call(b"4")
 | |
|         con.restore()
 | |
| 
 | |
|     def test_wrap(self):
 | |
|         code = "12+34"
 | |
|         events = code_to_events(code)
 | |
|         _, con = self.handle_events_narrow(events)
 | |
|         con.out.write.assert_any_call(b"1")
 | |
|         con.out.write.assert_any_call(b"2")
 | |
|         con.out.write.assert_any_call(b"+")
 | |
|         con.out.write.assert_any_call(b"3")
 | |
|         con.out.write.assert_any_call(b"\\")
 | |
|         con.out.write.assert_any_call(b"\n")
 | |
|         con.out.write.assert_any_call(b"4")
 | |
|         con.restore()
 | |
| 
 | |
|     def test_resize_wider(self):
 | |
|         code = "1234567890"
 | |
|         events = code_to_events(code)
 | |
|         reader, console = self.handle_events_narrow(events)
 | |
| 
 | |
|         console.height = 20
 | |
|         console.width = 80
 | |
|         console.getheightwidth = MagicMock(lambda _: (20, 80))
 | |
| 
 | |
|         def same_reader(_):
 | |
|             return reader
 | |
| 
 | |
|         def same_console(events):
 | |
|             console.get_event = MagicMock(side_effect=events)
 | |
|             return console
 | |
| 
 | |
|         _, con = handle_all_events(
 | |
|             [Event(evt="resize", data=None)],
 | |
|             prepare_reader=same_reader,
 | |
|             prepare_console=same_console,
 | |
|         )
 | |
| 
 | |
|         con.out.write.assert_any_call(self.move_right(2))
 | |
|         con.out.write.assert_any_call(self.move_up(2))
 | |
|         con.out.write.assert_any_call(b"567890")
 | |
| 
 | |
|         con.restore()
 | |
| 
 | |
|     def test_resize_narrower(self):
 | |
|         code = "1234567890"
 | |
|         events = code_to_events(code)
 | |
|         reader, console = self.handle_events(events)
 | |
| 
 | |
|         console.height = 20
 | |
|         console.width = 4
 | |
|         console.getheightwidth = MagicMock(lambda _: (20, 4))
 | |
| 
 | |
|         def same_reader(_):
 | |
|             return reader
 | |
| 
 | |
|         def same_console(events):
 | |
|             console.get_event = MagicMock(side_effect=events)
 | |
|             return console
 | |
| 
 | |
|         _, con = handle_all_events(
 | |
|             [Event(evt="resize", data=None)],
 | |
|             prepare_reader=same_reader,
 | |
|             prepare_console=same_console,
 | |
|         )
 | |
| 
 | |
|         con.out.write.assert_any_call(b"456\\")
 | |
|         con.out.write.assert_any_call(b"789\\")
 | |
| 
 | |
|         con.restore()
 | |
| 
 | |
|     def test_cursor_left(self):
 | |
|         code = "1"
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))],
 | |
|         )
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(self.move_left())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_cursor_left_right(self):
 | |
|         code = "1"
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [
 | |
|                 Event(evt="key", data="left", raw=bytearray(b"\x1bOD")),
 | |
|                 Event(evt="key", data="right", raw=bytearray(b"\x1bOC")),
 | |
|             ],
 | |
|         )
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(self.move_left())
 | |
|         con.out.write.assert_any_call(self.move_right())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_cursor_up(self):
 | |
|         code = "1\n2+3"
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [Event(evt="key", data="up", raw=bytearray(b"\x1bOA"))],
 | |
|         )
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(self.move_up())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_cursor_up_down(self):
 | |
|         code = "1\n2+3"
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [
 | |
|                 Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
 | |
|                 Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
 | |
|             ],
 | |
|         )
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(self.move_up())
 | |
|         con.out.write.assert_any_call(self.move_down())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_cursor_back_write(self):
 | |
|         events = itertools.chain(
 | |
|             code_to_events("1"),
 | |
|             [Event(evt="key", data="left", raw=bytearray(b"\x1bOD"))],
 | |
|             code_to_events("2"),
 | |
|         )
 | |
|         _, con = self.handle_events(events)
 | |
|         con.out.write.assert_any_call(b"1")
 | |
|         con.out.write.assert_any_call(self.move_left())
 | |
|         con.out.write.assert_any_call(b"21")
 | |
|         con.restore()
 | |
| 
 | |
|     def test_multiline_function_move_up_short_terminal(self):
 | |
|         # fmt: off
 | |
|         code = (
 | |
|             "def f():\n"
 | |
|             "  foo"
 | |
|         )
 | |
|         # fmt: on
 | |
| 
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [
 | |
|                 Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
 | |
|                 Event(evt="scroll", data=None),
 | |
|             ],
 | |
|         )
 | |
|         _, con = self.handle_events_short(events)
 | |
|         con.out.write.assert_any_call(self.move_left(5))
 | |
|         con.out.write.assert_any_call(self.move_up())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_multiline_function_move_up_down_short_terminal(self):
 | |
|         # fmt: off
 | |
|         code = (
 | |
|             "def f():\n"
 | |
|             "  foo"
 | |
|         )
 | |
|         # fmt: on
 | |
| 
 | |
|         events = itertools.chain(
 | |
|             code_to_events(code),
 | |
|             [
 | |
|                 Event(evt="key", data="up", raw=bytearray(b"\x1bOA")),
 | |
|                 Event(evt="scroll", data=None),
 | |
|                 Event(evt="key", data="down", raw=bytearray(b"\x1bOB")),
 | |
|                 Event(evt="scroll", data=None),
 | |
|             ],
 | |
|         )
 | |
|         _, con = self.handle_events_short(events)
 | |
|         con.out.write.assert_any_call(self.move_left(8))
 | |
|         con.out.write.assert_any_call(self.erase_in_line())
 | |
|         con.restore()
 | |
| 
 | |
|     def test_resize_bigger_on_multiline_function(self):
 | |
|         # fmt: off
 | |
|         code = (
 | |
|             "def f():\n"
 | |
|             "  foo"
 | |
|         )
 | |
|         # fmt: on
 | |
| 
 | |
|         events = itertools.chain(code_to_events(code))
 | |
|         reader, console = self.handle_events_short(events)
 | |
| 
 | |
|         console.height = 2
 | |
|         console.getheightwidth = MagicMock(lambda _: (2, 80))
 | |
| 
 | |
|         def same_reader(_):
 | |
|             return reader
 | |
| 
 | |
|         def same_console(events):
 | |
|             console.get_event = MagicMock(side_effect=events)
 | |
|             return console
 | |
| 
 | |
|         _, con = handle_all_events(
 | |
|             [Event(evt="resize", data=None)],
 | |
|             prepare_reader=same_reader,
 | |
|             prepare_console=same_console,
 | |
|         )
 | |
|         con.out.write.assert_has_calls(
 | |
|             [
 | |
|                 call(self.move_left(5)),
 | |
|                 call(self.move_up()),
 | |
|                 call(b"def f():"),
 | |
|                 call(self.move_left(3)),
 | |
|                 call(self.move_down()),
 | |
|             ]
 | |
|         )
 | |
|         console.restore()
 | |
|         con.restore()
 | |
| 
 | |
|     def test_resize_smaller_on_multiline_function(self):
 | |
|         # fmt: off
 | |
|         code = (
 | |
|             "def f():\n"
 | |
|             "  foo"
 | |
|         )
 | |
|         # fmt: on
 | |
| 
 | |
|         events = itertools.chain(code_to_events(code))
 | |
|         reader, console = self.handle_events_height_3(events)
 | |
| 
 | |
|         console.height = 1
 | |
|         console.getheightwidth = MagicMock(lambda _: (1, 80))
 | |
| 
 | |
|         def same_reader(_):
 | |
|             return reader
 | |
| 
 | |
|         def same_console(events):
 | |
|             console.get_event = MagicMock(side_effect=events)
 | |
|             return console
 | |
| 
 | |
|         _, con = handle_all_events(
 | |
|             [Event(evt="resize", data=None)],
 | |
|             prepare_reader=same_reader,
 | |
|             prepare_console=same_console,
 | |
|         )
 | |
|         con.out.write.assert_has_calls(
 | |
|             [
 | |
|                 call(self.move_left(5)),
 | |
|                 call(self.move_up()),
 | |
|                 call(self.erase_in_line()),
 | |
|                 call(b"  foo"),
 | |
|             ]
 | |
|         )
 | |
|         console.restore()
 | |
|         con.restore()
 | |
| 
 | |
|     def move_up(self, lines=1):
 | |
|         return MOVE_UP.format(lines).encode("utf8")
 | |
| 
 | |
|     def move_down(self, lines=1):
 | |
|         return MOVE_DOWN.format(lines).encode("utf8")
 | |
| 
 | |
|     def move_left(self, cols=1):
 | |
|         return MOVE_LEFT.format(cols).encode("utf8")
 | |
| 
 | |
|     def move_right(self, cols=1):
 | |
|         return MOVE_RIGHT.format(cols).encode("utf8")
 | |
| 
 | |
|     def erase_in_line(self):
 | |
|         return ERASE_IN_LINE.encode("utf8")
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     unittest.main()
 | 
