Merge PR #1296 'Use the lua client to run functional tests'

This commit is contained in:
Thiago de Arruda
2014-10-16 14:23:36 -03:00
13 changed files with 683 additions and 140 deletions

View File

@@ -1,32 +0,0 @@
. "$CI_SCRIPTS/common.sh"
set_environment /opt/neovim-deps/64
sudo apt-get install expect valgrind
$MAKE_CMD
git clone --depth=1 -b master git://github.com/neovim/python-client
cd python-client
sudo pip install .
sudo pip install nose
# We run the tests twice:
# - First by connecting with an nvim instance spawned by "expect"
# - Second by starting nvim in embedded mode through the python client
# This is required until nvim is mature enough to always run in embedded mode
test_cmd="nosetests --verbosity=2 --nologcapture"
nvim_cmd="valgrind -q --track-origins=yes --leak-check=yes --suppressions=$suppressions --log-file=$tmpdir/valgrind-%p.log ../build/bin/nvim -u NONE"
if ! ../scripts/run-api-tests.exp "$test_cmd" "$nvim_cmd"; then
valgrind_check "$tmpdir"
exit 1
fi
valgrind_check "$tmpdir"
export NVIM_SPAWN_ARGV="[\"valgrind\", \"-q\", \"--track-origins=yes\", \"--leak-check=yes\", \"--suppressions=$suppressions\", \"--log-file=$tmpdir/valgrind-%p.log\", \"../build/bin/nvim\", \"-u\", \"NONE\", \"--embed\"]"
if ! nosetests --verbosity=2 --nologcapture; then
valgrind_check "$tmpdir"
exit 1
fi
valgrind_check "$tmpdir"

View File

@@ -11,7 +11,6 @@ env:
- CI_TARGET=gcc
- CI_TARGET=gcc-32
- CI_TARGET=clint
- CI_TARGET=api-python
- CI_TARGET=coverity
before_install:
# Adds user to a dummy group.

View File

