Add a testing interface that works for Neovim.
- Remove support for python 3.2 to reduce number of test cases and because it actually fails with Neovim. It is not a supported version anyways. - Due to Neovim not handling fast typing through the console properly (https://github.com/neovim/neovim/issues/2454), the typing is actually simulated through the Python client. We need to differentiate now if a keystroke is meant for the terminal or for the Vim session. Using neovim.input() introduces additional chances for races since inputs are not buffered but processed right away. This results in more retries for some tests. - Neovim needs more parameters and configuration passed in through the test script. Added command line arguments for these. - Skip an extra test under Neovim due to https://github.com/neovim/python-client/issues/128.
This commit is contained in:
parent
992e094638
commit
306f0ace5f
@ -2,18 +2,12 @@ language: python
|
||||
|
||||
python:
|
||||
- 2.7
|
||||
- 3.2
|
||||
- 3.3
|
||||
- 3.4
|
||||
env:
|
||||
- VIM_VERSION="74"
|
||||
- VIM_VERSION="mercurial"
|
||||
# - VIM_VERSION="NEOVIM"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
# TODO(sirver): Neovim does not play well with our testing right now.
|
||||
- env: VIM_VERSION="NEOVIM"
|
||||
- VIM_VERSION="NEOVIM"
|
||||
|
||||
install:
|
||||
# Some of these commands fail transiently. We keep retrying them until they succeed.
|
||||
|
@ -1,5 +1,5 @@
|
||||
from test.vim_test_case import VimTestCase as _VimTest
|
||||
from test.constant import *
|
||||
from test.vim_test_case import VimTestCase as _VimTest
|
||||
|
||||
|
||||
class ContextSnippets_SimpleSnippet(_VimTest):
|
||||
@ -42,7 +42,6 @@ class ContextSnippets_DoNotExpandOnFalse(_VimTest):
|
||||
wanted = keys
|
||||
|
||||
|
||||
|
||||
class ContextSnippets_UseContext(_VimTest):
|
||||
files = { 'us/all.snippets': r"""
|
||||
global !p
|
||||
@ -99,8 +98,8 @@ class ContextSnippets_PriorityKeyword(_VimTest):
|
||||
endsnippet
|
||||
"""}
|
||||
|
||||
keys = "i" + EX
|
||||
wanted = "b"
|
||||
keys = 'i' + EX
|
||||
wanted = 'b'
|
||||
|
||||
|
||||
class ContextSnippets_ReportError(_VimTest):
|
||||
@ -110,18 +109,21 @@ class ContextSnippets_ReportError(_VimTest):
|
||||
endsnippet
|
||||
"""}
|
||||
|
||||
keys = "e" + EX
|
||||
wanted = "e" + EX
|
||||
keys = 'e' + EX
|
||||
wanted = 'e' + EX
|
||||
expected_error = r"NameError: name 'Tru' is not defined"
|
||||
|
||||
|
||||
class ContextSnippets_ReportErrorOnIndexOutOfRange(_VimTest):
|
||||
# Working around: https://github.com/neovim/python-client/issues/128.
|
||||
skip_if = lambda self: 'Bug in Neovim.' \
|
||||
if self.vim_flavor == 'neovim' else None
|
||||
files = { 'us/all.snippets': r"""
|
||||
snippet e "desc" "buffer[123]" e
|
||||
error
|
||||
endsnippet
|
||||
"""}
|
||||
|
||||
keys = "e" + EX
|
||||
wanted = "e" + EX
|
||||
keys = 'e' + EX
|
||||
wanted = 'e' + EX
|
||||
expected_error = r"IndexError: line number out of range"
|
||||
|
@ -78,7 +78,7 @@ class NonUnicodeDataInUnnamedRegister(_VimTest):
|
||||
# The string below was the one a user had on their clipboard when
|
||||
# encountering the UnicodeDecodeError and could not be coerced into
|
||||
# unicode.
|
||||
self.vim.send(
|
||||
self.vim.send_to_vim(
|
||||
':let @" = "\\x80kdI{\\x80@7 1},' +
|
||||
'\\x80kh\\x80kh\\x80kd\\x80kdq\\x80kb\\x1b"\n')
|
||||
# End: #171 #}}}
|
||||
|
@ -85,7 +85,7 @@ class Plugin_SuperTab_SimpleTest(_VimTest):
|
||||
|
||||
def _before_test(self):
|
||||
# Make sure that UltiSnips has the keymap
|
||||
self.vim.send(':call UltiSnips#map_keys#MapKeys()\n')
|
||||
self.vim.send_to_vim(':call UltiSnips#map_keys#MapKeys()\n')
|
||||
|
||||
def _extra_vim_config(self, vim_config):
|
||||
assert EX == '\t' # Otherwise this test needs changing.
|
||||
|
@ -10,7 +10,7 @@ class _AddFuncBase(_VimTest):
|
||||
args = ''
|
||||
|
||||
def _before_test(self):
|
||||
self.vim.send(':call UltiSnips#AddSnippetWithPriority(%s)\n' % self.args)
|
||||
self.vim.send_to_vim(':call UltiSnips#AddSnippetWithPriority(%s)\n' % self.args)
|
||||
|
||||
|
||||
class AddFunc_Simple(_AddFuncBase):
|
||||
@ -61,7 +61,7 @@ hi2...hi3
|
||||
hi4Hello"""
|
||||
|
||||
def _before_test(self):
|
||||
self.vim.send(':set langmap=\\\\;;A\n')
|
||||
self.vim.send_to_vim(':set langmap=\\\\;;A\n')
|
||||
|
||||
# Test for bug 871357 #
|
||||
|
||||
@ -81,7 +81,7 @@ hi2...hi3
|
||||
hi4"""
|
||||
|
||||
def _before_test(self):
|
||||
self.vim.send(
|
||||
self.vim.send_to_vim(
|
||||
":set langmap=йq,цw,уe,кr,еt,нy,гu,шi,щo,зp,х[,ъ],фa,ыs,вd,аf,пg,рh,оj,лk,дl,ж\\;,э',яz,чx,сc,мv,иb,тn,ьm,ю.,ё',ЙQ,ЦW,УE,КR,ЕT,НY,ГU,ШI,ЩO,ЗP,Х\{,Ъ\},ФA,ЫS,ВD,АF,ПG,РH,ОJ,ЛK,ДL,Ж\:,Э\",ЯZ,ЧX,СC,МV,ИB,ТN,ЬM,Б\<,Ю\>\n")
|
||||
|
||||
# End: Langmap Handling #}}}
|
||||
|
@ -94,11 +94,16 @@ class VimInterface(TempFileManager):
|
||||
|
||||
def get_buffer_data(self):
|
||||
buffer_path = self.unique_name_temp(prefix='buffer_')
|
||||
self.send(ESC + ':w! %s\n' % buffer_path)
|
||||
self.send_to_vim(ESC + ':w! %s\n' % buffer_path)
|
||||
if wait_until_file_exists(buffer_path, 50):
|
||||
return read_text_file(buffer_path)[:-1]
|
||||
|
||||
def send(self, s):
|
||||
def send_to_terminal(self, s):
|
||||
"""Types 's' into the terminal."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def send_to_vim(self, s):
|
||||
"""Types 's' into the vim instance under test."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def launch(self, config=[]):
|
||||
@ -121,13 +126,16 @@ class VimInterface(TempFileManager):
|
||||
config_path = self.write_temp('vim_config.vim',
|
||||
textwrap.dedent(os.linesep.join(config + post_config) + '\n'))
|
||||
|
||||
# Note the space to exclude it from shell history.
|
||||
self.send(""" %s -u %s\r\n""" % (self._vim_executable, config_path))
|
||||
# Note the space to exclude it from shell history. Also we always set
|
||||
# NVIM_LISTEN_ADDRESS, even when running vanilla vim, because it will
|
||||
# just not care.
|
||||
self.send_to_terminal(""" NVIM_LISTEN_ADDRESS=/tmp/nvim %s -u %s\r\n""" % (
|
||||
self._vim_executable, config_path))
|
||||
wait_until_file_exists(done_file)
|
||||
self._vim_pid = int(open(pid_file, 'r').read())
|
||||
|
||||
def leave_with_wait(self):
|
||||
self.send(3 * ESC + ':qa!\n')
|
||||
self.send_to_vim(3 * ESC + ':qa!\n')
|
||||
while is_process_running(self._vim_pid):
|
||||
time.sleep(.05)
|
||||
|
||||
@ -139,7 +147,7 @@ class VimInterfaceTmux(VimInterface):
|
||||
self.session = session
|
||||
self._check_version()
|
||||
|
||||
def send(self, s):
|
||||
def _send(self, s):
|
||||
# I did not find any documentation on what needs escaping when sending
|
||||
# to tmux, but it seems like this is all that is needed for now.
|
||||
s = s.replace(';', r'\;')
|
||||
@ -148,6 +156,12 @@ class VimInterfaceTmux(VimInterface):
|
||||
s = s.encode('utf-8')
|
||||
silent_call(['tmux', 'send-keys', '-t', self.session, '-l', s])
|
||||
|
||||
def send_to_terminal(self, s):
|
||||
return self._send(s)
|
||||
|
||||
def send_to_vim(self, s):
|
||||
return self._send(s)
|
||||
|
||||
def _check_version(self):
|
||||
stdout, _ = subprocess.Popen(['tmux', '-V'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||
@ -159,6 +173,33 @@ class VimInterfaceTmux(VimInterface):
|
||||
'Need at least tmux 1.8, you have %s.' %
|
||||
stdout.strip())
|
||||
|
||||
class VimInterfaceTmuxNeovim(VimInterfaceTmux):
|
||||
|
||||
def __init__(self, vim_executable, session):
|
||||
VimInterfaceTmux.__init__(self, vim_executable, session)
|
||||
self._nvim = None
|
||||
|
||||
def send_to_vim(self, s):
|
||||
if s == ARR_L:
|
||||
s = "<Left>"
|
||||
elif s == ARR_R:
|
||||
s = "<Right>"
|
||||
elif s == ARR_U:
|
||||
s = "<Up>"
|
||||
elif s == ARR_D:
|
||||
s = "<Down>"
|
||||
elif s == BS:
|
||||
s = "<bs>"
|
||||
elif s == ESC:
|
||||
s = "<esc>"
|
||||
elif s == "<":
|
||||
s = "<lt>"
|
||||
self._nvim.input(s)
|
||||
|
||||
def launch(self, config=[]):
|
||||
import neovim
|
||||
VimInterfaceTmux.launch(self, config)
|
||||
self._nvim = neovim.attach('socket', path='/tmp/nvim')
|
||||
|
||||
class VimInterfaceWindows(VimInterface):
|
||||
BRACES = re.compile('([}{])')
|
||||
|
@ -9,7 +9,7 @@ import textwrap
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from test.constant import PYTHON3
|
||||
from test.constant import PYTHON3, SEQUENCES
|
||||
from test.vim_interface import create_directory, TempFileManager
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ class VimTestCase(unittest.TestCase, TempFileManager):
|
||||
skip_if = lambda self: None
|
||||
version = None # Will be set to vim --version output
|
||||
maxDiff = None # Show all diff output, always.
|
||||
vim_flavor = None # will be 'vim' or 'neovim'.
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
unittest.TestCase.__init__(self, *args, **kwargs)
|
||||
@ -78,6 +79,7 @@ class VimTestCase(unittest.TestCase, TempFileManager):
|
||||
os.symlink(source, os.path.join(absdir, os.path.basename(source)))
|
||||
|
||||
def setUp(self):
|
||||
# TODO(sirver): this uses 'vim', but must use --vim from the commandline.
|
||||
if not VimTestCase.version:
|
||||
VimTestCase.version, _ = subprocess.Popen(['vim', '--version'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||
@ -110,9 +112,13 @@ class VimTestCase(unittest.TestCase, TempFileManager):
|
||||
'bundle')
|
||||
vim_config.append('execute pathogen#infect()')
|
||||
|
||||
# Vim parameters.
|
||||
# Some configurations are unnecessary for vanilla Vim, but Neovim
|
||||
# defines some defaults differently.
|
||||
vim_config.append('syntax on')
|
||||
vim_config.append('filetype plugin indent on')
|
||||
vim_config.append('set nosmarttab')
|
||||
vim_config.append('set noautoindent')
|
||||
vim_config.append('set backspace=""')
|
||||
vim_config.append('set clipboard=""')
|
||||
vim_config.append('set encoding=utf-8')
|
||||
vim_config.append('set fileencoding=utf-8')
|
||||
@ -127,6 +133,10 @@ class VimTestCase(unittest.TestCase, TempFileManager):
|
||||
'let g:UltiSnipsUsePythonVersion="%i"' %
|
||||
(3 if PYTHON3 else 2))
|
||||
vim_config.append('let g:UltiSnipsSnippetDirectories=["us"]')
|
||||
if self.python_host_prog:
|
||||
vim_config.append('let g:python_host_prog="%s"' % self.python_host_prog)
|
||||
if self.python3_host_prog:
|
||||
vim_config.append('let g:python3_host_prog="%s"' % self.python3_host_prog)
|
||||
|
||||
self._extra_vim_config(vim_config)
|
||||
|
||||
@ -170,9 +180,17 @@ class VimTestCase(unittest.TestCase, TempFileManager):
|
||||
if not self.interrupt:
|
||||
# Go into insert mode and type the keys but leave Vim some time to
|
||||
# react.
|
||||
for c in 'i' + self.keys:
|
||||
self.vim.send(c)
|
||||
text = 'i' + self.keys
|
||||
while text:
|
||||
to_send = None
|
||||
for seq in SEQUENCES:
|
||||
if text.startswith(seq):
|
||||
to_send = seq
|
||||
break
|
||||
to_send = to_send or text[0]
|
||||
self.vim.send_to_vim(to_send)
|
||||
time.sleep(self.sleeptime)
|
||||
text = text[len(to_send):]
|
||||
self.output = self.vim.get_buffer_data()
|
||||
|
||||
def tearDown(self):
|
||||
|
29
test_all.py
29
test_all.py
@ -39,7 +39,8 @@ import os
|
||||
import platform
|
||||
import subprocess
|
||||
import unittest
|
||||
from test.vim_interface import (create_directory, tempfile, VimInterfaceTmux)
|
||||
from test.vim_interface import (
|
||||
create_directory, tempfile, VimInterfaceTmux, VimInterfaceTmuxNeovim)
|
||||
|
||||
|
||||
def plugin_cache_dir():
|
||||
@ -100,8 +101,17 @@ if __name__ == '__main__':
|
||||
'multiplexer and race conditions in writing to the file system.')
|
||||
p.add_option('-x', '--exitfirst', dest='exitfirst', action='store_true',
|
||||
help='exit instantly on first error or failed test.')
|
||||
p.add_option('--vim', dest='vim', type=str, default="vim",
|
||||
p.add_option('--vim', dest='vim', type=str, default='vim',
|
||||
help='executable to run when launching vim.')
|
||||
p.add_option('--interface', dest='interface', type=str, default='tmux',
|
||||
help="Interface to use. Use 'tmux' with vanilla Vim and 'tmux_nvim' "
|
||||
'with Neovim.')
|
||||
p.add_option('--python-host-prog', dest='python_host_prog', type=str, default='',
|
||||
# NOCOM(#sirver): what
|
||||
help="")
|
||||
p.add_option('--python3-host-prog', dest='python3_host_prog', type=str, default='',
|
||||
# NOCOM(#sirver): what
|
||||
help="")
|
||||
|
||||
o, args = p.parse_args()
|
||||
return o, args
|
||||
@ -120,7 +130,15 @@ if __name__ == '__main__':
|
||||
|
||||
all_test_suites = unittest.defaultTestLoader.discover(start_dir='test')
|
||||
|
||||
vim = VimInterfaceTmux(options.vim, options.session)
|
||||
vim = None
|
||||
vim_flavor = 'vim'
|
||||
if options.interface == 'tmux':
|
||||
vim = VimInterfaceTmux(options.vim, options.session)
|
||||
vim_flavor = 'vim'
|
||||
else:
|
||||
vim = VimInterfaceTmuxNeovim(options.vim, options.session)
|
||||
vim_flavor = 'neovim'
|
||||
|
||||
if not options.clone_plugins and platform.system() == 'Windows':
|
||||
raise RuntimeError(
|
||||
'TODO: TestSuite is broken under windows. Volunteers wanted!.')
|
||||
@ -136,7 +154,10 @@ if __name__ == '__main__':
|
||||
test.interrupt = options.interrupt
|
||||
test.retries = options.retries
|
||||
test.test_plugins = options.plugins
|
||||
test.python_host_prog = options.python_host_prog
|
||||
test.python3_host_prog = options.python3_host_prog
|
||||
test.vim = vim
|
||||
test.vim_flavor = vim_flavor
|
||||
all_other_plugins.update(test.plugins)
|
||||
|
||||
if len(selected_tests):
|
||||
@ -153,7 +174,7 @@ if __name__ == '__main__':
|
||||
|
||||
v = 2 if options.verbose else 1
|
||||
successfull = unittest.TextTestRunner(verbosity=v,
|
||||
failfast=options.exitfirst).run(suite).wasSuccessful()
|
||||
failfast=options.exitfirst).run(suite).wasSuccessful()
|
||||
return 0 if successfull else 1
|
||||
sys.exit(main())
|
||||
|
||||
|
@ -56,7 +56,8 @@ build_vanilla_vim () {
|
||||
if [[ $VIM_VERSION = "74" || $VIM_VERSION = "mercurial" ]]; then
|
||||
build_vanilla_vim
|
||||
elif [[ $VIM_VERSION == "NEOVIM" ]]; then
|
||||
pip install neovim
|
||||
PIP=$(which pip)
|
||||
$PIP install neovim
|
||||
else
|
||||
echo "Unknown VIM_VERSION: $VIM_VERSION"
|
||||
exit 1
|
||||
|
@ -2,13 +2,29 @@
|
||||
|
||||
set -ex
|
||||
|
||||
VIM="${HOME}/bin/vim"
|
||||
PYTHON="python${TRAVIS_PYTHON_VERSION}"
|
||||
PYTHON_CMD="$(which ${PYTHON})"
|
||||
|
||||
# This is needed so that vim finds the shared libraries it was build against -
|
||||
# they are not on the regular path.
|
||||
export LD_LIBRARY_PATH="$($PYTHON-config --prefix)/lib"
|
||||
if [[ $VIM_VERSION = "74" || $VIM_VERSION = "mercurial" ]]; then
|
||||
INTERFACE="--interface tmux"
|
||||
VIM="${HOME}/bin/vim"
|
||||
# This is needed so that vim finds the shared libraries it was build against -
|
||||
# they are not on the regular path.
|
||||
export LD_LIBRARY_PATH="$($PYTHON-config --prefix)/lib"
|
||||
|
||||
elif [[ $VIM_VERSION == "NEOVIM" ]]; then
|
||||
VIM="$(which nvim)"
|
||||
if [[ $TRAVIS_PYTHON_VERSION =~ ^2\. ]]; then
|
||||
INTERFACE="--interface tmux_nvim --python-host-prog=$PYTHON_CMD"
|
||||
PY_IN_VIM="py"
|
||||
else
|
||||
INTERFACE="--interface tmux_nvim --python3-host-prog=$PYTHON_CMD"
|
||||
PY_IN_VIM="py3"
|
||||
fi
|
||||
else
|
||||
echo "Unknown VIM_VERSION: $VIM_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $TRAVIS_PYTHON_VERSION =~ ^2\. ]]; then
|
||||
PY_IN_VIM="py"
|
||||
@ -19,9 +35,6 @@ fi
|
||||
echo "Using python from: $PYTHON_CMD Version: $($PYTHON_CMD --version 2>&1)"
|
||||
echo "Using vim from: $VIM. Version: $($VIMn)"
|
||||
|
||||
printf "${PY_IN_VIM} import sys;print(sys.version);\nquit" | $VIM -e -V9myVimLog
|
||||
cat myVimLog
|
||||
|
||||
tmux new -d -s vim
|
||||
|
||||
$PYTHON_CMD ./test_all.py -v --plugins --session vim --vim $VIM
|
||||
$PYTHON_CMD ./test_all.py -v --plugins $INTERFACE --session vim --vim $VIM
|
||||
|
Loading…
Reference in New Issue
Block a user