diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/api/buffer_spec.lua | 118 | ||||
-rw-r--r-- | test/functional/api/server_notifications_spec.lua | 40 | ||||
-rw-r--r-- | test/functional/api/server_requests_spec.lua | 68 | ||||
-rw-r--r-- | test/functional/api/tabpage_spec.lua | 42 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 108 | ||||
-rw-r--r-- | test/functional/api/window_spec.lua | 124 | ||||
-rw-r--r-- | test/functional/helpers.lua | 174 |
7 files changed, 672 insertions, 2 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua new file mode 100644 index 0000000000..169d605b63 --- /dev/null +++ b/test/functional/api/buffer_spec.lua @@ -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) diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua new file mode 100644 index 0000000000..6791fbb4ba --- /dev/null +++ b/test/functional/api/server_notifications_spec.lua @@ -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) diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua new file mode 100644 index 0000000000..b6f56a868c --- /dev/null +++ b/test/functional/api/server_requests_spec.lua @@ -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) diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua new file mode 100644 index 0000000000..9937e0c72e --- /dev/null +++ b/test/functional/api/tabpage_spec.lua @@ -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) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua new file mode 100644 index 0000000000..6a61607d2e --- /dev/null +++ b/test/functional/api/vim_spec.lua @@ -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) diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua new file mode 100644 index 0000000000..a3814cce0f --- /dev/null +++ b/test/functional/api/window_spec.lua @@ -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) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 671e34e592..324af6a232 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -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 } |