@@ -228,17 +228,9 @@ if(BUSTED_PRG)
-P ${CMAKE_MODULE_PATH}/RunTests.cmake
DEPENDS nvim-test unittest-headers)
# For the functional tests we need the full path to the real busted script,
# which will be included by run-functional-tests.py.
get_filename_component(LUA_PRG_DIR ${LUA_PRG} PATH)
get_filename_component(LUA_PREFIX_DIR ${LUA_PRG_DIR} PATH)
file(GLOB_RECURSE BUSTED_REAL_PRG
${LUA_PREFIX_DIR}/lib/luarocks/rocks/busted/*busted)
add_custom_target(test
COMMAND ${CMAKE_COMMAND}
-DBUSTED_PRG=${PROJECT_SOURCE_DIR}/scripts/run-functional-tests.py
-DBUSTED_REAL_PRG=${BUSTED_REAL_PRG}
-DBUSTED_PRG=${BUSTED_PRG}
-DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test

View File

@@ -6,8 +6,8 @@ endif()
if(TEST_TYPE STREQUAL "functional")
execute_process(
COMMAND python ${BUSTED_PRG} ${BUSTED_REAL_PRG} -v -o
${BUSTED_OUTPUT_TYPE} --lpath=${BUILD_DIR}/?.lua ${TEST_DIR}/functional
COMMAND ${BUSTED_PRG} -v -o ${BUSTED_OUTPUT_TYPE}
--lpath=${BUILD_DIR}/?.lua ${TEST_DIR}/functional
WORKING_DIRECTORY ${WORKING_DIR}
RESULT_VARIABLE res)
else()

View File

@@ -1,93 +0,0 @@
# Run functional tests using lua, busted and the python client
import os
import sys
import textwrap
from lupa import LuaRuntime, as_attrgetter
from neovim import Nvim, spawn_session
# Extract arguments
busted_script = sys.argv[1]
busted_argv = sys.argv[2:]
# Setup a lua state for running busted
lua = LuaRuntime(unpack_returned_tuples=True)
lua_globals = lua.globals()
# helper to transform iterables into lua tables
list_to_table = lua.eval('''
function(l)
local t = {}
for i, item in python.enumerate(l) do t[i + 1] = item end
return t
end
''')
dict_to_table = lua.eval('''
function(d)
local t = {}
for k, v in python.iterex(d.items()) do t[k] = v end
return t
end
''')
def to_table(obj):
if type(obj) in [tuple, list]:
return list_to_table(list(to_table(e) for e in obj))
if type(obj) is dict:
return dict_to_table(as_attrgetter(
dict((k, to_table(v)) for k, v in obj.items())))
return obj
nvim_prog = os.environ.get('NVIM_PROG', 'build/bin/nvim')
nvim_argv = [nvim_prog, '-u', 'NONE', '--embed']
if 'VALGRIND' in os.environ:
log_file = os.environ.get('VALGRIND_LOG', 'valgrind-%p.log')
valgrind_argv = ['valgrind', '-q', '--tool=memcheck', '--leak-check=yes',
'--track-origins=yes', '--suppressions=.valgrind.supp',
'--log-file={0}'.format(log_file)]
if 'VALGRIND_GDB' in os.environ:
valgrind_argv += ['--vgdb=yes', '--vgdb-error=0']
nvim_argv = valgrind_argv + nvim_argv
session = spawn_session(nvim_argv)
nvim = Nvim.from_session(session)
def nvim_command(cmd):
nvim.command(cmd)
def nvim_eval(expr):
return to_table(nvim.eval(expr))
def nvim_feed(input, mode=''):
nvim.feedkeys(input)
def buffer_slice(start=None, stop=None, buffer_idx=None):
rv = '\n'.join(nvim.buffers[buffer_idx or 0][start:stop])
return rv
def nvim_replace_termcodes(input, *opts):
return nvim.replace_termcodes(input, *opts)
expose = [
nvim_command,
nvim_eval,
nvim_feed,
nvim_replace_termcodes,
buffer_slice,
textwrap.dedent,
]
for fn in expose:
lua_globals[fn.__name__] = fn
# Set 'arg' global to let busted parse arguments
lua_globals['arg'] = list_to_table(busted_argv)
# Read the busted script and execute in the lua state
with open(busted_script) as f:
busted_setup = f.read()
lua.execute(busted_setup)

View File

@@ -0,0 +1,118 @@
-- Sanity checks for buffer_* API calls via msgpack-rpc
local helpers = require('test.functional.helpers')
local clear, nvim, buffer, curbuf, curwin, eq, ok =
helpers.clear, helpers.nvim, helpers.buffer, helpers.curbuf, helpers.curwin,
helpers.eq, helpers.ok
describe('buffer_* functions', function()
before_each(clear)
describe('line_count, insert and del_line', function()
it('works', function()
eq(1, curbuf('line_count'))
curbuf('insert', -1, {'line'})
eq(2, curbuf('line_count'))
curbuf('insert', -1, {'line'})
eq(3, curbuf('line_count'))
curbuf('del_line', -1)
eq(2, curbuf('line_count'))
curbuf('del_line', -1)
curbuf('del_line', -1)
-- There's always at least one line
eq(1, curbuf('line_count'))
end)
end)
describe('{get,set,del}_line', function()
it('works', function()
eq('', curbuf('get_line', 0))
curbuf('set_line', 0, 'line1')
eq('line1', curbuf('get_line', 0))
curbuf('set_line', 0, 'line2')
eq('line2', curbuf('get_line', 0))
curbuf('del_line', 0)
eq('', curbuf('get_line', 0))
end)
end)
describe('{get,set}_line_slice', function()
it('works', function()
eq({''}, curbuf('get_line_slice', 0, -1, true, true))
-- Replace buffer
curbuf('set_line_slice', 0, -1, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
eq({'b', 'c'}, curbuf('get_line_slice', 1, -1, true, true))
eq({'b'}, curbuf('get_line_slice', 1, 2, true, false))
eq({}, curbuf('get_line_slice', 1, 1, true, false))
eq({'a', 'b'}, curbuf('get_line_slice', 0, -1, true, false))
eq({'b'}, curbuf('get_line_slice', 1, -1, true, false))
eq({'b', 'c'}, curbuf('get_line_slice', -2, -1, true, true))
curbuf('set_line_slice', 1, 2, true, false, {'a', 'b', 'c'})
eq({'a', 'a', 'b', 'c', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', -1, -1, true, true, {'a', 'b', 'c'})
eq({'a', 'a', 'b', 'c', 'a', 'b', 'c'},
curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', 0, -3, true, false, {})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', 0, -1, true, true, {})
eq({''}, curbuf('get_line_slice', 0, -1, true, true))
end)
end)
describe('{get,set}_var', function()
it('works', function()
curbuf('set_var', 'lua', {1, 2, {['3'] = 1}})
eq({1, 2, {['3'] = 1}}, curbuf('get_var', 'lua'))
eq({1, 2, {['3'] = 1}}, nvim('eval', 'b:lua'))
end)
end)
describe('{get,set}_option', function()
it('works', function()
eq(8, curbuf('get_option', 'shiftwidth'))
curbuf('set_option', 'shiftwidth', 4)
eq(4, curbuf('get_option', 'shiftwidth'))
-- global-local option
curbuf('set_option', 'define', 'test')
eq('test', curbuf('get_option', 'define'))
-- Doesn't change the global value
eq([[^\s*#\s*define]], nvim('get_option', 'define'))
end)
end)
describe('{get,set}_name', function()
it('works', function()
nvim('command', 'new')
eq('', curbuf('get_name'))
local new_name = nvim('eval', 'resolve(tempname())')
curbuf('set_name', new_name)
eq(new_name, curbuf('get_name'))
nvim('command', 'w!')
local f = io.open(new_name)
ok(f ~= nil)
f:close()
os.remove(new_name)
end)
end)
describe('is_valid', function()
it('works', function()
nvim('command', 'new')
local b = nvim('get_current_buffer')
ok(buffer('is_valid', b))
nvim('command', 'bw!')
ok(not buffer('is_valid', b))
end)
end)
describe('get_mark', function()
it('works', function()
curbuf('insert', -1, {'a', 'bit of', 'text'})
curwin('set_cursor', {3, 4})
nvim('command', 'mark V')
eq({3, 0}, curbuf('get_mark', 'V'))
end)
end)
end)

View File

@@ -0,0 +1,40 @@
-- Tests for nvim notifications
local helpers = require('test.functional.helpers')
local eq, clear, eval, execute, nvim, next_message =
helpers.eq, helpers.clear, helpers.eval, helpers.execute, helpers.nvim,
helpers.next_message
describe('notify', function()
local channel
before_each(function()
clear()
channel = nvim('get_api_info')[1]
end)
describe('passing a valid channel id', function()
it('sends the notification/args to the corresponding channel', function()
eval('rpcnotify('..channel..', "test-event", 1, 2, 3)')
eq({'notification', 'test-event', {1, 2, 3}}, next_message())
execute('au FileType lua call rpcnotify('..channel..', "lua!")')
execute('set filetype=lua')
eq({'notification', 'lua!', {}}, next_message())
end)
end)
describe('passing 0 as the channel id', function()
it('sends the notification/args to all subscribed channels', function()
nvim('subscribe', 'event2')
eval('rpcnotify(0, "event1", 1, 2, 3)')
eval('rpcnotify(0, "event2", 4, 5, 6)')
eval('rpcnotify(0, "event2", 7, 8, 9)')
eq({'notification', 'event2', {4, 5, 6}}, next_message())
eq({'notification', 'event2', {7, 8, 9}}, next_message())
nvim('unsubscribe', 'event2')
nvim('subscribe', 'event1')
eval('rpcnotify(0, "event2", 10, 11, 12)')
eval('rpcnotify(0, "event1", 13, 14, 15)')
eq({'notification', 'event1', {13, 14, 15}}, next_message())
end)
end)
end)

View File

@@ -0,0 +1,68 @@
-- Tests for some server->client RPC scenarios. Note that unlike with
-- `rpcnotify`, to evaluate `rpcrequest` calls we need the client event loop to
-- be running.
local helpers = require('test.functional.helpers')
local clear, nvim, eval, eq, run, stop = helpers.clear, helpers.nvim,
helpers.eval, helpers.eq, helpers.run, helpers.stop
describe('server -> client', function()
local cid
before_each(function()
clear()
cid = nvim('get_api_info')[1]
end)
describe('simple call', function()
it('works', function()
local function on_setup()
eq({4, 5, 6}, eval('rpcrequest('..cid..', "scall", 1, 2, 3)'))
stop()
end
local function on_request(method, args)
eq('scall', method)
eq({1, 2, 3}, args)
nvim('command', 'let g:result = [4, 5, 6]')
return eval('g:result')
end
run(on_request, nil, on_setup)
end)
end)
describe('recursive call', function()
it('works', function()
local function on_setup()
nvim('set_var', 'result1', 0)
nvim('set_var', 'result2', 0)
nvim('set_var', 'result3', 0)
nvim('set_var', 'result4', 0)
nvim('command', 'let g:result1 = rpcrequest('..cid..', "rcall", 2)')
eq(4, nvim('get_var', 'result1'))
eq(8, nvim('get_var', 'result2'))
eq(16, nvim('get_var', 'result3'))
eq(32, nvim('get_var', 'result4'))
stop()
end
local function on_request(method, args)
eq('rcall', method)
local n = unpack(args) * 2
if n <= 16 then
local cmd
if n == 4 then
cmd = 'let g:result2 = rpcrequest('..cid..', "rcall", '..n..')'
elseif n == 8 then
cmd = 'let g:result3 = rpcrequest('..cid..', "rcall", '..n..')'
elseif n == 16 then
cmd = 'let g:result4 = rpcrequest('..cid..', "rcall", '..n..')'
end
nvim('command', cmd)
end
return n
end
run(on_request, nil, on_setup)
end)
end)
end)

View File

@@ -0,0 +1,42 @@
-- Sanity checks for tabpage_* API calls via msgpack-rpc
local helpers = require('test.functional.helpers')
local clear, nvim, tabpage, curtab, eq, ok =
helpers.clear, helpers.nvim, helpers.tabpage, helpers.curtab, helpers.eq,
helpers.ok
describe('tabpage_* functions', function()
before_each(clear)
describe('get_windows and get_window', function()
it('works', function()
nvim('command', 'tabnew')
nvim('command', 'vsplit')
local tab1, tab2 = unpack(nvim('get_tabpages'))
local win1, win2, win3 = unpack(nvim('get_windows'))
eq({win1}, tabpage('get_windows', tab1))
eq({win2, win3}, tabpage('get_windows', tab2))
eq(win2, tabpage('get_window', tab2))
nvim('set_current_window', win3)
eq(win3, tabpage('get_window', tab2))
end)
end)
describe('{get,set}_var', function()
it('works', function()
curtab('set_var', 'lua', {1, 2, {['3'] = 1}})
eq({1, 2, {['3'] = 1}}, curtab('get_var', 'lua'))
eq({1, 2, {['3'] = 1}}, nvim('eval', 't:lua'))
end)
end)
describe('is_valid', function()
it('works', function()
nvim('command', 'tabnew')
local tab = nvim('get_tabpages')[2]
nvim('set_current_tabpage', tab)
ok(tabpage('is_valid', tab))
nvim('command', 'tabclose')
ok(not tabpage('is_valid', tab))
end)
end)
end)

View File

@@ -0,0 +1,108 @@
-- Sanity checks for vim_* API calls via msgpack-rpc
local helpers = require('test.functional.helpers')
local clear, nvim, eq, ok = helpers.clear, helpers.nvim, helpers.eq, helpers.ok
describe('vim_* functions', function()
before_each(clear)
describe('command', function()
it('works', function()
local fname = os.tmpname()
nvim('command', 'new')
nvim('command', 'edit '..fname)
nvim('command', 'normal itesting\napi')
nvim('command', 'w')
local f = io.open(fname)
ok(f ~= nil)
eq('testing\napi\n', f:read('*a'))
f:close()
os.remove(fname)
end)
end)
describe('eval', function()
it('works', function()
nvim('command', 'let g:v1 = "a"')
nvim('command', 'let g:v2 = [1, 2, {"v3": 3}]')
eq({v1 = 'a', v2 = {1, 2, {v3 = 3}}}, nvim('eval', 'g:'))
end)
end)
describe('strwidth', function()
it('works', function()
eq(3, nvim('strwidth', 'abc'))
-- 6 + (neovim)
-- 19 * 2 (each japanese character occupies two cells)
eq(44, nvim('strwidth', 'neovimのデザインかなりまともなのになってる。'))
end)
end)
describe('{get,set}_current_line', function()
it('works', function()
eq('', nvim('get_current_line'))
nvim('set_current_line', 'abc')
eq('abc', nvim('get_current_line'))
end)
end)
describe('{get,set}_var', function()
it('works', function()
nvim('set_var', 'lua', {1, 2, {['3'] = 1}})
eq({1, 2, {['3'] = 1}}, nvim('get_var', 'lua'))
eq({1, 2, {['3'] = 1}}, nvim('eval', 'g:lua'))
end)
end)
describe('{get,set}_option', function()
it('works', function()
ok(nvim('get_option', 'equalalways'))
nvim('set_option', 'equalalways', false)
ok(not nvim('get_option', 'equalalways'))
end)
end)
describe('{get,set}_current_buffer and get_buffers', function()
it('works', function()
eq(1, #nvim('get_buffers'))
eq(nvim('get_buffers')[1], nvim('get_current_buffer'))
nvim('command', 'new')
eq(2, #nvim('get_buffers'))
eq(nvim('get_buffers')[2], nvim('get_current_buffer'))
nvim('set_current_buffer', nvim('get_buffers')[1])
eq(nvim('get_buffers')[1], nvim('get_current_buffer'))
end)
end)
describe('{get,set}_current_window and get_windows', function()
it('works', function()
eq(1, #nvim('get_windows'))
eq(nvim('get_windows')[1], nvim('get_current_window'))
nvim('command', 'vsplit')
nvim('command', 'split')
eq(3, #nvim('get_windows'))
eq(nvim('get_windows')[1], nvim('get_current_window'))
nvim('set_current_window', nvim('get_windows')[2])
eq(nvim('get_windows')[2], nvim('get_current_window'))
end)
end)
describe('{get,set}_current_tabpage and get_tabpages', function()
it('works', function()
eq(1, #nvim('get_tabpages'))
eq(nvim('get_tabpages')[1], nvim('get_current_tabpage'))
nvim('command', 'tabnew')
eq(2, #nvim('get_tabpages'))
eq(2, #nvim('get_windows'))
eq(nvim('get_windows')[2], nvim('get_current_window'))
eq(nvim('get_tabpages')[2], nvim('get_current_tabpage'))
nvim('set_current_window', nvim('get_windows')[1])
-- Switching window also switches tabpages if necessary
eq(nvim('get_tabpages')[1], nvim('get_current_tabpage'))
eq(nvim('get_windows')[1], nvim('get_current_window'))
nvim('set_current_tabpage', nvim('get_tabpages')[2])
eq(nvim('get_tabpages')[2], nvim('get_current_tabpage'))
eq(nvim('get_windows')[2], nvim('get_current_window'))
end)
end)
end)

View File

@@ -0,0 +1,124 @@
-- Sanity checks for window_* API calls via msgpack-rpc
local helpers = require('test.functional.helpers')
local clear, nvim, buffer, curbuf, curbuf_contents, window, curwin, eq, neq,
ok = helpers.clear, helpers.nvim, helpers.buffer, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
helpers.neq, helpers.ok
describe('window_* functions', function()
before_each(clear)
describe('get_buffer', function()
it('works', function()
eq(curbuf(), window('get_buffer', nvim('get_windows')[1]))
nvim('command', 'new')
nvim('set_current_window', nvim('get_windows')[2])
eq(curbuf(), window('get_buffer', nvim('get_windows')[2]))
neq(window('get_buffer', nvim('get_windows')[1]),
window('get_buffer', nvim('get_windows')[2]))
end)
end)
describe('{get,set}_cursor', function()
it('works', function()
eq({1, 0}, curwin('get_cursor'))
nvim('command', 'normal ityping\027o some text')
eq('typing\n some text', curbuf_contents())
eq({2, 10}, curwin('get_cursor'))
curwin('set_cursor', {2, 6})
nvim('command', 'normal i dumb')
eq('typing\n some dumb text', curbuf_contents())
end)
end)
describe('{get,set}_height', function()
it('works', function()
nvim('command', 'vsplit')
eq(window('get_height', nvim('get_windows')[2]),
window('get_height', nvim('get_windows')[1]))
nvim('set_current_window', nvim('get_windows')[2])
nvim('command', 'split')
eq(window('get_height', nvim('get_windows')[2]),
window('get_height', nvim('get_windows')[1]) / 2)
window('set_height', nvim('get_windows')[2], 2)
eq(2, window('get_height', nvim('get_windows')[2]))
end)
end)
describe('{get,set}_width', function()
it('works', function()
nvim('command', 'split')
eq(window('get_width', nvim('get_windows')[2]),
window('get_width', nvim('get_windows')[1]))
nvim('set_current_window', nvim('get_windows')[2])
nvim('command', 'vsplit')
eq(window('get_width', nvim('get_windows')[2]),
window('get_width', nvim('get_windows')[1]) / 2)
window('set_width', nvim('get_windows')[2], 2)
eq(2, window('get_width', nvim('get_windows')[2]))
end)
end)
describe('{get,set}_var', function()
it('works', function()
curwin('set_var', 'lua', {1, 2, {['3'] = 1}})
eq({1, 2, {['3'] = 1}}, curwin('get_var', 'lua'))
eq({1, 2, {['3'] = 1}}, nvim('eval', 'w:lua'))
end)
end)
describe('{get,set}_option', function()
it('works', function()
curwin('set_option', 'colorcolumn', '4,3')
eq('4,3', curwin('get_option', 'colorcolumn'))
-- global-local option
curwin('set_option', 'statusline', 'window-status')
eq('window-status', curwin('get_option', 'statusline'))
eq('', nvim('get_option', 'statusline'))
end)
end)
describe('get_position', function()
it('works', function()
local height = window('get_height', nvim('get_windows')[1])
local width = window('get_width', nvim('get_windows')[1])
nvim('command', 'split')
nvim('command', 'vsplit')
eq({0, 0}, window('get_position', nvim('get_windows')[1]))
local vsplit_pos = math.floor(width / 2)
local split_pos = math.floor(height / 2)
local win2row, win2col =
unpack(window('get_position', nvim('get_windows')[2]))
local win3row, win3col =
unpack(window('get_position', nvim('get_windows')[3]))
eq(0, win2row)
eq(0, win3col)
ok(vsplit_pos - 1 <= win2col and win2col <= vsplit_pos + 1)
ok(split_pos - 1 <= win3row and win3row <= split_pos + 1)
end)
end)
describe('get_position', function()
it('works', function()
nvim('command', 'tabnew')
nvim('command', 'vsplit')
eq(window('get_tabpage',
nvim('get_windows')[1]), nvim('get_tabpages')[1])
eq(window('get_tabpage',
nvim('get_windows')[2]), nvim('get_tabpages')[2])
eq(window('get_tabpage',
nvim('get_windows')[3]), nvim('get_tabpages')[2])
end)
end)
describe('is_valid', function()
it('works', function()
nvim('command', 'split')
local win = nvim('get_windows')[2]
nvim('set_current_window', win)
ok(window('is_valid', win))
nvim('command', 'close')
ok(not window('is_valid', win))
end)
end)
end)

View File

@@ -1,3 +1,110 @@
local Loop = require('nvim.loop')
local MsgpackStream = require('nvim.msgpack_stream')
local AsyncSession = require('nvim.async_session')
local Session = require('nvim.session')
local nvim_prog = os.getenv('NVIM_PROG') or 'build/bin/nvim'
local nvim_argv = {nvim_prog, '-u', 'NONE', '-N', '--embed'}
if os.getenv('VALGRIND') then
local log_file = os.getenv('VALGRIND_LOG') or 'valgrind-%p.log'
local valgrind_argv = {'valgrind', '-q', '--tool=memcheck',
'--leak-check=yes', '--track-origins=yes',
'--suppressions=.valgrind.supp',
'--log-file='..log_file}
if os.getenv('VALGRIND_GDB') then
table.insert(valgrind_argv, '--vgdb=yes')
table.insert(valgrind_argv, '--vgdb-error=0')
end
local len = #valgrind_argv
for i = 1, #nvim_argv do
valgrind_argv[i + len] = nvim_argv[i]
end
nvim_argv = valgrind_argv
end
local session
local function restart()
local loop = Loop.new()
local msgpack_stream = MsgpackStream.new(loop)
local async_session = AsyncSession.new(msgpack_stream)
session = Session.new(async_session)
loop:spawn(nvim_argv)
end
restart()
local function request(method, ...)
local status, rv = session:request(method, ...)
if not status then
error(rv[2])
end
return rv
end
local function next_message()
return session:next_message()
end
local function run(request_cb, notification_cb, setup_cb)
session:run(request_cb, notification_cb, setup_cb)
end
local function stop()
session:stop()
end
local function nvim_command(cmd)
request('vim_command', cmd)
end
local function nvim_eval(expr)
return request('vim_eval', expr)
end
local function nvim_feed(input, mode)
mode = mode or ''
request('vim_feedkeys', input, mode)
end
local function buffer_slice(start, stop, buffer_idx)
local include_end = false
if not stop then
stop = -1
include_end = true
end
local buffer = request('vim_get_buffers')[buffer_idx or 1]
local slice = request('buffer_get_line_slice', buffer, start or 0, stop,
true, include_end)
return table.concat(slice, '\n')
end
local function nvim_replace_termcodes(input)
return request('vim_replace_termcodes', input, false, true, true )
end
local function dedent(str)
-- find minimum common indent across lines
local indent = nil
for line in str:gmatch('[^\n]+') do
local line_indent = line:match('^%s+') or ''
if indent == nil or #line_indent < #indent then
indent = line_indent
end
end
if #indent == 0 then
-- no minimum common indent
return str
end
-- create a pattern for the indent
indent = indent:gsub('%s', '%%s')
-- strip it from the first line
str = str:gsub('^'..indent, '')
-- strip it from the remaining lines
str = str:gsub('[\n]'..indent, '\n')
return str
end
local function clear()
nvim_command('call BeforeEachTest()')
end
@@ -48,7 +155,7 @@ local function neq(expected, actual)
end
local function expect(contents, first, last, buffer_index)
return eq(dedent(contents), buffer_slice(first, last, buffer_idx))
return eq(dedent(contents), buffer_slice(first, last, buffer_index))
end
rawfeed([[:function BeforeEachTest()
@@ -89,14 +196,77 @@ rawfeed([[:function BeforeEachTest()
endfunction
]])
local function ok(expr)
assert.is_true(expr)
end
local function nvim(method, ...)
return request('vim_'..method, ...)
end
local function buffer(method, ...)
return request('buffer_'..method, ...)
end
local function window(method, ...)
return request('window_'..method, ...)
end
local function tabpage(method, ...)
return request('tabpage_'..method, ...)
end
local function curbuf(method, ...)
local buf = nvim('get_current_buffer')
if not method then
return buf
end
return buffer(method, buf, ...)
end
local function curbuf_contents()
return table.concat(curbuf('get_line_slice', 0, -1, true, true), '\n')
end
local function curwin(method, ...)
local win = nvim('get_current_window')
if not method then
return win
end
return window(method, win, ...)
end
local function curtab(method, ...)
local tab = nvim('get_current_tabpage')
if not method then
return tab
end
return tabpage(method, tab, ...)
end
return {
clear = clear,
restart = restart,
rawfeed = rawfeed,
insert = insert,
feed = feed,
execute = execute,
eval = eval,
request = request,
next_message = next_message,
run = run,
stop = stop,
eq = eq,
neq = neq,
expect = expect
expect = expect,
ok = ok,
nvim = nvim,
buffer = buffer,
window = window,
tabpage = tabpage,
curbuf = curbuf,
curwin = curwin,
curtab = curtab,
curbuf_contents = curbuf_contents
}

View File

@@ -189,7 +189,14 @@ if(USE_BUNDLED_LUAROCKS)
add_custom_target(lpeg
DEPENDS ${DEPS_LIB_DIR}/luarocks/rocks/lpeg)
list(APPEND THIRD_PARTY_DEPS busted lua-messagepack lpeg)
add_custom_command(OUTPUT ${DEPS_LIB_DIR}/luarocks/rocks/nvim-client
COMMAND ${DEPS_BIN_DIR}/luarocks
ARGS build https://raw.githubusercontent.com/neovim/lua-client/master/nvim-client-0.0.1-1.rockspec CC=${DEPS_C_COMPILER} LD=${DEPS_C_COMPILER} LIBUV_DIR=${DEPS_INSTALL_DIR}
DEPENDS lpeg libuv)
add_custom_target(nvim-client
DEPENDS ${DEPS_LIB_DIR}/luarocks/rocks/nvim-client)
list(APPEND THIRD_PARTY_DEPS busted lua-messagepack lpeg nvim-client)
endif()
add_custom_target(third-party ALL