test: Use lua to perform sanity API checks

Sanity API checks made by the python-client in the api-python travis target were
converted to lua and will now live in this repository. This will simplify
performing breaking changes to the API as it won't be necessary to send parallel
PRs the python-client.
This commit is contained in:
Thiago de Arruda 2014-10-08 13:56:01 -03:00
parent 69561ea922
commit 0c2ec77ae0
9 changed files with 580 additions and 36 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

@ -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

@ -24,13 +24,15 @@ if os.getenv('VALGRIND') then
end
local session
do
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, ...)
@ -40,6 +42,18 @@ local function request(method, ...)
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
@ -141,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()
@ -182,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
}