aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py2/tests
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/python/prompt-toolkit/py2/tests
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/python/prompt-toolkit/py2/tests')
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_buffer.py111
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_cli.py629
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_contrib.py254
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_document.py74
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_filter.py168
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_inputstream.py142
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_key_binding.py140
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_layout.py60
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py50
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py110
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py50
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_style.py40
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_utils.py39
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py85
-rw-r--r--contrib/python/prompt-toolkit/py2/tests/ya.make28
15 files changed, 1980 insertions, 0 deletions
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_buffer.py b/contrib/python/prompt-toolkit/py2/tests/test_buffer.py
new file mode 100644
index 00000000000..a9cff190240
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_buffer.py
@@ -0,0 +1,111 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.buffer import Buffer
+
+import pytest
+
+
+@pytest.fixture
+def _buffer():
+ return Buffer()
+
+
+def test_initial(_buffer):
+ assert _buffer.text == ''
+ assert _buffer.cursor_position == 0
+
+
+def test_insert_text(_buffer):
+ _buffer.insert_text('some_text')
+ assert _buffer.text == 'some_text'
+ assert _buffer.cursor_position == len('some_text')
+
+
+def test_cursor_movement(_buffer):
+ _buffer.insert_text('some_text')
+ _buffer.cursor_left()
+ _buffer.cursor_left()
+ _buffer.cursor_left()
+ _buffer.cursor_right()
+ _buffer.insert_text('A')
+
+ assert _buffer.text == 'some_teAxt'
+ assert _buffer.cursor_position == len('some_teA')
+
+
+def test_backspace(_buffer):
+ _buffer.insert_text('some_text')
+ _buffer.cursor_left()
+ _buffer.cursor_left()
+ _buffer.delete_before_cursor()
+
+ assert _buffer.text == 'some_txt'
+ assert _buffer.cursor_position == len('some_t')
+
+
+def test_cursor_up(_buffer):
+ # Cursor up to a line thats longer.
+ _buffer.insert_text('long line1\nline2')
+ _buffer.cursor_up()
+
+ assert _buffer.document.cursor_position == 5
+
+ # Going up when already at the top.
+ _buffer.cursor_up()
+ assert _buffer.document.cursor_position == 5
+
+ # Going up to a line that's shorter.
+ _buffer.reset()
+ _buffer.insert_text('line1\nlong line2')
+
+ _buffer.cursor_up()
+ assert _buffer.document.cursor_position == 5
+
+
+def test_cursor_down(_buffer):
+ _buffer.insert_text('line1\nline2')
+ _buffer.cursor_position = 3
+
+ # Normally going down
+ _buffer.cursor_down()
+ assert _buffer.document.cursor_position == len('line1\nlin')
+
+ # Going down to a line that's storter.
+ _buffer.reset()
+ _buffer.insert_text('long line1\na\nb')
+ _buffer.cursor_position = 3
+
+ _buffer.cursor_down()
+ assert _buffer.document.cursor_position == len('long line1\na')
+
+
+def test_join_next_line(_buffer):
+ _buffer.insert_text('line1\nline2\nline3')
+ _buffer.cursor_up()
+ _buffer.join_next_line()
+
+ assert _buffer.text == 'line1\nline2 line3'
+
+ # Test when there is no '\n' in the text
+ _buffer.reset()
+ _buffer.insert_text('line1')
+ _buffer.cursor_position = 0
+ _buffer.join_next_line()
+
+ assert _buffer.text == 'line1'
+
+
+def test_newline(_buffer):
+ _buffer.insert_text('hello world')
+ _buffer.newline()
+
+ assert _buffer.text == 'hello world\n'
+
+
+def test_swap_characters_before_cursor(_buffer):
+ _buffer.insert_text('hello world')
+ _buffer.cursor_left()
+ _buffer.cursor_left()
+ _buffer.swap_characters_before_cursor()
+
+ assert _buffer.text == 'hello wrold'
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_cli.py b/contrib/python/prompt-toolkit/py2/tests/test_cli.py
new file mode 100644
index 00000000000..68ca3d03f05
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_cli.py
@@ -0,0 +1,629 @@
+# encoding: utf-8
+"""
+These are almost end-to-end tests. They create a CommandLineInterface
+instance, feed it with some input and check the result.
+"""
+from __future__ import unicode_literals
+from prompt_toolkit.application import Application
+from prompt_toolkit.buffer import Buffer, AcceptAction
+from prompt_toolkit.clipboard import InMemoryClipboard, ClipboardData
+from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
+from prompt_toolkit.eventloop.posix import PosixEventLoop
+from prompt_toolkit.history import InMemoryHistory
+from prompt_toolkit.input import PipeInput
+from prompt_toolkit.interface import CommandLineInterface
+from prompt_toolkit.key_binding.manager import KeyBindingManager
+from prompt_toolkit.output import DummyOutput
+from prompt_toolkit.terminal.vt100_input import ANSI_SEQUENCES
+from functools import partial
+import pytest
+
+
+def _history():
+ h = InMemoryHistory()
+ h.append('line1 first input')
+ h.append('line2 second input')
+ h.append('line3 third input')
+ return h
+
+
+def _feed_cli_with_input(text, editing_mode=EditingMode.EMACS, clipboard=None,
+ history=None, multiline=False, check_line_ending=True,
+ pre_run_callback=None):
+ """
+ Create a CommandLineInterface, feed it with the given user input and return
+ the CLI object.
+
+ This returns a (result, CLI) tuple.
+ """
+ # If the given text doesn't end with a newline, the interface won't finish.
+ if check_line_ending:
+ assert text.endswith('\n')
+
+ loop = PosixEventLoop()
+ try:
+ inp = PipeInput()
+ inp.send_text(text)
+ cli = CommandLineInterface(
+ application=Application(
+ buffer=Buffer(accept_action=AcceptAction.RETURN_DOCUMENT,
+ history=history, is_multiline=multiline),
+ editing_mode=editing_mode,
+ clipboard=clipboard or InMemoryClipboard(),
+ key_bindings_registry=KeyBindingManager.for_prompt().registry,
+ ),
+ eventloop=loop,
+ input=inp,
+ output=DummyOutput())
+
+ if pre_run_callback:
+ pre_run_callback(cli)
+
+ result = cli.run()
+ return result, cli
+ finally:
+ loop.close()
+ inp.close()
+
+
+def test_simple_text_input():
+ # Simple text input, followed by enter.
+ result, cli = _feed_cli_with_input('hello\n')
+ assert result.text == 'hello'
+ assert cli.buffers[DEFAULT_BUFFER].text == 'hello'
+
+
+def test_emacs_cursor_movements():
+ """
+ Test cursor movements with Emacs key bindings.
+ """
+ # ControlA (beginning-of-line)
+ result, cli = _feed_cli_with_input('hello\x01X\n')
+ assert result.text == 'Xhello'
+
+ # ControlE (end-of-line)
+ result, cli = _feed_cli_with_input('hello\x01X\x05Y\n')
+ assert result.text == 'XhelloY'
+
+ # ControlH or \b
+ result, cli = _feed_cli_with_input('hello\x08X\n')
+ assert result.text == 'hellX'
+
+ # Delete. (Left, left, delete)
+ result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x1b[3~\n')
+ assert result.text == 'helo'
+
+ # Left.
+ result, cli = _feed_cli_with_input('hello\x1b[DX\n')
+ assert result.text == 'hellXo'
+
+ # ControlA, right
+ result, cli = _feed_cli_with_input('hello\x01\x1b[CX\n')
+ assert result.text == 'hXello'
+
+ # ControlA, right
+ result, cli = _feed_cli_with_input('hello\x01\x1b[CX\n')
+ assert result.text == 'hXello'
+
+ # ControlB (backward-char)
+ result, cli = _feed_cli_with_input('hello\x02X\n')
+ assert result.text == 'hellXo'
+
+ # ControlF (forward-char)
+ result, cli = _feed_cli_with_input('hello\x01\x06X\n')
+ assert result.text == 'hXello'
+
+ # ControlC: raise KeyboardInterrupt.
+ with pytest.raises(KeyboardInterrupt):
+ result, cli = _feed_cli_with_input('hello\x03\n')
+ assert result.text == 'hello'
+
+ # ControlD without any input: raises EOFError.
+ with pytest.raises(EOFError):
+ result, cli = _feed_cli_with_input('\x04\n')
+ assert result.text == 'hello'
+
+ # ControlD: delete after cursor.
+ result, cli = _feed_cli_with_input('hello\x01\x04\n')
+ assert result.text == 'ello'
+
+ # ControlD at the end of the input ssshould not do anything.
+ result, cli = _feed_cli_with_input('hello\x04\n')
+ assert result.text == 'hello'
+
+ # Left, Left, ControlK (kill-line)
+ result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x0b\n')
+ assert result.text == 'hel'
+
+ # Left, Left Esc- ControlK (kill-line, but negative)
+ result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x1b-\x0b\n')
+ assert result.text == 'lo'
+
+ # ControlL: should not influence the result.
+ result, cli = _feed_cli_with_input('hello\x0c\n')
+ assert result.text == 'hello'
+
+ # ControlRight (forward-word)
+ result, cli = _feed_cli_with_input('hello world\x01X\x1b[1;5CY\n')
+ assert result.text == 'XhelloY world'
+
+ # ContrlolLeft (backward-word)
+ result, cli = _feed_cli_with_input('hello world\x1b[1;5DY\n')
+ assert result.text == 'hello Yworld'
+
+ # <esc>-f with argument. (forward-word)
+ result, cli = _feed_cli_with_input('hello world abc def\x01\x1b3\x1bfX\n')
+ assert result.text == 'hello world abcX def'
+
+ # <esc>-f with negative argument. (forward-word)
+ result, cli = _feed_cli_with_input('hello world abc def\x1b-\x1b3\x1bfX\n')
+ assert result.text == 'hello Xworld abc def'
+
+ # <esc>-b with argument. (backward-word)
+ result, cli = _feed_cli_with_input('hello world abc def\x1b3\x1bbX\n')
+ assert result.text == 'hello Xworld abc def'
+
+ # <esc>-b with negative argument. (backward-word)
+ result, cli = _feed_cli_with_input('hello world abc def\x01\x1b-\x1b3\x1bbX\n')
+ assert result.text == 'hello world abc Xdef'
+
+ # ControlW (kill-word / unix-word-rubout)
+ result, cli = _feed_cli_with_input('hello world\x17\n')
+ assert result.text == 'hello '
+ assert cli.clipboard.get_data().text == 'world'
+
+ result, cli = _feed_cli_with_input('test hello world\x1b2\x17\n')
+ assert result.text == 'test '
+
+ # Escape Backspace (unix-word-rubout)
+ result, cli = _feed_cli_with_input('hello world\x1b\x7f\n')
+ assert result.text == 'hello '
+ assert cli.clipboard.get_data().text == 'world'
+
+ result, cli = _feed_cli_with_input('hello world\x1b\x08\n')
+ assert result.text == 'hello '
+ assert cli.clipboard.get_data().text == 'world'
+
+ # Backspace (backward-delete-char)
+ result, cli = _feed_cli_with_input('hello world\x7f\n')
+ assert result.text == 'hello worl'
+ assert result.cursor_position == len('hello worl')
+
+ result, cli = _feed_cli_with_input('hello world\x08\n')
+ assert result.text == 'hello worl'
+ assert result.cursor_position == len('hello worl')
+
+ # Delete (delete-char)
+ result, cli = _feed_cli_with_input('hello world\x01\x1b[3~\n')
+ assert result.text == 'ello world'
+ assert result.cursor_position == 0
+
+ # Escape-\\ (delete-horizontal-space)
+ result, cli = _feed_cli_with_input('hello world\x1b8\x02\x1b\\\n')
+ assert result.text == 'helloworld'
+ assert result.cursor_position == len('hello')
+
+
+def test_emacs_yank():
+ # ControlY (yank)
+ c = InMemoryClipboard(ClipboardData('XYZ'))
+ result, cli = _feed_cli_with_input('hello\x02\x19\n', clipboard=c)
+ assert result.text == 'hellXYZo'
+ assert result.cursor_position == len('hellXYZ')
+
+
+def test_quoted_insert():
+ # ControlQ - ControlB (quoted-insert)
+ result, cli = _feed_cli_with_input('hello\x11\x02\n')
+ assert result.text == 'hello\x02'
+
+
+def test_transformations():
+ # Meta-c (capitalize-word)
+ result, cli = _feed_cli_with_input('hello world\01\x1bc\n')
+ assert result.text == 'Hello world'
+ assert result.cursor_position == len('Hello')
+
+ # Meta-u (uppercase-word)
+ result, cli = _feed_cli_with_input('hello world\01\x1bu\n')
+ assert result.text == 'HELLO world'
+ assert result.cursor_position == len('Hello')
+
+ # Meta-u (downcase-word)
+ result, cli = _feed_cli_with_input('HELLO WORLD\01\x1bl\n')
+ assert result.text == 'hello WORLD'
+ assert result.cursor_position == len('Hello')
+
+ # ControlT (transpose-chars)
+ result, cli = _feed_cli_with_input('hello\x14\n')
+ assert result.text == 'helol'
+ assert result.cursor_position == len('hello')
+
+ # Left, Left, Control-T (transpose-chars)
+ result, cli = _feed_cli_with_input('abcde\x1b[D\x1b[D\x14\n')
+ assert result.text == 'abdce'
+ assert result.cursor_position == len('abcd')
+
+
+def test_emacs_other_bindings():
+ # Transpose characters.
+ result, cli = _feed_cli_with_input('abcde\x14X\n') # Ctrl-T
+ assert result.text == 'abcedX'
+
+ # Left, Left, Transpose. (This is slightly different.)
+ result, cli = _feed_cli_with_input('abcde\x1b[D\x1b[D\x14X\n')
+ assert result.text == 'abdcXe'
+
+ # Clear before cursor.
+ result, cli = _feed_cli_with_input('hello\x1b[D\x1b[D\x15X\n')
+ assert result.text == 'Xlo'
+
+ # unix-word-rubout: delete word before the cursor.
+ # (ControlW).
+ result, cli = _feed_cli_with_input('hello world test\x17X\n')
+ assert result.text == 'hello world X'
+
+ result, cli = _feed_cli_with_input('hello world /some/very/long/path\x17X\n')
+ assert result.text == 'hello world X'
+
+ # (with argument.)
+ result, cli = _feed_cli_with_input('hello world test\x1b2\x17X\n')
+ assert result.text == 'hello X'
+
+ result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b2\x17X\n')
+ assert result.text == 'hello X'
+
+ # backward-kill-word: delete word before the cursor.
+ # (Esc-ControlH).
+ result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b\x08X\n')
+ assert result.text == 'hello world /some/very/long/X'
+
+ # (with arguments.)
+ result, cli = _feed_cli_with_input('hello world /some/very/long/path\x1b3\x1b\x08X\n')
+ assert result.text == 'hello world /some/very/X'
+
+
+def test_controlx_controlx():
+ # At the end: go to the start of the line.
+ result, cli = _feed_cli_with_input('hello world\x18\x18X\n')
+ assert result.text == 'Xhello world'
+ assert result.cursor_position == 1
+
+ # At the start: go to the end of the line.
+ result, cli = _feed_cli_with_input('hello world\x01\x18\x18X\n')
+ assert result.text == 'hello worldX'
+
+ # Left, Left Control-X Control-X: go to the end of the line.
+ result, cli = _feed_cli_with_input('hello world\x1b[D\x1b[D\x18\x18X\n')
+ assert result.text == 'hello worldX'
+
+
+def test_emacs_history_bindings():
+ # Adding a new item to the history.
+ history = _history()
+ result, cli = _feed_cli_with_input('new input\n', history=history)
+ assert result.text == 'new input'
+ history.strings[-1] == 'new input'
+
+ # Go up in history, and accept the last item.
+ result, cli = _feed_cli_with_input('hello\x1b[A\n', history=history)
+ assert result.text == 'new input'
+
+ # Esc< (beginning-of-history)
+ result, cli = _feed_cli_with_input('hello\x1b<\n', history=history)
+ assert result.text == 'line1 first input'
+
+ # Esc> (end-of-history)
+ result, cli = _feed_cli_with_input('another item\x1b[A\x1b[a\x1b>\n', history=history)
+ assert result.text == 'another item'
+
+ # ControlUp (previous-history)
+ result, cli = _feed_cli_with_input('\x1b[1;5A\n', history=history)
+ assert result.text == 'another item'
+
+ # Esc< ControlDown (beginning-of-history, next-history)
+ result, cli = _feed_cli_with_input('\x1b<\x1b[1;5B\n', history=history)
+ assert result.text == 'line2 second input'
+
+
+def test_emacs_reverse_search():
+ history = _history()
+
+ # ControlR (reverse-search-history)
+ result, cli = _feed_cli_with_input('\x12input\n\n', history=history)
+ assert result.text == 'line3 third input'
+
+ # Hitting ControlR twice.
+ result, cli = _feed_cli_with_input('\x12input\x12\n\n', history=history)
+ assert result.text == 'line2 second input'
+
+
+def test_emacs_arguments():
+ """
+ Test various combinations of arguments in Emacs mode.
+ """
+ # esc 4
+ result, cli = _feed_cli_with_input('\x1b4x\n')
+ assert result.text == 'xxxx'
+
+ # esc 4 4
+ result, cli = _feed_cli_with_input('\x1b44x\n')
+ assert result.text == 'x' * 44
+
+ # esc 4 esc 4
+ result, cli = _feed_cli_with_input('\x1b4\x1b4x\n')
+ assert result.text == 'x' * 44
+
+ # esc - right (-1 position to the right, equals 1 to the left.)
+ result, cli = _feed_cli_with_input('aaaa\x1b-\x1b[Cbbbb\n')
+ assert result.text == 'aaabbbba'
+
+ # esc - 3 right
+ result, cli = _feed_cli_with_input('aaaa\x1b-3\x1b[Cbbbb\n')
+ assert result.text == 'abbbbaaa'
+
+ # esc - - - 3 right
+ result, cli = _feed_cli_with_input('aaaa\x1b---3\x1b[Cbbbb\n')
+ assert result.text == 'abbbbaaa'
+
+
+def test_emacs_arguments_for_all_commands():
+ """
+ Test all Emacs commands with Meta-[0-9] arguments (both positive and
+ negative). No one should crash.
+ """
+ for key in ANSI_SEQUENCES:
+ # Ignore BracketedPaste. This would hang forever, because it waits for
+ # the end sequence.
+ if key != '\x1b[200~':
+ try:
+ # Note: we add an 'X' after the key, because Ctrl-Q (quoted-insert)
+ # expects something to follow. We add an additional \n, because
+ # Ctrl-R and Ctrl-S (reverse-search) expect that.
+ result, cli = _feed_cli_with_input(
+ 'hello\x1b4' + key + 'X\n\n')
+
+ result, cli = _feed_cli_with_input(
+ 'hello\x1b-' + key + 'X\n\n')
+ except KeyboardInterrupt:
+ # This exception should only be raised for Ctrl-C
+ assert key == '\x03'
+
+
+def test_emacs_kill_ring():
+ operations = (
+ # abc ControlA ControlK
+ 'abc\x01\x0b'
+
+ # def ControlA ControlK
+ 'def\x01\x0b'
+
+ # ghi ControlA ControlK
+ 'ghi\x01\x0b'
+
+ # ControlY (yank)
+ '\x19'
+ )
+
+ result, cli = _feed_cli_with_input(operations + '\n')
+ assert result.text == 'ghi'
+
+ result, cli = _feed_cli_with_input(operations + '\x1by\n')
+ assert result.text == 'def'
+
+ result, cli = _feed_cli_with_input(operations + '\x1by\x1by\n')
+ assert result.text == 'abc'
+
+ result, cli = _feed_cli_with_input(operations + '\x1by\x1by\x1by\n')
+ assert result.text == 'ghi'
+
+
+def test_emacs_insert_comment():
+ # Test insert-comment (M-#) binding.
+ result, cli = _feed_cli_with_input('hello\x1b#', check_line_ending=False)
+ assert result.text == '#hello'
+
+ result, cli = _feed_cli_with_input(
+ 'hello\nworld\x1b#', check_line_ending=False, multiline=True)
+ assert result.text == '#hello\n#world'
+
+
+def test_emacs_record_macro():
+ operations = (
+ ' '
+ '\x18(' # Start recording macro. C-X(
+ 'hello'
+ '\x18)' # Stop recording macro.
+ ' '
+ '\x18e' # Execute macro.
+ '\x18e' # Execute macro.
+ '\n'
+ )
+
+ result, cli = _feed_cli_with_input(operations)
+ assert result.text == ' hello hellohello'
+
+
+def test_prefix_meta():
+ # Test the prefix-meta command.
+ def setup_keybindings(cli):
+ from prompt_toolkit.key_binding.bindings.named_commands import prefix_meta
+ from prompt_toolkit.filters import ViInsertMode
+ cli.application.key_bindings_registry.add_binding('j', 'j', filter=ViInsertMode())(prefix_meta)
+
+ result, cli = _feed_cli_with_input(
+ 'hellojjIX\n', pre_run_callback=setup_keybindings, editing_mode=EditingMode.VI)
+ assert result.text == 'Xhello'
+
+
+def test_bracketed_paste():
+ result, cli = _feed_cli_with_input('\x1b[200~hello world\x1b[201~\n')
+ assert result.text == 'hello world'
+
+ result, cli = _feed_cli_with_input('\x1b[200~hello\nworld\x1b[201~\x1b\n')
+ assert result.text == 'hello\nworld'
+
+ # With \r\n endings.
+ result, cli = _feed_cli_with_input('\x1b[200~hello\r\nworld\x1b[201~\x1b\n')
+ assert result.text == 'hello\nworld'
+
+ # With \r endings.
+ result, cli = _feed_cli_with_input('\x1b[200~hello\rworld\x1b[201~\x1b\n')
+ assert result.text == 'hello\nworld'
+
+
+def test_vi_cursor_movements():
+ """
+ Test cursor movements with Vi key bindings.
+ """
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI)
+
+ result, cli = feed('\x1b\n')
+ assert result.text == ''
+ assert cli.editing_mode == EditingMode.VI
+
+ # Esc h a X
+ result, cli = feed('hello\x1bhaX\n')
+ assert result.text == 'hellXo'
+
+ # Esc I X
+ result, cli = feed('hello\x1bIX\n')
+ assert result.text == 'Xhello'
+
+ # Esc I X
+ result, cli = feed('hello\x1bIX\n')
+ assert result.text == 'Xhello'
+
+ # Esc 2hiX
+ result, cli = feed('hello\x1b2hiX\n')
+ assert result.text == 'heXllo'
+
+ # Esc 2h2liX
+ result, cli = feed('hello\x1b2h2liX\n')
+ assert result.text == 'hellXo'
+
+ # Esc \b\b
+ result, cli = feed('hello\b\b\n')
+ assert result.text == 'hel'
+
+ # Esc \b\b
+ result, cli = feed('hello\b\b\n')
+ assert result.text == 'hel'
+
+ # Esc 2h D
+ result, cli = feed('hello\x1b2hD\n')
+ assert result.text == 'he'
+
+ # Esc 2h rX \n
+ result, cli = feed('hello\x1b2hrX\n')
+ assert result.text == 'heXlo'
+
+
+def test_vi_operators():
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI)
+
+ # Esc g~0
+ result, cli = feed('hello\x1bg~0\n')
+ assert result.text == 'HELLo'
+
+ # Esc gU0
+ result, cli = feed('hello\x1bgU0\n')
+ assert result.text == 'HELLo'
+
+ # Esc d0
+ result, cli = feed('hello\x1bd0\n')
+ assert result.text == 'o'
+
+
+def test_vi_text_objects():
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI)
+
+ # Esc gUgg
+ result, cli = feed('hello\x1bgUgg\n')
+ assert result.text == 'HELLO'
+
+ # Esc gUU
+ result, cli = feed('hello\x1bgUU\n')
+ assert result.text == 'HELLO'
+
+ # Esc di(
+ result, cli = feed('before(inside)after\x1b8hdi(\n')
+ assert result.text == 'before()after'
+
+ # Esc di[
+ result, cli = feed('before[inside]after\x1b8hdi[\n')
+ assert result.text == 'before[]after'
+
+ # Esc da(
+ result, cli = feed('before(inside)after\x1b8hda(\n')
+ assert result.text == 'beforeafter'
+
+
+def test_vi_digraphs():
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI)
+
+ # C-K o/
+ result, cli = feed('hello\x0bo/\n')
+ assert result.text == 'helloø'
+
+ # C-K /o (reversed input.)
+ result, cli = feed('hello\x0b/o\n')
+ assert result.text == 'helloø'
+
+ # C-K e:
+ result, cli = feed('hello\x0be:\n')
+ assert result.text == 'helloë'
+
+ # C-K xxy (Unknown digraph.)
+ result, cli = feed('hello\x0bxxy\n')
+ assert result.text == 'helloy'
+
+
+def test_vi_block_editing():
+ " Test Vi Control-V style block insertion. "
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI,
+ multiline=True)
+
+ operations = (
+ # Three lines of text.
+ '-line1\n-line2\n-line3\n-line4\n-line5\n-line6'
+ # Go to the second character of the second line.
+ '\x1bkkkkkkkj0l'
+ # Enter Visual block mode.
+ '\x16'
+ # Go down two more lines.
+ 'jj'
+ # Go 3 characters to the right.
+ 'lll'
+ # Go to insert mode.
+ 'insert' # (Will be replaced.)
+ # Insert stars.
+ '***'
+ # Escape again.
+ '\x1b\n')
+
+ # Control-I
+ result, cli = feed(operations.replace('insert', 'I'))
+
+ assert (result.text ==
+ '-line1\n-***line2\n-***line3\n-***line4\n-line5\n-line6')
+
+ # Control-A
+ result, cli = feed(operations.replace('insert', 'A'))
+
+ assert (result.text ==
+ '-line1\n-line***2\n-line***3\n-line***4\n-line5\n-line6')
+
+
+def test_vi_character_paste():
+ feed = partial(_feed_cli_with_input, editing_mode=EditingMode.VI)
+
+ # Test 'p' character paste.
+ result, cli = feed('abcde\x1bhhxp\n')
+ assert result.text == 'abdce'
+ assert result.cursor_position == 3
+
+ # Test 'P' character paste.
+ result, cli = feed('abcde\x1bhhxP\n')
+ assert result.text == 'abcde'
+ assert result.cursor_position == 2
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_contrib.py b/contrib/python/prompt-toolkit/py2/tests/test_contrib.py
new file mode 100644
index 00000000000..64765d3f1a1
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_contrib.py
@@ -0,0 +1,254 @@
+from __future__ import unicode_literals, absolute_import, print_function
+
+import os
+import shutil
+import tempfile
+
+from contextlib import contextmanager
+
+from six import text_type
+
+from prompt_toolkit.completion import CompleteEvent
+from prompt_toolkit.document import Document
+from prompt_toolkit.contrib.completers.filesystem import PathCompleter
+
+
+@contextmanager
+def chdir(directory):
+ """Context manager for current working directory temporary change."""
+ orig_dir = os.getcwd()
+ os.chdir(directory)
+
+ try:
+ yield
+ finally:
+ os.chdir(orig_dir)
+
+
+def write_test_files(test_dir, names=None):
+ """Write test files in test_dir using the names list."""
+ names = names or range(10)
+ for i in names:
+ with open(os.path.join(test_dir, str(i)), 'wb') as out:
+ out.write(''.encode('UTF-8'))
+
+
+def test_pathcompleter_completes_in_current_directory():
+ completer = PathCompleter()
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert len(completions) > 0
+
+
+def test_pathcompleter_completes_files_in_current_directory():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ expected = sorted([str(i) for i in range(10)])
+
+ if not test_dir.endswith(os.path.sep):
+ test_dir += os.path.sep
+
+ with chdir(test_dir):
+ completer = PathCompleter()
+ # this should complete on the cwd
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = sorted(c.text for c in completions)
+ assert expected == result
+
+ # cleanup
+ shutil.rmtree(test_dir)
+
+
+def test_pathcompleter_completes_files_in_absolute_directory():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ expected = sorted([str(i) for i in range(10)])
+
+ test_dir = os.path.abspath(test_dir)
+ if not test_dir.endswith(os.path.sep):
+ test_dir += os.path.sep
+
+ completer = PathCompleter()
+ # force unicode
+ doc_text = text_type(test_dir)
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = sorted([c.text for c in completions])
+ assert expected == result
+
+ # cleanup
+ shutil.rmtree(test_dir)
+
+
+def test_pathcompleter_completes_directories_with_only_directories():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ # create a sub directory there
+ os.mkdir(os.path.join(test_dir, 'subdir'))
+
+ if not test_dir.endswith(os.path.sep):
+ test_dir += os.path.sep
+
+ with chdir(test_dir):
+ completer = PathCompleter(only_directories=True)
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = [c.text for c in completions]
+ assert ['subdir'] == result
+
+ # check that there is no completion when passing a file
+ with chdir(test_dir):
+ completer = PathCompleter(only_directories=True)
+ doc_text = '1'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert [] == completions
+
+ # cleanup
+ shutil.rmtree(test_dir)
+
+
+def test_pathcompleter_respects_completions_under_min_input_len():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ # min len:1 and no text
+ with chdir(test_dir):
+ completer = PathCompleter(min_input_len=1)
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert [] == completions
+
+ # min len:1 and text of len 1
+ with chdir(test_dir):
+ completer = PathCompleter(min_input_len=1)
+ doc_text = '1'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = [c.text for c in completions]
+ assert [''] == result
+
+ # min len:0 and text of len 2
+ with chdir(test_dir):
+ completer = PathCompleter(min_input_len=0)
+ doc_text = '1'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = [c.text for c in completions]
+ assert [''] == result
+
+ # create 10 files with a 2 char long name
+ for i in range(10):
+ with open(os.path.join(test_dir, str(i) * 2), 'wb') as out:
+ out.write(b'')
+
+ # min len:1 and text of len 1
+ with chdir(test_dir):
+ completer = PathCompleter(min_input_len=1)
+ doc_text = '2'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = sorted(c.text for c in completions)
+ assert ['', '2'] == result
+
+ # min len:2 and text of len 1
+ with chdir(test_dir):
+ completer = PathCompleter(min_input_len=2)
+ doc_text = '2'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert [] == completions
+
+ # cleanup
+ shutil.rmtree(test_dir)
+
+
+def test_pathcompleter_does_not_expanduser_by_default():
+ completer = PathCompleter()
+ doc_text = '~'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert [] == completions
+
+
+def test_pathcompleter_can_expanduser(monkeypatch):
+ monkeypatch.setenv('HOME', '/tmp')
+ completer = PathCompleter(expanduser=True)
+ doc_text = '~'
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ assert len(completions) > 0
+
+
+def test_pathcompleter_can_apply_file_filter():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ # add a .csv file
+ with open(os.path.join(test_dir, 'my.csv'), 'wb') as out:
+ out.write(b'')
+
+ file_filter = lambda f: f and f.endswith('.csv')
+
+ with chdir(test_dir):
+ completer = PathCompleter(file_filter=file_filter)
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = [c.text for c in completions]
+ assert ['my.csv'] == result
+
+ # cleanup
+ shutil.rmtree(test_dir)
+
+
+def test_pathcompleter_get_paths_constrains_path():
+ # setup: create a test dir with 10 files
+ test_dir = tempfile.mkdtemp()
+ write_test_files(test_dir)
+
+ # add a subdir with 10 other files with different names
+ subdir = os.path.join(test_dir, 'subdir')
+ os.mkdir(subdir)
+ write_test_files(subdir, 'abcdefghij')
+
+ get_paths = lambda: ['subdir']
+
+ with chdir(test_dir):
+ completer = PathCompleter(get_paths=get_paths)
+ doc_text = ''
+ doc = Document(doc_text, len(doc_text))
+ event = CompleteEvent()
+ completions = list(completer.get_completions(doc, event))
+ result = [c.text for c in completions]
+ expected = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
+ assert expected == result
+
+ # cleanup
+ shutil.rmtree(test_dir)
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_document.py b/contrib/python/prompt-toolkit/py2/tests/test_document.py
new file mode 100644
index 00000000000..8c0cf5704c1
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_document.py
@@ -0,0 +1,74 @@
+from __future__ import unicode_literals
+
+import pytest
+
+from prompt_toolkit.document import Document
+
+
+@pytest.fixture
+def document():
+ return Document(
+ 'line 1\n' +
+ 'line 2\n' +
+ 'line 3\n' +
+ 'line 4\n',
+ len('line 1\n' + 'lin')
+ )
+
+
+def test_current_char(document):
+ assert document.current_char == 'e'
+
+
+def test_text_before_cursor(document):
+ assert document.text_before_cursor == 'line 1\nlin'
+
+
+def test_text_after_cursor(document):
+ assert document.text_after_cursor == 'e 2\n' + \
+ 'line 3\n' + \
+ 'line 4\n'
+
+
+def test_lines(document):
+ assert document.lines == [
+ 'line 1',
+ 'line 2',
+ 'line 3',
+ 'line 4', '']
+
+
+def test_line_count(document):
+ assert document.line_count == 5
+
+
+def test_current_line_before_cursor(document):
+ assert document.current_line_before_cursor == 'lin'
+
+
+def test_current_line_after_cursor(document):
+ assert document.current_line_after_cursor == 'e 2'
+
+
+def test_current_line(document):
+ assert document.current_line == 'line 2'
+
+
+def test_cursor_position(document):
+ assert document.cursor_position_row == 1
+ assert document.cursor_position_col == 3
+
+ d = Document('', 0)
+ assert d.cursor_position_row == 0
+ assert d.cursor_position_col == 0
+
+
+def test_translate_index_to_position(document):
+ pos = document.translate_index_to_position(
+ len('line 1\nline 2\nlin'))
+
+ assert pos[0] == 2
+ assert pos[1] == 3
+
+ pos = document.translate_index_to_position(0)
+ assert pos == (0, 0)
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_filter.py b/contrib/python/prompt-toolkit/py2/tests/test_filter.py
new file mode 100644
index 00000000000..5aee62a9a90
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_filter.py
@@ -0,0 +1,168 @@
+from __future__ import unicode_literals
+from prompt_toolkit.filters import Condition, Never, Always, Filter
+from prompt_toolkit.filters.types import CLIFilter, SimpleFilter
+from prompt_toolkit.filters.utils import to_cli_filter, to_simple_filter
+from prompt_toolkit.filters.cli import HasArg, HasFocus, HasSelection
+
+import pytest
+
+
+def test_condition_filter_args():
+ c = Condition(lambda a, b, c: True)
+ assert c.test_args('a', 'b', 'c')
+ assert not c.test_args()
+ assert not c.test_args('a')
+ assert not c.test_args('a', 'b')
+ assert not c.test_args('a', 'b', 'c', 'd')
+
+ c2 = Condition(lambda a, b=1: True)
+ assert c2.test_args('a')
+ assert c2.test_args('a', 'b')
+ assert not c2.test_args('a', 'b', 'c')
+ assert not c2.test_args()
+
+ c3 = Condition(lambda *a: True)
+ assert c3.test_args()
+ assert c3.test_args('a')
+ assert c3.test_args('a', 'b')
+
+
+def test_and_arg():
+ c1 = Condition(lambda a: True)
+ c2 = Condition(lambda a: True)
+ c3 = c1 & c2
+
+ assert c3.test_args('a')
+ assert not c3.test_args()
+ assert not c3.test_args('a', 'b')
+
+
+def test_or_arg():
+ c1 = Condition(lambda a: True)
+ c2 = Condition(lambda a: True)
+ c3 = c1 | c2
+
+ assert c3.test_args('a')
+ assert not c3.test_args()
+ assert not c3.test_args('a', 'b')
+
+
+def test_condition():
+ c = Condition(lambda a: a % 2 == 0)
+ assert c(4)
+ assert c(6)
+ assert not c(5)
+ assert not c(3)
+
+
+def test_never():
+ assert not Never()()
+
+
+def test_always():
+ assert Always()()
+
+
+def test_invert():
+ assert not (~Always())()
+ assert (~Never()())
+
+ c = ~Condition(lambda: False)
+ assert c()
+
+
+def test_or():
+ for a in (True, False):
+ for b in (True, False):
+ c1 = Condition(lambda: a)
+ c2 = Condition(lambda: b)
+ c3 = c1 | c2
+
+ assert isinstance(c3, Filter)
+ assert c3() == a or b
+
+
+def test_and():
+ for a in (True, False):
+ for b in (True, False):
+ c1 = Condition(lambda: a)
+ c2 = Condition(lambda: b)
+ c3 = c1 & c2
+
+ assert isinstance(c3, Filter)
+ assert c3() == (a and b)
+
+
+def test_cli_filter():
+ c1 = Condition(lambda cli: True)
+ assert isinstance(c1, CLIFilter)
+ assert not isinstance(c1, SimpleFilter)
+
+ c2 = Condition(lambda: True)
+ assert not isinstance(c2, CLIFilter)
+ assert isinstance(c2, SimpleFilter)
+
+ c3 = c1 | c2
+ assert not isinstance(c3, CLIFilter)
+ assert not isinstance(c3, SimpleFilter)
+
+ c4 = Condition(lambda cli: True)
+ c5 = Condition(lambda cli: True)
+ c6 = c4 & c5
+ c7 = c4 | c5
+ assert isinstance(c6, CLIFilter)
+ assert isinstance(c7, CLIFilter)
+ assert not isinstance(c6, SimpleFilter)
+ assert not isinstance(c7, SimpleFilter)
+
+ c8 = Condition(lambda *args: True)
+ assert isinstance(c8, CLIFilter)
+ assert isinstance(c8, SimpleFilter)
+
+
+def test_to_cli_filter():
+ f1 = to_cli_filter(True)
+ f2 = to_cli_filter(False)
+ f3 = to_cli_filter(Condition(lambda cli: True))
+ f4 = to_cli_filter(Condition(lambda cli: False))
+
+ assert isinstance(f1, CLIFilter)
+ assert isinstance(f2, CLIFilter)
+ assert isinstance(f3, CLIFilter)
+ assert isinstance(f4, CLIFilter)
+ assert f1(None)
+ assert not f2(None)
+ assert f3(None)
+ assert not f4(None)
+
+ with pytest.raises(TypeError):
+ to_cli_filter(4)
+ with pytest.raises(TypeError):
+ to_cli_filter(Condition(lambda: True))
+
+
+def test_to_simple_filter():
+ f1 = to_simple_filter(True)
+ f2 = to_simple_filter(False)
+ f3 = to_simple_filter(Condition(lambda: True))
+ f4 = to_simple_filter(Condition(lambda: False))
+
+ assert isinstance(f1, SimpleFilter)
+ assert isinstance(f2, SimpleFilter)
+ assert isinstance(f3, SimpleFilter)
+ assert isinstance(f4, SimpleFilter)
+ assert f1()
+ assert not f2()
+ assert f3()
+ assert not f4()
+
+ with pytest.raises(TypeError):
+ to_simple_filter(4)
+ with pytest.raises(TypeError):
+ to_simple_filter(Condition(lambda cli: True))
+
+
+def test_cli_filters():
+ assert isinstance(HasArg(), CLIFilter)
+ assert isinstance(HasFocus('BUFFER_NAME'), CLIFilter)
+ assert isinstance(HasSelection(), CLIFilter)
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py b/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py
new file mode 100644
index 00000000000..de10c0f9a91
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_inputstream.py
@@ -0,0 +1,142 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.terminal.vt100_input import InputStream
+from prompt_toolkit.keys import Keys
+
+import pytest
+
+
+class _ProcessorMock(object):
+
+ def __init__(self):
+ self.keys = []
+
+ def feed_key(self, key_press):
+ self.keys.append(key_press)
+
+
+@pytest.fixture
+def processor():
+ return _ProcessorMock()
+
+
+@pytest.fixture
+def stream(processor):
+ return InputStream(processor.feed_key)
+
+
+def test_control_keys(processor, stream):
+ stream.feed('\x01\x02\x10')
+
+ assert len(processor.keys) == 3
+ assert processor.keys[0].key == Keys.ControlA
+ assert processor.keys[1].key == Keys.ControlB
+ assert processor.keys[2].key == Keys.ControlP
+ assert processor.keys[0].data == '\x01'
+ assert processor.keys[1].data == '\x02'
+ assert processor.keys[2].data == '\x10'
+
+
+def test_arrows(processor, stream):
+ stream.feed('\x1b[A\x1b[B\x1b[C\x1b[D')
+
+ assert len(processor.keys) == 4
+ assert processor.keys[0].key == Keys.Up
+ assert processor.keys[1].key == Keys.Down
+ assert processor.keys[2].key == Keys.Right
+ assert processor.keys[3].key == Keys.Left
+ assert processor.keys[0].data == '\x1b[A'
+ assert processor.keys[1].data == '\x1b[B'
+ assert processor.keys[2].data == '\x1b[C'
+ assert processor.keys[3].data == '\x1b[D'
+
+
+def test_escape(processor, stream):
+ stream.feed('\x1bhello')
+
+ assert len(processor.keys) == 1 + len('hello')
+ assert processor.keys[0].key == Keys.Escape
+ assert processor.keys[1].key == 'h'
+ assert processor.keys[0].data == '\x1b'
+ assert processor.keys[1].data == 'h'
+
+
+def test_special_double_keys(processor, stream):
+ stream.feed('\x1b[1;3D') # Should both send escape and left.
+
+ assert len(processor.keys) == 2
+ assert processor.keys[0].key == Keys.Escape
+ assert processor.keys[1].key == Keys.Left
+ assert processor.keys[0].data == '\x1b[1;3D'
+ assert processor.keys[1].data == '\x1b[1;3D'
+
+
+def test_flush_1(processor, stream):
+ # Send left key in two parts without flush.
+ stream.feed('\x1b')
+ stream.feed('[D')
+
+ assert len(processor.keys) == 1
+ assert processor.keys[0].key == Keys.Left
+ assert processor.keys[0].data == '\x1b[D'
+
+
+def test_flush_2(processor, stream):
+ # Send left key with a 'Flush' in between.
+ # The flush should make sure that we process evenything before as-is,
+ # with makes the first part just an escape character instead.
+ stream.feed('\x1b')
+ stream.flush()
+ stream.feed('[D')
+
+ assert len(processor.keys) == 3
+ assert processor.keys[0].key == Keys.Escape
+ assert processor.keys[1].key == '['
+ assert processor.keys[2].key == 'D'
+
+ assert processor.keys[0].data == '\x1b'
+ assert processor.keys[1].data == '['
+ assert processor.keys[2].data == 'D'
+
+
+def test_meta_arrows(processor, stream):
+ stream.feed('\x1b\x1b[D')
+
+ assert len(processor.keys) == 2
+ assert processor.keys[0].key == Keys.Escape
+ assert processor.keys[1].key == Keys.Left
+
+
+def test_control_square_close(processor, stream):
+ stream.feed('\x1dC')
+
+ assert len(processor.keys) == 2
+ assert processor.keys[0].key == Keys.ControlSquareClose
+ assert processor.keys[1].key == 'C'
+
+
+def test_invalid(processor, stream):
+ # Invalid sequence that has at two characters in common with other
+ # sequences.
+ stream.feed('\x1b[*')
+
+ assert len(processor.keys) == 3
+ assert processor.keys[0].key == Keys.Escape
+ assert processor.keys[1].key == '['
+ assert processor.keys[2].key == '*'
+
+
+def test_cpr_response(processor, stream):
+ stream.feed('a\x1b[40;10Rb')
+ assert len(processor.keys) == 3
+ assert processor.keys[0].key == 'a'
+ assert processor.keys[1].key == Keys.CPRResponse
+ assert processor.keys[2].key == 'b'
+
+
+def test_cpr_response_2(processor, stream):
+ # Make sure that the newline is not included in the CPR response.
+ stream.feed('\x1b[40;1R\n')
+ assert len(processor.keys) == 2
+ assert processor.keys[0].key == Keys.CPRResponse
+ assert processor.keys[1].key == Keys.ControlJ
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py b/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py
new file mode 100644
index 00000000000..d706c4443b2
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_key_binding.py
@@ -0,0 +1,140 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.key_binding.input_processor import InputProcessor, KeyPress
+from prompt_toolkit.key_binding.registry import Registry
+from prompt_toolkit.keys import Keys
+
+import pytest
+
+
+class Handlers(object):
+
+ def __init__(self):
+ self.called = []
+
+ def __getattr__(self, name):
+ def func(event):
+ self.called.append(name)
+ return func
+
+
+@pytest.fixture
+def handlers():
+ return Handlers()
+
+
+@pytest.fixture
+def registry(handlers):
+ registry = Registry()
+ registry.add_binding(
+ Keys.ControlX, Keys.ControlC)(handlers.controlx_controlc)
+ registry.add_binding(Keys.ControlX)(handlers.control_x)
+ registry.add_binding(Keys.ControlD)(handlers.control_d)
+ registry.add_binding(
+ Keys.ControlSquareClose, Keys.Any)(handlers.control_square_close_any)
+
+ return registry
+
+
+@pytest.fixture
+def processor(registry):
+ return InputProcessor(registry, lambda: None)
+
+
+def test_feed_simple(processor, handlers):
+ processor.feed(KeyPress(Keys.ControlX, '\x18'))
+ processor.feed(KeyPress(Keys.ControlC, '\x03'))
+ processor.process_keys()
+
+ assert handlers.called == ['controlx_controlc']
+
+
+def test_feed_several(processor, handlers):
+ # First an unknown key first.
+ processor.feed(KeyPress(Keys.ControlQ, ''))
+ processor.process_keys()
+
+ assert handlers.called == []
+
+ # Followed by a know key sequence.
+ processor.feed(KeyPress(Keys.ControlX, ''))
+ processor.feed(KeyPress(Keys.ControlC, ''))
+ processor.process_keys()
+
+ assert handlers.called == ['controlx_controlc']
+
+ # Followed by another unknown sequence.
+ processor.feed(KeyPress(Keys.ControlR, ''))
+ processor.feed(KeyPress(Keys.ControlS, ''))
+
+ # Followed again by a know key sequence.
+ processor.feed(KeyPress(Keys.ControlD, ''))
+ processor.process_keys()
+
+ assert handlers.called == ['controlx_controlc', 'control_d']
+
+
+def test_control_square_closed_any(processor, handlers):
+ processor.feed(KeyPress(Keys.ControlSquareClose, ''))
+ processor.feed(KeyPress('C', 'C'))
+ processor.process_keys()
+
+ assert handlers.called == ['control_square_close_any']
+
+
+def test_common_prefix(processor, handlers):
+ # Sending Control_X should not yet do anything, because there is
+ # another sequence starting with that as well.
+ processor.feed(KeyPress(Keys.ControlX, ''))
+ processor.process_keys()
+
+ assert handlers.called == []
+
+ # When another key is pressed, we know that we did not meant the longer
+ # "ControlX ControlC" sequence and the callbacks are called.
+ processor.feed(KeyPress(Keys.ControlD, ''))
+ processor.process_keys()
+
+ assert handlers.called == ['control_x', 'control_d']
+
+
+def test_previous_key_sequence(processor, handlers):
+ """
+ test whether we receive the correct previous_key_sequence.
+ """
+ events = []
+ def handler(event):
+ events.append(event)
+
+ # Build registry.
+ registry = Registry()
+ registry.add_binding('a', 'a')(handler)
+ registry.add_binding('b', 'b')(handler)
+ processor = InputProcessor(registry, lambda: None)
+
+ # Create processor and feed keys.
+ processor.feed(KeyPress('a', 'a'))
+ processor.feed(KeyPress('a', 'a'))
+ processor.feed(KeyPress('b', 'b'))
+ processor.feed(KeyPress('b', 'b'))
+ processor.process_keys()
+
+ # Test.
+ assert len(events) == 2
+ assert len(events[0].key_sequence) == 2
+ assert events[0].key_sequence[0].key == 'a'
+ assert events[0].key_sequence[0].data == 'a'
+ assert events[0].key_sequence[1].key == 'a'
+ assert events[0].key_sequence[1].data == 'a'
+ assert events[0].previous_key_sequence == []
+
+ assert len(events[1].key_sequence) == 2
+ assert events[1].key_sequence[0].key == 'b'
+ assert events[1].key_sequence[0].data == 'b'
+ assert events[1].key_sequence[1].key == 'b'
+ assert events[1].key_sequence[1].data == 'b'
+ assert len(events[1].previous_key_sequence) == 2
+ assert events[1].previous_key_sequence[0].key == 'a'
+ assert events[1].previous_key_sequence[0].data == 'a'
+ assert events[1].previous_key_sequence[1].key == 'a'
+ assert events[1].previous_key_sequence[1].data == 'a'
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_layout.py b/contrib/python/prompt-toolkit/py2/tests/test_layout.py
new file mode 100644
index 00000000000..6c9e67b4dea
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_layout.py
@@ -0,0 +1,60 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.layout.utils import split_lines
+from prompt_toolkit.token import Token
+
+
+def test_split_lines():
+ lines = list(split_lines([(Token.A, 'line1\nline2\nline3')]))
+
+ assert lines == [
+ [(Token.A, 'line1')],
+ [(Token.A, 'line2')],
+ [(Token.A, 'line3')],
+ ]
+
+
+def test_split_lines_2():
+ lines = list(split_lines([
+ (Token.A, 'line1'),
+ (Token.B, 'line2\nline3\nline4')
+ ]))
+
+ assert lines == [
+ [(Token.A, 'line1'), (Token.B, 'line2')],
+ [(Token.B, 'line3')],
+ [(Token.B, 'line4')],
+ ]
+
+
+def test_split_lines_3():
+ " Edge cases: inputs ending with newlines. "
+ # -1-
+ lines = list(split_lines([
+ (Token.A, 'line1\nline2\n')
+ ]))
+
+ assert lines == [
+ [(Token.A, 'line1')],
+ [(Token.A, 'line2')],
+ [(Token.A, '')],
+ ]
+
+ # -2-
+ lines = list(split_lines([
+ (Token.A, '\n'),
+ ]))
+
+ assert lines == [
+ [],
+ [(Token.A, '')],
+ ]
+
+ # -3-
+ lines = list(split_lines([
+ (Token.A, ''),
+ ]))
+
+ assert lines == [
+ [(Token.A, '')],
+ ]
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py b/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py
new file mode 100644
index 00000000000..c3b5826b36c
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_print_tokens.py
@@ -0,0 +1,50 @@
+"""
+Test `shortcuts.print_tokens`.
+"""
+from __future__ import unicode_literals
+from prompt_toolkit.shortcuts import print_tokens
+from prompt_toolkit.token import Token
+from prompt_toolkit.styles import style_from_dict
+
+
+class _Capture:
+ " Emulate an stdout object. "
+ encoding = 'utf-8'
+
+ def __init__(self):
+ self._data = []
+
+ def write(self, data):
+ self._data.append(data)
+
+ @property
+ def data(self):
+ return b''.join(self._data)
+
+ def flush(self):
+ pass
+
+ def isatty(self):
+ return True
+
+
+def test_print_tokens():
+ f = _Capture()
+ print_tokens([(Token, 'hello'), (Token, 'world')], file=f)
+ assert b'hello' in f.data
+ assert b'world' in f.data
+
+
+def test_with_style():
+ f = _Capture()
+ style = style_from_dict({
+ Token.Hello: '#ff0066',
+ Token.World: '#44ff44 italic',
+ })
+ tokens = [
+ (Token.Hello, 'Hello '),
+ (Token.World, 'world'),
+ ]
+ print_tokens(tokens, style=style, file=f)
+ assert b'\x1b[0;38;5;197mHello' in f.data
+ assert b'\x1b[0;38;5;83;3mworld' in f.data
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py b/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py
new file mode 100644
index 00000000000..6ece5cdeb53
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_regular_languages.py
@@ -0,0 +1,110 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.completion import CompleteEvent, Completer, Completion
+from prompt_toolkit.contrib.regular_languages import compile
+from prompt_toolkit.contrib.regular_languages.compiler import Match, Variables
+from prompt_toolkit.contrib.regular_languages.completion import \
+ GrammarCompleter
+from prompt_toolkit.document import Document
+
+
+def test_simple_match():
+ g = compile('hello|world')
+
+ m = g.match('hello')
+ assert isinstance(m, Match)
+
+ m = g.match('world')
+ assert isinstance(m, Match)
+
+ m = g.match('somethingelse')
+ assert m is None
+
+
+def test_variable_varname():
+ """
+ Test `Variable` with varname.
+ """
+ g = compile('((?P<varname>hello|world)|test)')
+
+ m = g.match('hello')
+ variables = m.variables()
+ assert isinstance(variables, Variables)
+ assert variables.get('varname') == 'hello'
+ assert variables['varname'] == 'hello'
+
+ m = g.match('world')
+ variables = m.variables()
+ assert isinstance(variables, Variables)
+ assert variables.get('varname') == 'world'
+ assert variables['varname'] == 'world'
+
+ m = g.match('test')
+ variables = m.variables()
+ assert isinstance(variables, Variables)
+ assert variables.get('varname') is None
+ assert variables['varname'] is None
+
+
+def test_prefix():
+ """
+ Test `match_prefix`.
+ """
+ g = compile(r'(hello\ world|something\ else)')
+
+ m = g.match_prefix('hello world')
+ assert isinstance(m, Match)
+
+ m = g.match_prefix('he')
+ assert isinstance(m, Match)
+
+ m = g.match_prefix('')
+ assert isinstance(m, Match)
+
+ m = g.match_prefix('som')
+ assert isinstance(m, Match)
+
+ m = g.match_prefix('hello wor')
+ assert isinstance(m, Match)
+
+ m = g.match_prefix('no-match')
+ assert m.trailing_input().start == 0
+ assert m.trailing_input().stop == len('no-match')
+
+ m = g.match_prefix('hellotest')
+ assert m.trailing_input().start == len('hello')
+ assert m.trailing_input().stop == len('hellotest')
+
+
+def test_completer():
+ class completer1(Completer):
+
+ def get_completions(self, document, complete_event):
+ yield Completion(
+ 'before-%s-after' % document.text, -len(document.text))
+ yield Completion(
+ 'before-%s-after-B' % document.text, -len(document.text))
+
+ class completer2(Completer):
+
+ def get_completions(self, document, complete_event):
+ yield Completion(
+ 'before2-%s-after2' % document.text, -len(document.text))
+ yield Completion(
+ 'before2-%s-after2-B' % document.text, -len(document.text))
+
+ # Create grammar. "var1" + "whitespace" + "var2"
+ g = compile(r'(?P<var1>[a-z]*) \s+ (?P<var2>[a-z]*)')
+
+ # Test 'get_completions()'
+ completer = GrammarCompleter(
+ g, {'var1': completer1(), 'var2': completer2()})
+ completions = list(completer.get_completions(
+ Document('abc def', len('abc def')),
+ CompleteEvent()))
+
+ assert len(completions) == 2
+ assert completions[0].text == 'before2-def-after2'
+ assert completions[0].start_position == -3
+ assert completions[1].text == 'before2-def-after2-B'
+ assert completions[1].start_position == -3
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py b/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py
new file mode 100644
index 00000000000..8c13510ea83
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_shortcuts.py
@@ -0,0 +1,50 @@
+from prompt_toolkit.shortcuts import _split_multiline_prompt
+from prompt_toolkit.token import Token
+
+
+def test_split_multiline_prompt():
+ # Test 1: no newlines:
+ tokens = [(Token, 'ab')]
+ has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
+ assert has_before_tokens(None) is False
+ assert before(None) == []
+ assert first_input_line(None) == [
+ (Token, 'a'),
+ (Token, 'b'),
+ ]
+
+ # Test 1: multiple lines.
+ tokens = [(Token, 'ab\ncd\nef')]
+ has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
+ assert has_before_tokens(None) is True
+ assert before(None) == [
+ (Token, 'a'),
+ (Token, 'b'),
+ (Token, '\n'),
+ (Token, 'c'),
+ (Token, 'd'),
+ ]
+ assert first_input_line(None) == [
+ (Token, 'e'),
+ (Token, 'f'),
+ ]
+
+ # Edge case 1: starting with a newline.
+ tokens = [(Token, '\nab')]
+ has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
+ assert has_before_tokens(None) is True
+ assert before(None) == []
+ assert first_input_line(None) == [
+ (Token, 'a'),
+ (Token, 'b')
+ ]
+
+ # Edge case 2: starting with two newlines.
+ tokens = [(Token, '\n\nab')]
+ has_before_tokens, before, first_input_line = _split_multiline_prompt(lambda cli: tokens)
+ assert has_before_tokens(None) is True
+ assert before(None) == [(Token, '\n')]
+ assert first_input_line(None) == [
+ (Token, 'a'),
+ (Token, 'b')
+ ]
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_style.py b/contrib/python/prompt-toolkit/py2/tests/test_style.py
new file mode 100644
index 00000000000..fc839ec95f2
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_style.py
@@ -0,0 +1,40 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.styles import Attrs, style_from_dict
+from prompt_toolkit.token import Token
+
+
+def test_style_from_dict():
+ style = style_from_dict({
+ Token.A: '#ff0000 bold underline italic',
+ Token.B: 'bg:#00ff00 blink reverse',
+ })
+
+ expected = Attrs(color='ff0000', bgcolor=None, bold=True,
+ underline=True, italic=True, blink=False, reverse=False)
+ assert style.get_attrs_for_token(Token.A) == expected
+
+ expected = Attrs(color=None, bgcolor='00ff00', bold=False,
+ underline=False, italic=False, blink=True, reverse=True)
+ assert style.get_attrs_for_token(Token.B) == expected
+
+
+def test_style_inheritance():
+ style = style_from_dict({
+ Token: '#ff0000',
+ Token.A.B.C: 'bold',
+ Token.A.B.C.D: '#ansired',
+ Token.A.B.C.D.E: 'noinherit blink'
+ })
+
+ expected = Attrs(color='ff0000', bgcolor=None, bold=True,
+ underline=False, italic=False, blink=False, reverse=False)
+ assert style.get_attrs_for_token(Token.A.B.C) == expected
+
+ expected = Attrs(color='ansired', bgcolor=None, bold=True,
+ underline=False, italic=False, blink=False, reverse=False)
+ assert style.get_attrs_for_token(Token.A.B.C.D) == expected
+
+ expected = Attrs(color=None, bgcolor=None, bold=False,
+ underline=False, italic=False, blink=True, reverse=False)
+ assert style.get_attrs_for_token(Token.A.B.C.D.E) == expected
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_utils.py b/contrib/python/prompt-toolkit/py2/tests/test_utils.py
new file mode 100644
index 00000000000..1e3d92cda69
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_utils.py
@@ -0,0 +1,39 @@
+from __future__ import unicode_literals
+
+from prompt_toolkit.utils import take_using_weights
+
+import itertools
+
+
+def test_using_weights():
+ def take(generator, count):
+ return list(itertools.islice(generator, 0, count))
+
+ # Check distribution.
+ data = take(take_using_weights(['A', 'B', 'C'], [5, 10, 20]), 35)
+ assert data.count('A') == 5
+ assert data.count('B') == 10
+ assert data.count('C') == 20
+
+ assert data == [
+ 'A', 'B', 'C', 'C', 'B', 'C', 'C', 'A', 'B', 'C', 'C', 'B', 'C',
+ 'C', 'A', 'B', 'C', 'C', 'B', 'C', 'C', 'A', 'B', 'C', 'C',
+ 'B', 'C', 'C', 'A', 'B', 'C', 'C', 'B', 'C', 'C']
+
+ # Another order.
+ data = take(take_using_weights(['A', 'B', 'C'], [20, 10, 5]), 35)
+ assert data.count('A') == 20
+ assert data.count('B') == 10
+ assert data.count('C') == 5
+
+ # Bigger numbers.
+ data = take(take_using_weights(['A', 'B', 'C'], [20, 10, 5]), 70)
+ assert data.count('A') == 40
+ assert data.count('B') == 20
+ assert data.count('C') == 10
+
+ # Negative numbers.
+ data = take(take_using_weights(['A', 'B', 'C'], [-20, 10, 0]), 70)
+ assert data.count('A') == 0
+ assert data.count('B') == 70
+ assert data.count('C') == 0
diff --git a/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py b/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py
new file mode 100644
index 00000000000..1ccec7bf7b1
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/test_yank_nth_arg.py
@@ -0,0 +1,85 @@
+from __future__ import unicode_literals
+from prompt_toolkit.buffer import Buffer
+from prompt_toolkit.history import InMemoryHistory
+
+import pytest
+
+
+@pytest.fixture
+def _history():
+ " Prefilled history. "
+ history = InMemoryHistory()
+ history.append('alpha beta gamma delta')
+ history.append('one two three four')
+ return history
+
+
+# Test yank_last_arg.
+
+
+def test_empty_history():
+ buf = Buffer()
+ buf.yank_last_arg()
+ assert buf.document.current_line == ''
+
+
+def test_simple_search(_history):
+ buff = Buffer(history=_history)
+ buff.yank_last_arg()
+ assert buff.document.current_line == 'four'
+
+
+def test_simple_search_with_quotes(_history):
+ _history.append("""one two "three 'x' four"\n""")
+ buff = Buffer(history=_history)
+ buff.yank_last_arg()
+ assert buff.document.current_line == '''"three 'x' four"'''
+
+
+def test_simple_search_with_arg(_history):
+ buff = Buffer(history=_history)
+ buff.yank_last_arg(n=2)
+ assert buff.document.current_line == 'three'
+
+
+def test_simple_search_with_arg_out_of_bounds(_history):
+ buff = Buffer(history=_history)
+ buff.yank_last_arg(n=8)
+ assert buff.document.current_line == ''
+
+
+def test_repeated_search(_history):
+ buff = Buffer(history=_history)
+ buff.yank_last_arg()
+ buff.yank_last_arg()
+ assert buff.document.current_line == 'delta'
+
+
+def test_repeated_search_with_wraparound(_history):
+ buff = Buffer(history=_history)
+ buff.yank_last_arg()
+ buff.yank_last_arg()
+ buff.yank_last_arg()
+ assert buff.document.current_line == 'four'
+
+
+# Test yank_last_arg.
+
+
+def test_yank_nth_arg(_history):
+ buff = Buffer(history=_history)
+ buff.yank_nth_arg()
+ assert buff.document.current_line == 'two'
+
+
+def test_repeated_yank_nth_arg(_history):
+ buff = Buffer(history=_history)
+ buff.yank_nth_arg()
+ buff.yank_nth_arg()
+ assert buff.document.current_line == 'beta'
+
+
+def test_yank_nth_arg_with_arg(_history):
+ buff = Buffer(history=_history)
+ buff.yank_nth_arg(n=2)
+ assert buff.document.current_line == 'three'
diff --git a/contrib/python/prompt-toolkit/py2/tests/ya.make b/contrib/python/prompt-toolkit/py2/tests/ya.make
new file mode 100644
index 00000000000..afd26fbfe72
--- /dev/null
+++ b/contrib/python/prompt-toolkit/py2/tests/ya.make
@@ -0,0 +1,28 @@
+PY2TEST()
+
+OWNER(g:python-contrib)
+
+PEERDIR(
+ contrib/python/prompt-toolkit
+)
+
+TEST_SRCS(
+ test_buffer.py
+ test_cli.py
+ test_contrib.py
+ test_document.py
+ test_filter.py
+ test_inputstream.py
+ test_key_binding.py
+ test_layout.py
+ test_print_tokens.py
+ test_regular_languages.py
+ test_shortcuts.py
+ test_style.py
+ test_utils.py
+ test_yank_nth_arg.py
+)
+
+NO_LINT()
+
+END()