diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2021-09-17 09:16:40 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-17 09:16:40 -0700 |
| commit | d8de4eb685e35646c7d541e9a75bdc296127b7e2 (patch) | |
| tree | 4bb05ec713856715ac9ba57e5d116eed344511b9 /test/functional/eval | |
| parent | d56002f7b722facd97b0958e141c8ed2d01495f7 (diff) | |
| download | rneovim-d8de4eb685e35646c7d541e9a75bdc296127b7e2.tar.gz rneovim-d8de4eb685e35646c7d541e9a75bdc296127b7e2.tar.bz2 rneovim-d8de4eb685e35646c7d541e9a75bdc296127b7e2.zip | |
test: reorg #15698
Problem:
Subdirectories like "visual", "insert", "normal" encourage people to
separate *related* tests for no good reason. Typically the _mode_ is
not the relevant topic of a test (and when it is, _then_ create
an appropriate describe() or it()).
Solution:
- Delete the various `test/functional/<mode>/` subdirectories, move
their tests to more meaningful topics.
- Rename `…/normal/` to `…/editor/`.
- Move or merge `…/visual/*` and `…/insert/*` tests into here where
appropriate.
- Rename `…/eval/` to `…/vimscript/`.
- Move `…/viml/*` into here also.
* test(reorg): insert/* => editor/mode_insert_spec.lua
* test(reorg): cmdline/* => editor/mode_cmdline_spec.lua
* test(reorg): eval core tests => eval_spec.lua
Diffstat (limited to 'test/functional/eval')
40 files changed, 0 insertions, 6914 deletions
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua deleted file mode 100644 index d07e74d40e..0000000000 --- a/test/functional/eval/api_functions_spec.lua +++ /dev/null @@ -1,167 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') -local lfs = require('lfs') -local neq, eq, command = helpers.neq, helpers.eq, helpers.command -local clear, curbufmeths = helpers.clear, helpers.curbufmeths -local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval -local insert, pcall_err = helpers.insert, helpers.pcall_err -local meths = helpers.meths - -describe('eval-API', function() - before_each(clear) - - it("work", function() - command("call nvim_command('let g:test = 1')") - eq(1, eval("nvim_get_var('test')")) - - local buf = eval("nvim_get_current_buf()") - command("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])") - expect([[ - aa - bb]]) - - command("call nvim_win_set_cursor(0, [1, 1])") - command("call nvim_input('ax<esc>')") - expect([[ - aax - bb]]) - end) - - it("throw errors for invalid arguments", function() - local err = exc_exec('call nvim_get_current_buf("foo")') - eq('Vim(call):E118: Too many arguments for function: nvim_get_current_buf', err) - - err = exc_exec('call nvim_set_option("hlsearch")') - eq('Vim(call):E119: Not enough arguments for function: nvim_set_option', err) - - err = exc_exec('call nvim_buf_set_lines(1, 0, -1, [], ["list"])') - eq('Vim(call):E5555: API call: Wrong type for argument 4 when calling nvim_buf_set_lines, expecting Boolean', err) - - err = exc_exec('call nvim_buf_set_lines(0, 0, -1, v:true, "string")') - eq('Vim(call):E5555: API call: Wrong type for argument 5 when calling nvim_buf_set_lines, expecting ArrayOf(String)', err) - - err = exc_exec('call nvim_buf_get_number("0")') - eq('Vim(call):E5555: API call: Wrong type for argument 1 when calling nvim_buf_get_number, expecting Buffer', err) - - err = exc_exec('call nvim_buf_line_count(17)') - eq('Vim(call):E5555: API call: Invalid buffer id: 17', err) - end) - - it('cannot change texts if textlocked', function() - command("autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])") - eq('Vim(call):E5555: API call: E523: Not allowed here', pcall_err(command, "normal! yy")) - end) - - it("use buffer numbers and windows ids as handles", function() - local screen = Screen.new(40, 8) - screen:attach() - local bnr = eval("bufnr('')") - local bhnd = eval("nvim_get_current_buf()") - local wid = eval("win_getid()") - local whnd = eval("nvim_get_current_win()") - eq(bnr, bhnd) - eq(wid, whnd) - - command("new") -- creates new buffer and new window - local bnr2 = eval("bufnr('')") - local bhnd2 = eval("nvim_get_current_buf()") - local wid2 = eval("win_getid()") - local whnd2 = eval("nvim_get_current_win()") - eq(bnr2, bhnd2) - eq(wid2, whnd2) - neq(bnr, bnr2) - neq(wid, wid2) - -- 0 is synonymous to the current buffer - eq(bnr2, eval("nvim_buf_get_number(0)")) - - command("bn") -- show old buffer in new window - eq(bnr, eval("nvim_get_current_buf()")) - eq(bnr, eval("bufnr('')")) - eq(bnr, eval("nvim_buf_get_number(0)")) - eq(wid2, eval("win_getid()")) - eq(whnd2, eval("nvim_get_current_win()")) - end) - - it("get_lines and set_lines use NL to represent NUL", function() - curbufmeths.set_lines(0, -1, true, {"aa\0", "b\0b"}) - eq({'aa\n', 'b\nb'}, eval("nvim_buf_get_lines(0, 0, -1, 1)")) - - command('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])') - eq({'aa\0', 'xx', '\0yy'}, curbufmeths.get_lines(0, -1, 1)) - end) - - it("that are FUNC_ATTR_NOEVAL cannot be called", function() - -- Deprecated vim_ prefix is not exported. - local err = exc_exec('call vim_get_current_buffer("foo")') - eq('Vim(call):E117: Unknown function: vim_get_current_buffer', err) - - -- Deprecated buffer_ prefix is not exported. - err = exc_exec('call buffer_line_count(0)') - eq('Vim(call):E117: Unknown function: buffer_line_count', err) - - -- Functions deprecated before the api functions became available - -- in vimscript are not exported. - err = exc_exec('call buffer_get_line(0, 1)') - eq('Vim(call):E117: Unknown function: buffer_get_line', err) - - -- some api functions are only useful from a msgpack-rpc channel - err = exc_exec('call nvim_subscribe("fancyevent")') - eq('Vim(call):E117: Unknown function: nvim_subscribe', err) - end) - - it('have metadata accessible with api_info()', function() - local api_keys = eval("sort(keys(api_info()))") - eq({'error_types', 'functions', 'types', - 'ui_events', 'ui_options', 'version'}, api_keys) - end) - - it('are highlighted by vim.vim syntax file', function() - if lfs.attributes("build/runtime/syntax/vim/generated.vim",'uid') == nil then - pending("runtime was not built, skipping test") - return - end - local screen = Screen.new(40, 8) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Brown}, - [2] = {foreground = Screen.colors.DarkCyan}, - [3] = {foreground = Screen.colors.SlateBlue}, - [4] = {foreground = Screen.colors.Fuchsia}, - [5] = {bold = true, foreground = Screen.colors.Blue}, - }) - - command("set ft=vim") - command("let &rtp='build/runtime/,'.&rtp") - command("syntax on") - insert([[ - call bufnr('%') - call nvim_input('typing...') - call not_a_function(42)]]) - - screen:expect([[ - {1:call} {2:bufnr}{3:(}{4:'%'}{3:)} | - {1:call} {2:nvim_input}{3:(}{4:'typing...'}{3:)} | - {1:call} not_a_function{3:(}{4:42}{3:^)} | - {5:~ }| - {5:~ }| - {5:~ }| - {5:~ }| - | - ]]) - end) - - it('cannot be called from sandbox', function() - eq('Vim(call):E48: Not allowed in sandbox', - pcall_err(command, "sandbox call nvim_input('ievil')")) - eq({''}, meths.buf_get_lines(0, 0, -1, true)) - end) - - it('converts blobs to API strings', function() - command('let g:v1 = nvim__id(0z68656c6c6f)') - command('let g:v2 = nvim__id(v:_null_blob)') - eq(1, eval('type(g:v1)')) - eq(1, eval('type(g:v2)')) - eq('hello', eval('g:v1')) - eq('', eval('g:v2')) - end) -end) diff --git a/test/functional/eval/backtick_expansion_spec.lua b/test/functional/eval/backtick_expansion_spec.lua deleted file mode 100644 index b1b44cfa8b..0000000000 --- a/test/functional/eval/backtick_expansion_spec.lua +++ /dev/null @@ -1,50 +0,0 @@ -local lfs = require('lfs') -local helpers = require('test.functional.helpers')(after_each) -local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq -local write_file = helpers.write_file - -describe("backtick expansion", function() - setup(function() - clear() - lfs.mkdir("test-backticks") - write_file("test-backticks/file1", "test file 1") - write_file("test-backticks/file2", "test file 2") - write_file("test-backticks/file3", "test file 3") - lfs.mkdir("test-backticks/subdir") - write_file("test-backticks/subdir/file4", "test file 4") - -- Long path might cause "Press ENTER" prompt; use :silent to avoid it. - command('silent cd test-backticks') - end) - - teardown(function() - helpers.rmdir('test-backticks') - end) - - it("with default 'shell'", function() - if helpers.iswin() then - command(":silent args `dir /b *2`") - else - command(":silent args `echo ***2`") - end - eq({ "file2", }, eval("argv()")) - if helpers.iswin() then - command(":silent args `dir /s/b *4`") - eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')")) - else - command(":silent args `echo */*4`") - eq({ "subdir/file4", }, eval("argv()")) - end - end) - - it("with shell=fish", function() - if eval("executable('fish')") == 0 then - pending('missing "fish" command') - return - end - command("set shell=fish") - command(":silent args `echo ***2`") - eq({ "file2", }, eval("argv()")) - command(":silent args `echo */*4`") - eq({ "subdir/file4", }, eval("argv()")) - end) -end) diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/eval/buf_functions_spec.lua deleted file mode 100644 index e957e5f5af..0000000000 --- a/test/functional/eval/buf_functions_spec.lua +++ /dev/null @@ -1,306 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local lfs = require('lfs') - -local eq = helpers.eq -local clear = helpers.clear -local funcs = helpers.funcs -local meths = helpers.meths -local command = helpers.command -local exc_exec = helpers.exc_exec -local bufmeths = helpers.bufmeths -local winmeths = helpers.winmeths -local curbufmeths = helpers.curbufmeths -local curwinmeths = helpers.curwinmeths -local curtabmeths = helpers.curtabmeths -local get_pathsep = helpers.get_pathsep -local rmdir = helpers.rmdir -local pcall_err = helpers.pcall_err - -local fname = 'Xtest-functional-eval-buf_functions' -local fname2 = fname .. '.2' -local dirname = fname .. '.d' - -before_each(clear) - -for _, func in ipairs({'bufname(%s)', 'bufnr(%s)', 'bufwinnr(%s)', - 'getbufline(%s, 1)', 'getbufvar(%s, "changedtick")', - 'setbufvar(%s, "f", 0)'}) do - local funcname = func:match('%w+') - describe(funcname .. '() function', function() - it('errors out when receives v:true/v:false/v:null', function() - -- Not compatible with Vim: in Vim it always results in buffer not found - -- without any error messages. - for _, var in ipairs({'v:true', 'v:false'}) do - eq('Vim(call):E5299: Expected a Number or a String, Boolean found', - exc_exec('call ' .. func:format(var))) - end - eq('Vim(call):E5300: Expected a Number or a String', - exc_exec('call ' .. func:format('v:null'))) - end) - it('errors out when receives invalid argument', function() - eq('Vim(call):E745: Expected a Number or a String, List found', - exc_exec('call ' .. func:format('[]'))) - eq('Vim(call):E728: Expected a Number or a String, Dictionary found', - exc_exec('call ' .. func:format('{}'))) - eq('Vim(call):E805: Expected a Number or a String, Float found', - exc_exec('call ' .. func:format('0.0'))) - eq('Vim(call):E703: Expected a Number or a String, Funcref found', - exc_exec('call ' .. func:format('function("tr")'))) - end) - end) -end - -describe('bufname() function', function() - it('returns empty string when buffer was not found', function() - command('file ' .. fname) - eq('', funcs.bufname(2)) - eq('', funcs.bufname('non-existent-buffer')) - eq('', funcs.bufname('#')) - command('edit ' .. fname2) - eq(2, funcs.bufnr('%')) - eq('', funcs.bufname('X')) - end) - before_each(function() - lfs.mkdir(dirname) - end) - after_each(function() - rmdir(dirname) - end) - it('returns expected buffer name', function() - eq('', funcs.bufname('%')) -- Buffer has no name yet - command('file ' .. fname) - local wd = lfs.currentdir() - local sep = get_pathsep() - local curdirname = funcs.fnamemodify(wd, ':t') - for _, arg in ipairs({'%', 1, 'X', wd}) do - eq(fname, funcs.bufname(arg)) - meths.set_current_dir('..') - eq(curdirname .. sep .. fname, funcs.bufname(arg)) - meths.set_current_dir(curdirname) - meths.set_current_dir(dirname) - eq(wd .. sep .. fname, funcs.bufname(arg)) - meths.set_current_dir('..') - eq(fname, funcs.bufname(arg)) - command('enew') - end - eq('', funcs.bufname('%')) - eq('', funcs.bufname('$')) - eq(2, funcs.bufnr('%')) - end) -end) - -describe('bufnr() function', function() - it('returns -1 when buffer was not found', function() - command('file ' .. fname) - eq(-1, funcs.bufnr(2)) - eq(-1, funcs.bufnr('non-existent-buffer')) - eq(-1, funcs.bufnr('#')) - command('edit ' .. fname2) - eq(2, funcs.bufnr('%')) - eq(-1, funcs.bufnr('X')) - end) - it('returns expected buffer number', function() - eq(1, funcs.bufnr('%')) - command('file ' .. fname) - local wd = lfs.currentdir() - local curdirname = funcs.fnamemodify(wd, ':t') - eq(1, funcs.bufnr(fname)) - eq(1, funcs.bufnr(wd)) - eq(1, funcs.bufnr(curdirname)) - eq(1, funcs.bufnr('X')) - end) - it('returns number of last buffer with "$"', function() - eq(1, funcs.bufnr('$')) - command('new') - eq(2, funcs.bufnr('$')) - command('new') - eq(3, funcs.bufnr('$')) - command('only') - eq(3, funcs.bufnr('$')) - eq(3, funcs.bufnr('%')) - command('buffer 1') - eq(3, funcs.bufnr('$')) - eq(1, funcs.bufnr('%')) - command('bwipeout 2') - eq(3, funcs.bufnr('$')) - eq(1, funcs.bufnr('%')) - command('bwipeout 3') - eq(1, funcs.bufnr('$')) - eq(1, funcs.bufnr('%')) - command('new') - eq(4, funcs.bufnr('$')) - end) -end) - -describe('bufwinnr() function', function() - it('returns -1 when buffer was not found', function() - command('file ' .. fname) - eq(-1, funcs.bufwinnr(2)) - eq(-1, funcs.bufwinnr('non-existent-buffer')) - eq(-1, funcs.bufwinnr('#')) - command('split ' .. fname2) -- It would be OK if there was one window - eq(2, funcs.bufnr('%')) - eq(-1, funcs.bufwinnr('X')) - end) - before_each(function() - lfs.mkdir(dirname) - end) - after_each(function() - rmdir(dirname) - end) - it('returns expected window number', function() - eq(1, funcs.bufwinnr('%')) - command('file ' .. fname) - command('vsplit') - command('split ' .. fname2) - eq(2, funcs.bufwinnr(fname)) - eq(1, funcs.bufwinnr(fname2)) - eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1))) - meths.set_current_dir(dirname) - eq(2, funcs.bufwinnr(fname)) - eq(1, funcs.bufwinnr(fname2)) - eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1))) - eq(1, funcs.bufwinnr('%')) - eq(2, funcs.bufwinnr(1)) - eq(1, funcs.bufwinnr(2)) - eq(-1, funcs.bufwinnr(3)) - eq(1, funcs.bufwinnr('$')) - end) -end) - -describe('getbufline() function', function() - it('returns empty list when buffer was not found', function() - command('file ' .. fname) - eq({}, funcs.getbufline(2, 1)) - eq({}, funcs.getbufline('non-existent-buffer', 1)) - eq({}, funcs.getbufline('#', 1)) - command('edit ' .. fname2) - eq(2, funcs.bufnr('%')) - eq({}, funcs.getbufline('X', 1)) - end) - it('returns empty list when range is invalid', function() - eq({}, funcs.getbufline(1, 0)) - curbufmeths.set_lines(0, 1, false, {'foo', 'bar', 'baz'}) - eq({}, funcs.getbufline(1, 2, 1)) - eq({}, funcs.getbufline(1, -10, -20)) - eq({}, funcs.getbufline(1, -2, -1)) - eq({}, funcs.getbufline(1, -1, 9999)) - end) - it('returns expected lines', function() - meths.set_option('hidden', true) - command('file ' .. fname) - curbufmeths.set_lines(0, 1, false, {'foo\0', '\0bar', 'baz'}) - command('edit ' .. fname2) - curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'}) - eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, 9999)) - eq({'abc\n', '\ndef', 'ghi'}, funcs.getbufline(2, 1, 9999)) - eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, '$')) - eq({'baz'}, funcs.getbufline(1, '$', '$')) - eq({'baz'}, funcs.getbufline(1, '$', 9999)) - end) -end) - -describe('getbufvar() function', function() - it('returns empty list when buffer was not found', function() - command('file ' .. fname) - eq('', funcs.getbufvar(2, '&autoindent')) - eq('', funcs.getbufvar('non-existent-buffer', '&autoindent')) - eq('', funcs.getbufvar('#', '&autoindent')) - command('edit ' .. fname2) - eq(2, funcs.bufnr('%')) - eq('', funcs.getbufvar('X', '&autoindent')) - end) - it('returns empty list when variable/option/etc was not found', function() - command('file ' .. fname) - eq('', funcs.getbufvar(1, '&autondent')) - eq('', funcs.getbufvar(1, 'changedtic')) - end) - it('returns expected option value', function() - eq(0, funcs.getbufvar(1, '&autoindent')) - eq(0, funcs.getbufvar(1, '&l:autoindent')) - eq(0, funcs.getbufvar(1, '&g:autoindent')) - -- Also works with global-only options - eq(1, funcs.getbufvar(1, '&hidden')) - eq(1, funcs.getbufvar(1, '&l:hidden')) - eq(1, funcs.getbufvar(1, '&g:hidden')) - -- Also works with window-local options - eq(0, funcs.getbufvar(1, '&number')) - eq(0, funcs.getbufvar(1, '&l:number')) - eq(0, funcs.getbufvar(1, '&g:number')) - command('new') - -- But with window-local options it probably does not what you expect - command("setl number") - -- (note that current window’s buffer is 2, but getbufvar() receives 1) - eq({id=2}, curwinmeths.get_buf()) - eq(1, funcs.getbufvar(1, '&number')) - eq(1, funcs.getbufvar(1, '&l:number')) - -- You can get global value though, if you find this useful. - eq(0, funcs.getbufvar(1, '&g:number')) - end) - it('returns expected variable value', function() - eq(2, funcs.getbufvar(1, 'changedtick')) - curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'}) - eq(3, funcs.getbufvar(1, 'changedtick')) - curbufmeths.set_var('test', true) - eq(true, funcs.getbufvar(1, 'test')) - eq({test=true, changedtick=3}, funcs.getbufvar(1, '')) - command('new') - eq(3, funcs.getbufvar(1, 'changedtick')) - eq(true, funcs.getbufvar(1, 'test')) - eq({test=true, changedtick=3}, funcs.getbufvar(1, '')) - end) -end) - -describe('setbufvar() function', function() - it('throws the error or ignores the input when buffer was not found', function() - command('file ' .. fname) - eq(0, - exc_exec('call setbufvar(2, "&autoindent", 0)')) - eq('Vim(call):E94: No matching buffer for non-existent-buffer', - exc_exec('call setbufvar("non-existent-buffer", "&autoindent", 0)')) - eq(0, - exc_exec('call setbufvar("#", "&autoindent", 0)')) - command('edit ' .. fname2) - eq(2, funcs.bufnr('%')) - eq('Vim(call):E93: More than one match for X', - exc_exec('call setbufvar("X", "&autoindent", 0)')) - end) - it('may set options, including window-local and global values', function() - local buf1 = meths.get_current_buf() - eq(false, curwinmeths.get_option('number')) - command('split') - command('new') - eq(2, bufmeths.get_number(curwinmeths.get_buf())) - funcs.setbufvar(1, '&number', true) - local windows = curtabmeths.list_wins() - eq(false, winmeths.get_option(windows[1], 'number')) - eq(true, winmeths.get_option(windows[2], 'number')) - eq(false, winmeths.get_option(windows[3], 'number')) - eq(false, winmeths.get_option(meths.get_current_win(), 'number')) - - eq(true, meths.get_option('hidden')) - funcs.setbufvar(1, '&hidden', 0) - eq(false, meths.get_option('hidden')) - - eq(false, bufmeths.get_option(buf1, 'autoindent')) - funcs.setbufvar(1, '&autoindent', true) - eq(true, bufmeths.get_option(buf1, 'autoindent')) - eq('Vim(call):E355: Unknown option: xxx', - exc_exec('call setbufvar(1, "&xxx", 0)')) - end) - it('may set variables', function() - local buf1 = meths.get_current_buf() - command('split') - command('new') - eq(2, curbufmeths.get_number()) - funcs.setbufvar(1, 'number', true) - eq(true, bufmeths.get_var(buf1, 'number')) - eq('Vim(call):E461: Illegal variable name: b:', - exc_exec('call setbufvar(1, "", 0)')) - eq(true, bufmeths.get_var(buf1, 'number')) - eq('Vim:E46: Cannot change read-only variable "b:changedtick"', - pcall_err(funcs.setbufvar, 1, 'changedtick', true)) - eq(2, funcs.getbufvar(1, 'changedtick')) - end) -end) diff --git a/test/functional/eval/changedtick_spec.lua b/test/functional/eval/changedtick_spec.lua deleted file mode 100644 index 99406d9d7a..0000000000 --- a/test/functional/eval/changedtick_spec.lua +++ /dev/null @@ -1,142 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local eval = helpers.eval -local feed = helpers.feed -local clear = helpers.clear -local funcs = helpers.funcs -local meths = helpers.meths -local command = helpers.command -local exc_exec = helpers.exc_exec -local redir_exec = helpers.redir_exec -local pcall_err = helpers.pcall_err -local curbufmeths = helpers.curbufmeths - -before_each(clear) - -local function changedtick() - local ct = curbufmeths.get_changedtick() - eq(ct, curbufmeths.get_var('changedtick')) - eq(ct, curbufmeths.get_var('changedtick')) - eq(ct, eval('b:changedtick')) - eq(ct, eval('b:["changedtick"]')) - eq(ct, eval('b:.changedtick')) - eq(ct, funcs.getbufvar('%', 'changedtick')) - eq(ct, funcs.getbufvar('%', '').changedtick) - eq(ct, eval('b:').changedtick) - return ct -end - -describe('b:changedtick', function() - -- Ported tests from Vim-8.0.333 - it('increments', function() -- Test_changedtick_increments - -- New buffer has an empty line, tick starts at 2 - eq(2, changedtick()) - funcs.setline(1, 'hello') - eq(3, changedtick()) - eq(0, exc_exec('undo')) - -- Somehow undo counts as two changes - eq(5, changedtick()) - end) - it('is present in b: dictionary', function() - eq(2, changedtick()) - command('let d = b:') - eq(2, meths.get_var('d').changedtick) - end) - it('increments at bdel', function() - command('new') - eq(2, changedtick()) - local bnr = curbufmeths.get_number() - eq(2, bnr) - command('bdel') - eq(3, funcs.getbufvar(bnr, 'changedtick')) - eq(1, curbufmeths.get_number()) - end) - it('fails to be changed by user', function() - local ct = changedtick() - local ctn = ct + 100500 - eq(0, exc_exec('let d = b:')) - eq('\nE46: Cannot change read-only variable "b:changedtick"', - redir_exec('let b:changedtick = ' .. ctn)) - eq('\nE46: Cannot change read-only variable "b:["changedtick"]"', - redir_exec('let b:["changedtick"] = ' .. ctn)) - eq('\nE46: Cannot change read-only variable "b:.changedtick"', - redir_exec('let b:.changedtick = ' .. ctn)) - eq('\nE46: Cannot change read-only variable "d.changedtick"', - redir_exec('let d.changedtick = ' .. ctn)) - eq('Key is read-only: changedtick', - pcall_err(curbufmeths.set_var, 'changedtick', ctn)) - - eq('\nE795: Cannot delete variable b:changedtick', - redir_exec('unlet b:changedtick')) - eq('\nE46: Cannot change read-only variable "b:.changedtick"', - redir_exec('unlet b:.changedtick')) - eq('\nE46: Cannot change read-only variable "b:["changedtick"]"', - redir_exec('unlet b:["changedtick"]')) - eq('\nE46: Cannot change read-only variable "d.changedtick"', - redir_exec('unlet d.changedtick')) - eq('Key is read-only: changedtick', - pcall_err(curbufmeths.del_var, 'changedtick')) - eq(ct, changedtick()) - - eq('\nE46: Cannot change read-only variable "b:["changedtick"]"', - redir_exec('let b:["changedtick"] += ' .. ctn)) - eq('\nE46: Cannot change read-only variable "b:["changedtick"]"', - redir_exec('let b:["changedtick"] -= ' .. ctn)) - eq('\nE46: Cannot change read-only variable "b:["changedtick"]"', - redir_exec('let b:["changedtick"] .= ' .. ctn)) - - eq(ct, changedtick()) - - funcs.setline(1, 'hello') - - eq(ct + 1, changedtick()) - end) - it('is listed in :let output', function() - eq('\nb:changedtick #2', - redir_exec(':let b:')) - end) - it('fails to unlock b:changedtick', function() - eq(0, exc_exec('let d = b:')) - eq(0, funcs.islocked('b:changedtick')) - eq(0, funcs.islocked('d.changedtick')) - eq('\nE940: Cannot lock or unlock variable b:changedtick', - redir_exec('unlockvar b:changedtick')) - eq('\nE46: Cannot change read-only variable "d.changedtick"', - redir_exec('unlockvar d.changedtick')) - eq(0, funcs.islocked('b:changedtick')) - eq(0, funcs.islocked('d.changedtick')) - eq('\nE940: Cannot lock or unlock variable b:changedtick', - redir_exec('lockvar b:changedtick')) - eq('\nE46: Cannot change read-only variable "d.changedtick"', - redir_exec('lockvar d.changedtick')) - eq(0, funcs.islocked('b:changedtick')) - eq(0, funcs.islocked('d.changedtick')) - end) - it('is being completed', function() - feed(':echo b:<Tab><Home>let cmdline="<End>"<CR>') - eq('echo b:changedtick', meths.get_var('cmdline')) - end) - it('cannot be changed by filter() or map()', function() - eq(2, changedtick()) - eq('\nE795: Cannot delete variable filter() argument', - redir_exec('call filter(b:, 0)')) - eq('\nE742: Cannot change value of map() argument', - redir_exec('call map(b:, 0)')) - eq('\nE742: Cannot change value of map() argument', - redir_exec('call map(b:, "v:val")')) - eq(2, changedtick()) - end) - it('cannot be remove()d', function() - eq(2, changedtick()) - eq('\nE795: Cannot delete variable remove() argument', - redir_exec('call remove(b:, "changedtick")')) - eq(2, changedtick()) - end) - it('does not inherit VAR_FIXED when copying dictionary over', function() - eq(2, changedtick()) - eq('', redir_exec('let d1 = copy(b:)|let d1.changedtick = 42')) - eq('', redir_exec('let d2 = copy(b:)|unlet d2.changedtick')) - eq(2, changedtick()) - end) -end) diff --git a/test/functional/eval/container_functions_spec.lua b/test/functional/eval/container_functions_spec.lua deleted file mode 100644 index 04a3248c49..0000000000 --- a/test/functional/eval/container_functions_spec.lua +++ /dev/null @@ -1,24 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local eval = helpers.eval -local meths = helpers.meths -local clear = helpers.clear - -before_each(clear) - -describe('extend()', function() - it('suceeds to extend list with itself', function() - meths.set_var('l', {1, {}}) - eq({1, {}, 1, {}}, eval('extend(l, l)')) - eq({1, {}, 1, {}}, meths.get_var('l')) - - meths.set_var('l', {1, {}}) - eq({1, {}, 1, {}}, eval('extend(l, l, 0)')) - eq({1, {}, 1, {}}, meths.get_var('l')) - - meths.set_var('l', {1, {}}) - eq({1, 1, {}, {}}, eval('extend(l, l, 1)')) - eq({1, 1, {}, {}}, meths.get_var('l')) - end) -end) diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/eval/ctx_functions_spec.lua deleted file mode 100644 index f23adbc556..0000000000 --- a/test/functional/eval/ctx_functions_spec.lua +++ /dev/null @@ -1,406 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local call = helpers.call -local clear = helpers.clear -local command = helpers.command -local eq = helpers.eq -local eval = helpers.eval -local feed = helpers.feed -local map = helpers.tbl_map -local nvim = helpers.nvim -local parse_context = helpers.parse_context -local redir_exec = helpers.redir_exec -local source = helpers.source -local trim = helpers.trim -local write_file = helpers.write_file -local pcall_err = helpers.pcall_err - -describe('context functions', function() - local fname1 = 'Xtest-functional-eval-ctx1' - local fname2 = 'Xtest-functional-eval-ctx2' - local outofbounds = - 'Vim:E475: Invalid value for argument index: out of bounds' - - before_each(function() - clear() - write_file(fname1, "1\n2\n3") - write_file(fname2, "a\nb\nc") - end) - - after_each(function() - os.remove(fname1) - os.remove(fname2) - end) - - describe('ctxpush/ctxpop', function() - it('saves and restores registers properly', function() - local regs = {'1', '2', '3', 'a'} - local vals = {'1', '2', '3', 'hjkl'} - feed('i1<cr>2<cr>3<c-[>ddddddqahjklq') - eq(vals, map(function(r) return trim(call('getreg', r)) end, regs)) - call('ctxpush') - call('ctxpush', {'regs'}) - - map(function(r) call('setreg', r, {}) end, regs) - eq({'', '', '', ''}, - map(function(r) return trim(call('getreg', r)) end, regs)) - - call('ctxpop') - eq(vals, map(function(r) return trim(call('getreg', r)) end, regs)) - - map(function(r) call('setreg', r, {}) end, regs) - eq({'', '', '', ''}, - map(function(r) return trim(call('getreg', r)) end, regs)) - - call('ctxpop') - eq(vals, map(function(r) return trim(call('getreg', r)) end, regs)) - end) - - it('saves and restores jumplist properly', function() - command('edit '..fname1) - feed('G') - feed('gg') - command('edit '..fname2) - local jumplist = call('getjumplist') - call('ctxpush') - call('ctxpush', {'jumps'}) - - command('clearjumps') - eq({{}, 0}, call('getjumplist')) - - call('ctxpop') - eq(jumplist, call('getjumplist')) - - command('clearjumps') - eq({{}, 0}, call('getjumplist')) - - call('ctxpop') - eq(jumplist, call('getjumplist')) - end) - - it('saves and restores buffer list properly', function() - command('edit '..fname1) - command('edit '..fname2) - command('edit TEST') - local bufs = call('map', call('getbufinfo'), 'v:val.name') - call('ctxpush') - call('ctxpush', {'bufs'}) - - command('%bwipeout') - eq({''}, call('map', call('getbufinfo'), 'v:val.name')) - - call('ctxpop') - eq({'', unpack(bufs)}, call('map', call('getbufinfo'), 'v:val.name')) - - command('%bwipeout') - eq({''}, call('map', call('getbufinfo'), 'v:val.name')) - - call('ctxpop') - eq({'', unpack(bufs)}, call('map', call('getbufinfo'), 'v:val.name')) - end) - - it('saves and restores global variables properly', function() - nvim('set_var', 'one', 1) - nvim('set_var', 'Two', 2) - nvim('set_var', 'THREE', 3) - eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) - call('ctxpush') - call('ctxpush', {'gvars'}) - - nvim('del_var', 'one') - nvim('del_var', 'Two') - nvim('del_var', 'THREE') - eq('Vim:E121: Undefined variable: g:one', pcall_err(eval, 'g:one')) - eq('Vim:E121: Undefined variable: g:Two', pcall_err(eval, 'g:Two')) - eq('Vim:E121: Undefined variable: g:THREE', pcall_err(eval, 'g:THREE')) - - call('ctxpop') - eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) - - nvim('del_var', 'one') - nvim('del_var', 'Two') - nvim('del_var', 'THREE') - eq('Vim:E121: Undefined variable: g:one', pcall_err(eval, 'g:one')) - eq('Vim:E121: Undefined variable: g:Two', pcall_err(eval, 'g:Two')) - eq('Vim:E121: Undefined variable: g:THREE', pcall_err(eval, 'g:THREE')) - - call('ctxpop') - eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) - end) - - it('saves and restores script functions properly', function() - source([[ - function s:greet(name) - echom 'Hello, '.a:name.'!' - endfunction - - function s:greet_all(name, ...) - echom 'Hello, '.a:name.'!' - for more in a:000 - echom 'Hello, '.more.'!' - endfor - endfunction - - function Greet(name) - call call('s:greet', [a:name]) - endfunction - - function GreetAll(name, ...) - call call('s:greet_all', extend([a:name], a:000)) - endfunction - - function SaveSFuncs() - call ctxpush(['sfuncs']) - endfunction - - function DeleteSFuncs() - delfunction s:greet - delfunction s:greet_all - endfunction - - function RestoreFuncs() - call ctxpop() - endfunction - ]]) - - eq('\nHello, World!', redir_exec([[call Greet('World')]])) - eq('\nHello, World!'.. - '\nHello, One!'.. - '\nHello, Two!'.. - '\nHello, Three!', - redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]])) - - call('SaveSFuncs') - call('DeleteSFuncs') - - eq('\nError detected while processing function Greet:'.. - '\nline 1:'.. - '\nE117: Unknown function: s:greet', - redir_exec([[call Greet('World')]])) - eq('\nError detected while processing function GreetAll:'.. - '\nline 1:'.. - '\nE117: Unknown function: s:greet_all', - redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]])) - - call('RestoreFuncs') - - eq('\nHello, World!', redir_exec([[call Greet('World')]])) - eq('\nHello, World!'.. - '\nHello, One!'.. - '\nHello, Two!'.. - '\nHello, Three!', - redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]])) - end) - - it('saves and restores functions properly', function() - source([[ - function Greet(name) - echom 'Hello, '.a:name.'!' - endfunction - - function GreetAll(name, ...) - echom 'Hello, '.a:name.'!' - for more in a:000 - echom 'Hello, '.more.'!' - endfor - endfunction - ]]) - - eq('\nHello, World!', redir_exec([[call Greet('World')]])) - eq('\nHello, World!'.. - '\nHello, One!'.. - '\nHello, Two!'.. - '\nHello, Three!', - redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]])) - - call('ctxpush', {'funcs'}) - command('delfunction Greet') - command('delfunction GreetAll') - - eq('Vim:E117: Unknown function: Greet', pcall_err(call, 'Greet', 'World')) - eq('Vim:E117: Unknown function: GreetAll', - pcall_err(call, 'GreetAll', 'World', 'One', 'Two', 'Three')) - - call('ctxpop') - - eq('\nHello, World!', redir_exec([[call Greet('World')]])) - eq('\nHello, World!'.. - '\nHello, One!'.. - '\nHello, Two!'.. - '\nHello, Three!', - redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]])) - end) - - it('errors out when context stack is empty', function() - local err = 'Vim:Context stack is empty' - eq(err, pcall_err(call, 'ctxpop')) - eq(err, pcall_err(call, 'ctxpop')) - call('ctxpush') - call('ctxpush') - call('ctxpop') - call('ctxpop') - eq(err, pcall_err(call, 'ctxpop')) - end) - end) - - describe('ctxsize()', function() - it('returns context stack size', function() - eq(0, call('ctxsize')) - call('ctxpush') - eq(1, call('ctxsize')) - call('ctxpush') - eq(2, call('ctxsize')) - call('ctxpush') - eq(3, call('ctxsize')) - call('ctxpop') - eq(2, call('ctxsize')) - call('ctxpop') - eq(1, call('ctxsize')) - call('ctxpop') - eq(0, call('ctxsize')) - end) - end) - - describe('ctxget()', function() - it('errors out when index is out of bounds', function() - eq(outofbounds, pcall_err(call, 'ctxget')) - call('ctxpush') - eq(outofbounds, pcall_err(call, 'ctxget', 1)) - call('ctxpop') - eq(outofbounds, pcall_err(call, 'ctxget', 0)) - end) - - it('returns context dictionary at index in context stack', function() - feed('i1<cr>2<cr>3<c-[>ddddddqahjklq') - command('edit! '..fname1) - feed('G') - feed('gg') - command('edit '..fname2) - nvim('set_var', 'one', 1) - nvim('set_var', 'Two', 2) - nvim('set_var', 'THREE', 3) - - local with_regs = { - ['regs'] = { - {['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true}, - {['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50}, - {['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51}, - {['rc'] = {'hjkl'}, ['n'] = 97}, - } - } - - local with_jumps = { - ['jumps'] = eval(([[ - filter(map(getjumplist()[0], 'filter( - { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum }, - { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)') - ]]):gsub('\n', '')) - } - - local with_bufs = { - ['bufs'] = eval([[ - filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)') - ]]) - } - - local with_gvars = { - ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}} - } - - local with_all = { - ['regs'] = with_regs['regs'], - ['jumps'] = with_jumps['jumps'], - ['bufs'] = with_bufs['bufs'], - ['gvars'] = with_gvars['gvars'], - } - - call('ctxpush') - eq(with_all, parse_context(call('ctxget'))) - eq(with_all, parse_context(call('ctxget', 0))) - - call('ctxpush', {'gvars'}) - eq(with_gvars, parse_context(call('ctxget'))) - eq(with_gvars, parse_context(call('ctxget', 0))) - eq(with_all, parse_context(call('ctxget', 1))) - - call('ctxpush', {'bufs'}) - eq(with_bufs, parse_context(call('ctxget'))) - eq(with_bufs, parse_context(call('ctxget', 0))) - eq(with_gvars, parse_context(call('ctxget', 1))) - eq(with_all, parse_context(call('ctxget', 2))) - - call('ctxpush', {'jumps'}) - eq(with_jumps, parse_context(call('ctxget'))) - eq(with_jumps, parse_context(call('ctxget', 0))) - eq(with_bufs, parse_context(call('ctxget', 1))) - eq(with_gvars, parse_context(call('ctxget', 2))) - eq(with_all, parse_context(call('ctxget', 3))) - - call('ctxpush', {'regs'}) - eq(with_regs, parse_context(call('ctxget'))) - eq(with_regs, parse_context(call('ctxget', 0))) - eq(with_jumps, parse_context(call('ctxget', 1))) - eq(with_bufs, parse_context(call('ctxget', 2))) - eq(with_gvars, parse_context(call('ctxget', 3))) - eq(with_all, parse_context(call('ctxget', 4))) - - call('ctxpop') - eq(with_jumps, parse_context(call('ctxget'))) - eq(with_jumps, parse_context(call('ctxget', 0))) - eq(with_bufs, parse_context(call('ctxget', 1))) - eq(with_gvars, parse_context(call('ctxget', 2))) - eq(with_all, parse_context(call('ctxget', 3))) - - call('ctxpop') - eq(with_bufs, parse_context(call('ctxget'))) - eq(with_bufs, parse_context(call('ctxget', 0))) - eq(with_gvars, parse_context(call('ctxget', 1))) - eq(with_all, parse_context(call('ctxget', 2))) - - call('ctxpop') - eq(with_gvars, parse_context(call('ctxget'))) - eq(with_gvars, parse_context(call('ctxget', 0))) - eq(with_all, parse_context(call('ctxget', 1))) - - call('ctxpop') - eq(with_all, parse_context(call('ctxget'))) - eq(with_all, parse_context(call('ctxget', 0))) - end) - end) - - describe('ctxset()', function() - it('errors out when index is out of bounds', function() - eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1})) - call('ctxpush') - eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1}, 1)) - call('ctxpop') - eq(outofbounds, pcall_err(call, 'ctxset', {dummy = 1}, 0)) - end) - - it('sets context dictionary at index in context stack', function() - nvim('set_var', 'one', 1) - nvim('set_var', 'Two', 2) - nvim('set_var', 'THREE', 3) - call('ctxpush') - local ctx1 = call('ctxget') - nvim('set_var', 'one', 'a') - nvim('set_var', 'Two', 'b') - nvim('set_var', 'THREE', 'c') - call('ctxpush') - call('ctxpush') - local ctx2 = call('ctxget') - - eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) - call('ctxset', ctx1) - call('ctxset', ctx2, 2) - call('ctxpop') - eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) - call('ctxpop') - eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) - nvim('set_var', 'one', 1.5) - eq({1.5, 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) - call('ctxpop') - eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) - end) - end) -end) diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua deleted file mode 100644 index 9e19568249..0000000000 --- a/test/functional/eval/environ_spec.lua +++ /dev/null @@ -1,80 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq = helpers.eq -local environ = helpers.funcs.environ -local exists = helpers.funcs.exists -local system = helpers.funcs.system -local nvim_prog = helpers.nvim_prog -local command = helpers.command -local eval = helpers.eval -local setenv = helpers.funcs.setenv - -describe('environment variables', function() - it('environ() handles empty env variable', function() - clear({env={EMPTY_VAR=""}}) - eq("", environ()['EMPTY_VAR']) - eq(nil, environ()['DOES_NOT_EXIST']) - end) - - it('exists() handles empty env variable', function() - clear({env={EMPTY_VAR=""}}) - eq(1, exists('$EMPTY_VAR')) - eq(0, exists('$DOES_NOT_EXIST')) - end) -end) - -describe('empty $HOME', function() - local original_home = os.getenv('HOME') - - -- recover $HOME after each test - after_each(function() - if original_home ~= nil then - setenv('HOME', original_home) - end - os.remove('test_empty_home') - os.remove('./~') - end) - - local function tilde_in_cwd() - -- get files in cwd - command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')") - -- get the index of the file named '~' - command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")') - return eval('test_empty_home_tilde_index') ~= -1 - end - - local function write_and_test_tilde() - system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', - '-c', 'write test_empty_home', '+q'}) - eq(false, tilde_in_cwd()) - end - - it("'~' folder not created in cwd if $HOME and related env not defined", function() - command("unlet $HOME") - write_and_test_tilde() - - command("let $HOMEDRIVE='C:'") - command("let $USERPROFILE='C:\\'") - write_and_test_tilde() - - command("unlet $HOMEDRIVE") - write_and_test_tilde() - - command("unlet $USERPROFILE") - write_and_test_tilde() - - command("let $HOME='%USERPROFILE%'") - command("let $USERPROFILE='C:\\'") - write_and_test_tilde() - end) - - it("'~' folder not created in cwd if writing a file with invalid $HOME", function() - setenv('HOME', '/path/does/not/exist') - write_and_test_tilde() - end) - - it("'~' folder not created in cwd if writing a file with $HOME=''", function() - command("let $HOME=''") - write_and_test_tilde() - end) -end) diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua deleted file mode 100644 index 28aefb72e5..0000000000 --- a/test/functional/eval/executable_spec.lua +++ /dev/null @@ -1,218 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq, clear, call, iswin, write_file, command = - helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file, - helpers.command -local exc_exec = helpers.exc_exec -local eval = helpers.eval - -describe('executable()', function() - before_each(clear) - - it('returns 1 for commands in $PATH', function() - local exe = iswin() and 'ping' or 'ls' - eq(1, call('executable', exe)) - command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - eq(1, call('executable', 'null')) - eq(1, call('executable', 'true')) - eq(1, call('executable', 'false')) - end) - - it('fails for invalid values', function() - for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) - end - command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) - end - end) - - it('returns 0 for non-existent files', function() - eq(0, call('executable', 'no_such_file_exists_209ufq23f')) - end) - - it('sibling to nvim binary', function() - -- Some executable in build/bin/, *not* in $PATH nor CWD. - local sibling_exe = 'printargs-test' - -- Windows: siblings are in Nvim's "pseudo-$PATH". - local expected = iswin() and 1 or 0 - if iswin() then - eq('arg1=lemon;arg2=sky;arg3=tree;', - call('system', sibling_exe..' lemon sky tree')) - end - eq(expected, call('executable', sibling_exe)) - end) - - describe('exec-bit', function() - setup(function() - clear() - write_file('Xtest_not_executable', 'non-executable file') - write_file('Xtest_executable', 'executable file (exec-bit set)') - if not iswin() then -- N/A for Windows. - call('system', {'chmod', '-x', 'Xtest_not_executable'}) - call('system', {'chmod', '+x', 'Xtest_executable'}) - end - end) - - teardown(function() - os.remove('Xtest_not_executable') - os.remove('Xtest_executable') - end) - - it('not set', function() - eq(0, call('executable', 'Xtest_not_executable')) - eq(0, call('executable', './Xtest_not_executable')) - end) - - it('set, unqualified and not in $PATH', function() - eq(0, call('executable', 'Xtest_executable')) - end) - - it('set, qualified as a path', function() - local expected = iswin() and 0 or 1 - eq(expected, call('executable', './Xtest_executable')) - end) - end) -end) - -describe('executable() (Windows)', function() - if not iswin() then return end -- N/A for Unix. - - local exts = {'bat', 'exe', 'com', 'cmd'} - setup(function() - for _, ext in ipairs(exts) do - write_file('test_executable_'..ext..'.'..ext, '') - end - write_file('test_executable_zzz.zzz', '') - end) - - teardown(function() - for _, ext in ipairs(exts) do - os.remove('test_executable_'..ext..'.'..ext) - end - os.remove('test_executable_zzz.zzz') - end) - - it('tries default extensions on a filename if $PATHEXT is empty', function() - -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd". - clear({env={PATHEXT=''}}) - for _,ext in ipairs(exts) do - eq(1, call('executable', 'test_executable_'..ext)) - end - eq(0, call('executable', 'test_executable_zzz')) - end) - - it('tries default extensions on a filepath if $PATHEXT is empty', function() - -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd". - clear({env={PATHEXT=''}}) - for _,ext in ipairs(exts) do - eq(1, call('executable', '.\\test_executable_'..ext)) - end - eq(0, call('executable', '.\\test_executable_zzz')) - end) - - it('system([…]), jobstart([…]) use $PATHEXT #9569', function() - -- Invoking `cmdscript` should find/execute `cmdscript.cmd`. - eq('much success\n', call('system', {'test/functional/fixtures/cmdscript'})) - assert(0 < call('jobstart', {'test/functional/fixtures/cmdscript'})) - end) - - it('full path with extension', function() - -- Some executable we can expect in the test env. - local exe = 'printargs-test' - local exedir = eval("fnamemodify(v:progpath, ':h')") - local exepath = exedir..'/'..exe..'.exe' - eq(1, call('executable', exepath)) - eq('arg1=lemon;arg2=sky;arg3=tree;', - call('system', exepath..' lemon sky tree')) - end) - - it('full path without extension', function() - -- Some executable we can expect in the test env. - local exe = 'printargs-test' - local exedir = eval("fnamemodify(v:progpath, ':h')") - local exepath = exedir..'/'..exe - eq('arg1=lemon;arg2=sky;arg3=tree;', - call('system', exepath..' lemon sky tree')) - eq(1, call('executable', exepath)) - end) - - it('respects $PATHEXT when trying extensions on a filename', function() - clear({env={PATHEXT='.zzz'}}) - for _,ext in ipairs(exts) do - eq(0, call('executable', 'test_executable_'..ext)) - end - eq(1, call('executable', 'test_executable_zzz')) - end) - - it('respects $PATHEXT when trying extensions on a filepath', function() - clear({env={PATHEXT='.zzz'}}) - for _,ext in ipairs(exts) do - eq(0, call('executable', '.\\test_executable_'..ext)) - end - eq(1, call('executable', '.\\test_executable_zzz')) - end) - - it("with weird $PATHEXT", function() - clear({env={PATHEXT=';'}}) - eq(0, call('executable', '.\\test_executable_zzz')) - clear({env={PATHEXT=';;;.zzz;;'}}) - eq(1, call('executable', '.\\test_executable_zzz')) - end) - - it("unqualified filename, Unix-style 'shell'", function() - clear({env={PATHEXT=''}}) - command('set shell=sh') - for _,ext in ipairs(exts) do - eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) - end - eq(1, call('executable', 'test_executable_zzz.zzz')) - end) - - it("relative path, Unix-style 'shell' (backslashes)", function() - clear({env={PATHEXT=''}}) - command('set shell=bash.exe') - for _,ext in ipairs(exts) do - eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext)) - eq(1, call('executable', './test_executable_'..ext..'.'..ext)) - end - eq(1, call('executable', '.\\test_executable_zzz.zzz')) - eq(1, call('executable', './test_executable_zzz.zzz')) - end) - - it('unqualified filename, $PATHEXT contains dot', function() - clear({env={PATHEXT='.;.zzz'}}) - for _,ext in ipairs(exts) do - eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) - end - eq(1, call('executable', 'test_executable_zzz.zzz')) - clear({env={PATHEXT='.zzz;.'}}) - for _,ext in ipairs(exts) do - eq(1, call('executable', 'test_executable_'..ext..'.'..ext)) - end - eq(1, call('executable', 'test_executable_zzz.zzz')) - end) - - it('relative path, $PATHEXT contains dot (backslashes)', function() - clear({env={PATHEXT='.;.zzz'}}) - for _,ext in ipairs(exts) do - eq(1, call('executable', '.\\test_executable_'..ext..'.'..ext)) - eq(1, call('executable', './test_executable_'..ext..'.'..ext)) - end - eq(1, call('executable', '.\\test_executable_zzz.zzz')) - eq(1, call('executable', './test_executable_zzz.zzz')) - end) - - it('ignores case of extension', function() - clear({env={PATHEXT='.ZZZ'}}) - eq(1, call('executable', 'test_executable_zzz.zzz')) - end) - - it('relative path does not search $PATH', function() - clear({env={PATHEXT=''}}) - eq(0, call('executable', './System32/notepad.exe')) - eq(0, call('executable', '.\\System32\\notepad.exe')) - eq(0, call('executable', '../notepad.exe')) - eq(0, call('executable', '..\\notepad.exe')) - end) -end) diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua deleted file mode 100644 index fccf52935b..0000000000 --- a/test/functional/eval/execute_spec.lua +++ /dev/null @@ -1,337 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local eval = helpers.eval -local clear = helpers.clear -local source = helpers.source -local redir_exec = helpers.redir_exec -local exc_exec = helpers.exc_exec -local funcs = helpers.funcs -local Screen = require('test.functional.ui.screen') -local command = helpers.command -local feed = helpers.feed -local iswin = helpers.iswin - -describe('execute()', function() - before_each(clear) - - it('captures the same result as :redir', function() - eq(redir_exec('messages'), funcs.execute('messages')) - end) - - it('captures the concatenated outputs of a List of commands', function() - eq("foobar", funcs.execute({'echon "foo"', 'echon "bar"'})) - eq("\nfoo\nbar", funcs.execute({'echo "foo"', 'echo "bar"'})) - end) - - it('supports nested execute("execute(...)")', function() - eq('42', funcs.execute([[echon execute("echon execute('echon 42')")]])) - end) - - it('supports nested :redir to a variable', function() - source([[ - function! g:Foo() - let a = '' - redir => a - silent echon "foo" - redir END - return a - endfunction - function! g:Bar() - let a = '' - redir => a - silent echon "bar1" - call g:Foo() - silent echon "bar2" - redir END - silent echon "bar3" - return a - endfunction - ]]) - eq('top1bar1foobar2bar3', funcs.execute('echon "top1"|call g:Bar()')) - end) - - it('supports nested :redir to a register', function() - source([[ - let @a = '' - function! g:Foo() - redir @a>> - silent echon "foo" - redir END - return @a - endfunction - function! g:Bar() - redir @a>> - silent echon "bar1" - call g:Foo() - silent echon "bar2" - redir END - silent echon "bar3" - return @a - endfunction - ]]) - eq('top1bar1foobar2bar3', funcs.execute('echon "top1"|call g:Bar()')) - -- :redir itself doesn't nest, so the redirection ends in g:Foo - eq('bar1foo', eval('@a')) - end) - - it('captures a transformed string', function() - eq('^A', funcs.execute('echon "\\<C-a>"')) - end) - - it('returns empty string if the argument list is empty', function() - eq('', funcs.execute({})) - eq(0, exc_exec('let g:ret = execute(v:_null_list)')) - eq('', eval('g:ret')) - end) - - it('captures errors', function() - local ret - ret = exc_exec('call execute(0.0)') - eq('Vim(call):E806: using Float as a String', ret) - ret = exc_exec('call execute(v:_null_dict)') - eq('Vim(call):E731: using Dictionary as a String', ret) - ret = exc_exec('call execute(function("tr"))') - eq('Vim(call):E729: using Funcref as a String', ret) - ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])') - eq('Vim:E806: using Float as a String', ret) - ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])') - eq('Vim:E731: using Dictionary as a String', ret) - ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])') - eq('Vim:E729: using Funcref as a String', ret) - end) - - it('captures output with highlights', function() - eq('\nErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red', - eval('execute("hi ErrorMsg")')) - end) - - it('does not corrupt the command display #5422', function() - local screen = Screen.new(70, 7) - screen:attach() - feed(':echo execute("hi ErrorMsg")<CR>') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {2: }| - | - ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red | - {3:Press ENTER or type command to continue}^ | - ]], { - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, - }) - feed('<CR>') - end) - - it('places cursor correctly #6035', function() - local screen = Screen.new(40, 6) - screen:attach() - source([=[ - " test 1: non-silenced output goes as usual - function! Test1() - echo 1234 - let x = execute('echon "abcdef"', '') - echon 'ABCD' - endfunction - - " test 2: silenced output does not affect ui - function! Test2() - echo 1234 - let x = execute('echon "abcdef"', 'silent') - echon 'ABCD' - endfunction - - " test 3: silenced! error does not affect ui - function! Test3() - echo 1234 - let x = execute('echoerr "abcdef"', 'silent!') - echon 'ABCD' - endfunction - - " test 4: silenced echoerr goes as usual - " bug here - function! Test4() - echo 1234 - let x = execute('echoerr "abcdef"', 'silent') - echon 'ABCD' - endfunction - - " test 5: silenced! echoerr does not affect ui - function! Test5() - echo 1234 - let x = execute('echoerr "abcdef"', 'silent!') - echon 'ABCD' - endfunction - - " test 6: silenced error goes as usual - function! Test6() - echo 1234 - let x = execute('echo undefined', 'silent') - echon 'ABCD' - endfunction - - " test 7: existing error does not mess the result - function! Test7() - " display from Test6() is still visible - " why does the "abcdef" goes into a newline - let x = execute('echon "abcdef"', '') - echon 'ABCD' - endfunction - ]=]) - - feed([[:call Test1()<cr>]]) - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ABCD | - ]]) - - feed([[:call Test2()<cr>]]) - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - 1234ABCD | - ]]) - - feed([[:call Test3()<cr>]]) - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - 1234ABCD | - ]]) - - feed([[:call Test4()<cr>]]) - -- unexpected: need to fix - -- echoerr does not set did_emsg - -- "ef" was overwritten since msg_col was recovered wrongly - screen:expect([[ - 1234 | - Error detected while processing function| - Test4: | - line 2: | - abcdABCD | - Press ENTER or type command to continue^ | - ]]) - - feed([[<cr>]]) -- to clear screen - feed([[:call Test5()<cr>]]) - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - 1234ABCD | - ]]) - - feed([[:call Test6()<cr>]]) - screen:expect([[ - | - Error detected while processing function| - Test6: | - line 2: | - E121ABCD | - Press ENTER or type command to continue^ | - ]]) - - feed([[:call Test7()<cr>]]) - screen:expect([[ - Error detected while processing function| - Test6: | - line 2: | - E121ABCD | - ABCD | - Press ENTER or type command to continue^ | - ]]) - end) - - -- This deviates from vim behavior, but is consistent - -- with how nvim currently displays the output. - it('captures shell-command output', function() - local win_lf = iswin() and '\13' or '' - eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo')) - end) - - describe('{silent} argument', function() - it('captures & displays output for ""', function() - local screen = Screen.new(40, 5) - screen:attach() - command('let g:mes = execute("echon 42", "")') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - 42 | - ]]) - eq('42', eval('g:mes')) - end) - - it('captures but does not display output for "silent"', function() - local screen = Screen.new(40, 5) - screen:attach() - command('let g:mes = execute("echon 42")') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - | - ]]) - eq('42', eval('g:mes')) - - command('let g:mes = execute("echon 13", "silent")') - screen:expect{grid=[[ - ^ | - ~ | - ~ | - ~ | - | - ]], unchanged=true} - eq('13', eval('g:mes')) - end) - - it('suppresses errors for "silent!"', function() - eq(0, exc_exec('let g:mes = execute(0.0, "silent!")')) - eq('', eval('g:mes')) - - eq(0, exc_exec('let g:mes = execute("echon add(1, 1)", "silent!")')) - eq('1', eval('g:mes')) - - eq(0, exc_exec('let g:mes = execute(["echon 42", "echon add(1, 1)"], "silent!")')) - eq('421', eval('g:mes')) - end) - - it('propagates errors for "" and "silent"', function() - local ret - ret = exc_exec('call execute(0.0, "")') - eq('Vim(call):E806: using Float as a String', ret) - - ret = exc_exec('call execute(v:_null_dict, "silent")') - eq('Vim(call):E731: using Dictionary as a String', ret) - - ret = exc_exec('call execute("echo add(1, 1)", "")') - eq('Vim(echo):E897: List or Blob required', ret) - - ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "")') - eq('Vim(echo):E897: List or Blob required', ret) - - ret = exc_exec('call execute("echo add(1, 1)", "silent")') - eq('Vim(echo):E897: List or Blob required', ret) - - ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "silent")') - eq('Vim(echo):E897: List or Blob required', ret) - end) - end) -end) diff --git a/test/functional/eval/exepath_spec.lua b/test/functional/eval/exepath_spec.lua deleted file mode 100644 index 08d2c59af8..0000000000 --- a/test/functional/eval/exepath_spec.lua +++ /dev/null @@ -1,40 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq, clear, call, iswin = - helpers.eq, helpers.clear, helpers.call, helpers.iswin -local command = helpers.command -local exc_exec = helpers.exc_exec -local matches = helpers.matches - -describe('exepath()', function() - before_each(clear) - - it('returns 1 for commands in $PATH', function() - local exe = iswin() and 'ping' or 'ls' - local ext_pat = iswin() and '%.EXE$' or '$' - matches(exe .. ext_pat, call('exepath', exe)) - command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - ext_pat = iswin() and '%.CMD$' or '$' - matches('null' .. ext_pat, call('exepath', 'null')) - matches('true' .. ext_pat, call('exepath', 'true')) - matches('false' .. ext_pat, call('exepath', 'false')) - end) - - it('fails for invalid values', function() - for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) - end - command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) - end - end) - - if iswin() then - it('append extension if omitted', function() - local filename = 'cmd' - local pathext = '.exe' - clear({env={PATHEXT=pathext}}) - eq(call('exepath', filename..pathext), call('exepath', filename)) - end) - end -end) diff --git a/test/functional/eval/fnamemodify_spec.lua b/test/functional/eval/fnamemodify_spec.lua deleted file mode 100644 index d54a6db417..0000000000 --- a/test/functional/eval/fnamemodify_spec.lua +++ /dev/null @@ -1,156 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq = helpers.eq -local iswin = helpers.iswin -local fnamemodify = helpers.funcs.fnamemodify -local getcwd = helpers.funcs.getcwd -local command = helpers.command -local write_file = helpers.write_file -local alter_slashes = helpers.alter_slashes - -local function eq_slashconvert(expected, got) - eq(alter_slashes(expected), alter_slashes(got)) -end - -describe('fnamemodify()', function() - setup(function() - write_file('Xtest-fnamemodify.txt', [[foobar]]) - end) - - before_each(clear) - - teardown(function() - os.remove('Xtest-fnamemodify.txt') - end) - - it('handles the root path', function() - local root = helpers.pathroot() - eq(root, fnamemodify([[/]], ':p:h')) - eq(root, fnamemodify([[/]], ':p')) - if iswin() then - eq(root, fnamemodify([[\]], ':p:h')) - eq(root, fnamemodify([[\]], ':p')) - command('set shellslash') - root = string.sub(root, 1, -2)..'/' - eq(root, fnamemodify([[\]], ':p:h')) - eq(root, fnamemodify([[\]], ':p')) - eq(root, fnamemodify([[/]], ':p:h')) - eq(root, fnamemodify([[/]], ':p')) - end - end) - - it(':8 works', function() - eq('Xtest-fnamemodify.txt', fnamemodify([[Xtest-fnamemodify.txt]], ':8')) - end) - - it('handles examples from ":help filename-modifiers"', function() - local filename = "src/version.c" - local cwd = getcwd() - - eq_slashconvert(cwd .. '/src/version.c', fnamemodify(filename, ':p')) - - eq_slashconvert('src/version.c', fnamemodify(filename, ':p:.')) - eq_slashconvert(cwd .. '/src', fnamemodify(filename, ':p:h')) - eq_slashconvert(cwd .. '', fnamemodify(filename, ':p:h:h')) - eq('version.c', fnamemodify(filename, ':p:t')) - eq_slashconvert(cwd .. '/src/version', fnamemodify(filename, ':p:r')) - - eq_slashconvert(cwd .. '/src/main.c', fnamemodify(filename, ':s?version?main?:p')) - - local converted_cwd = cwd:gsub('/', '\\') - eq(converted_cwd .. '\\src\\version.c', fnamemodify(filename, ':p:gs?/?\\\\?')) - - eq('src', fnamemodify(filename, ':h')) - eq('version.c', fnamemodify(filename, ':t')) - eq_slashconvert('src/version', fnamemodify(filename, ':r')) - eq('version', fnamemodify(filename, ':t:r')) - eq('c', fnamemodify(filename, ':e')) - - eq_slashconvert('src/main.c', fnamemodify(filename, ':s?version?main?')) - end) - - it('handles advanced examples from ":help filename-modifiers"', function() - local filename = "src/version.c.gz" - - eq('gz', fnamemodify(filename, ':e')) - eq('c.gz', fnamemodify(filename, ':e:e')) - eq('c.gz', fnamemodify(filename, ':e:e:e')) - - eq('c', fnamemodify(filename, ':e:e:r')) - - eq_slashconvert('src/version.c', fnamemodify(filename, ':r')) - eq('c', fnamemodify(filename, ':r:e')) - - eq_slashconvert('src/version', fnamemodify(filename, ':r:r')) - eq_slashconvert('src/version', fnamemodify(filename, ':r:r:r')) - end) - - it('handles :h', function() - eq('.', fnamemodify('hello.txt', ':h')) - - eq_slashconvert('path/to', fnamemodify('path/to/hello.txt', ':h')) - end) - - it('handles :t', function() - eq('hello.txt', fnamemodify('hello.txt', ':t')) - eq_slashconvert('hello.txt', fnamemodify('path/to/hello.txt', ':t')) - end) - - it('handles :r', function() - eq('hello', fnamemodify('hello.txt', ':r')) - eq_slashconvert('path/to/hello', fnamemodify('path/to/hello.txt', ':r')) - end) - - it('handles :e', function() - eq('txt', fnamemodify('hello.txt', ':e')) - eq_slashconvert('txt', fnamemodify('path/to/hello.txt', ':e')) - end) - - it('handles regex replacements', function() - eq('content-there-here.txt', fnamemodify('content-here-here.txt', ':s/here/there/')) - eq('content-there-there.txt', fnamemodify('content-here-here.txt', ':gs/here/there/')) - end) - - it('handles shell escape', function() - local expected - - if iswin() then - -- we expand with double-quotes on Windows - expected = [["hello there! quote ' newline]] .. '\n' .. [["]] - else - expected = [['hello there! quote '\'' newline]] .. '\n' .. [[']] - end - - eq(expected, fnamemodify("hello there! quote ' newline\n", ':S')) - end) - - it('can combine :e and :r', function() - -- simple, single extension filename - eq('c', fnamemodify('a.c', ':e')) - eq('c', fnamemodify('a.c', ':e:e')) - eq('c', fnamemodify('a.c', ':e:e:r')) - eq('c', fnamemodify('a.c', ':e:e:r:r')) - - -- multi extension filename - eq('rb', fnamemodify('a.spec.rb', ':e:r')) - eq('rb', fnamemodify('a.spec.rb', ':e:r:r')) - - eq('spec', fnamemodify('a.spec.rb', ':e:e:r')) - eq('spec', fnamemodify('a.spec.rb', ':e:e:r:r')) - - eq('spec', fnamemodify('a.b.spec.rb', ':e:e:r')) - eq('b.spec', fnamemodify('a.b.spec.rb', ':e:e:e:r')) - eq('b', fnamemodify('a.b.spec.rb', ':e:e:e:r:r')) - - eq('spec', fnamemodify('a.b.spec.rb', ':r:e')) - eq('b', fnamemodify('a.b.spec.rb', ':r:r:e')) - - -- extraneous :e expansions - eq('c', fnamemodify('a.b.c.d.e', ':r:r:e')) - eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e')) - - -- :e never includes the whole filename, so "a.b":e:e:e --> "b" - eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) - eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) - end) -end) diff --git a/test/functional/eval/function_spec.lua b/test/functional/eval/function_spec.lua deleted file mode 100644 index ce8850fcc2..0000000000 --- a/test/functional/eval/function_spec.lua +++ /dev/null @@ -1,37 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local eq = helpers.eq -local matches = helpers.matches -local exc_exec = helpers.exc_exec -local iswin = helpers.iswin -local eval = helpers.eval - -describe('Up to MAX_FUNC_ARGS arguments are handled by', function() - local max_func_args = 20 -- from eval.h - local range = helpers.funcs.range - - before_each(clear) - - it('printf()', function() - local printf = helpers.funcs.printf - local rep = helpers.funcs['repeat'] - local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,' - eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args)))) - local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)') - eq('Vim(call):E740: Too many arguments for function printf', ret) - end) - - it('rpcnotify()', function() - local rpcnotify = helpers.funcs.rpcnotify - local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args))) - eq(1, ret) - ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)') - eq('Vim(call):E740: Too many arguments for function rpcnotify', ret) - end) -end) - -it('windowsversion()', function() - clear() - matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()')) -end) diff --git a/test/functional/eval/getline_spec.lua b/test/functional/eval/getline_spec.lua deleted file mode 100644 index 3c56bde094..0000000000 --- a/test/functional/eval/getline_spec.lua +++ /dev/null @@ -1,39 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local call = helpers.call -local clear = helpers.clear -local eq = helpers.eq -local expect = helpers.expect - -describe('getline()', function() - before_each(function() - clear() - call('setline', 1, {'a', 'b', 'c'}) - expect([[ - a - b - c]]) - end) - - it('returns empty string for invalid line', function() - eq('', call('getline', -1)) - eq('', call('getline', 0)) - eq('', call('getline', 4)) - end) - - it('returns empty list for invalid range', function() - eq({}, call('getline', 2, 1)) - eq({}, call('getline', -1, 1)) - eq({}, call('getline', 4, 4)) - end) - - it('returns value of valid line', function() - eq('b', call('getline', 2)) - eq('a', call('getline', '.')) - end) - - it('returns value of valid range', function() - eq({'a', 'b'}, call('getline', 1, 2)) - eq({'a', 'b', 'c'}, call('getline', 1, 4)) - end) -end) diff --git a/test/functional/eval/glob_spec.lua b/test/functional/eval/glob_spec.lua deleted file mode 100644 index b8807ecfcc..0000000000 --- a/test/functional/eval/glob_spec.lua +++ /dev/null @@ -1,28 +0,0 @@ -local lfs = require('lfs') -local helpers = require('test.functional.helpers')(after_each) -local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq - -before_each(function() - clear() - lfs.mkdir('test-glob') - - -- Long path might cause "Press ENTER" prompt; use :silent to avoid it. - command('silent cd test-glob') -end) - -after_each(function() - lfs.rmdir('test-glob') -end) - -describe('glob()', function() - it("glob('.*') returns . and .. ", function() - eq({'.', '..'}, eval("glob('.*', 0, 1)")) - -- Do it again to verify scandir_next_with_dots() internal state. - eq({'.', '..'}, eval("glob('.*', 0, 1)")) - end) - it("glob('*') returns an empty list ", function() - eq({}, eval("glob('*', 0, 1)")) - -- Do it again to verify scandir_next_with_dots() internal state. - eq({}, eval("glob('*', 0, 1)")) - end) -end) diff --git a/test/functional/eval/has_spec.lua b/test/functional/eval/has_spec.lua deleted file mode 100644 index a3af2d1a20..0000000000 --- a/test/functional/eval/has_spec.lua +++ /dev/null @@ -1,66 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local clear = helpers.clear -local funcs = helpers.funcs -local iswin = helpers.iswin - -describe('has()', function() - before_each(clear) - - it('"nvim-x.y.z"', function() - eq(0, funcs.has("nvim-")) - eq(0, funcs.has("nvim- ")) - eq(0, funcs.has("nvim- \t ")) - eq(0, funcs.has("nvim-0. 1. 1")) - eq(0, funcs.has("nvim-0. 1.1")) - eq(0, funcs.has("nvim-0.1. 1")) - eq(0, funcs.has("nvim-a")) - eq(0, funcs.has("nvim-a.b.c")) - eq(0, funcs.has("nvim-0.b.c")) - eq(0, funcs.has("nvim-0.0.c")) - eq(0, funcs.has("nvim-0.b.0")) - eq(0, funcs.has("nvim-a.b.0")) - eq(0, funcs.has("nvim-.0.0.0")) - eq(0, funcs.has("nvim-.0")) - eq(0, funcs.has("nvim-0.")) - eq(0, funcs.has("nvim-0..")) - eq(0, funcs.has("nvim-.")) - eq(0, funcs.has("nvim-..")) - eq(0, funcs.has("nvim-...")) - eq(0, funcs.has("nvim-42")) - eq(0, funcs.has("nvim-9999")) - eq(0, funcs.has("nvim-99.001.05")) - - eq(1, funcs.has("nvim")) - eq(1, funcs.has("nvim-0")) - eq(1, funcs.has("nvim-0.1")) - eq(1, funcs.has("nvim-0.0.0")) - eq(1, funcs.has("nvim-0.1.1.")) - eq(1, funcs.has("nvim-0.1.1.abc")) - eq(1, funcs.has("nvim-0.1.1..")) - eq(1, funcs.has("nvim-0.1.1.. ..")) - eq(1, funcs.has("nvim-0.1.1.... ")) - eq(1, funcs.has("nvim-0.0.0")) - eq(1, funcs.has("nvim-0.0.1")) - eq(1, funcs.has("nvim-0.1.0")) - eq(1, funcs.has("nvim-0.1.1")) - eq(1, funcs.has("nvim-0.1.5")) - eq(1, funcs.has("nvim-0000.001.05")) - eq(1, funcs.has("nvim-0.01.005")) - eq(1, funcs.has("nvim-00.001.05")) - end) - - it('"unnamedplus"', function() - if (not iswin()) and funcs.has("clipboard") == 1 then - eq(1, funcs.has("unnamedplus")) - else - eq(0, funcs.has("unnamedplus")) - end - end) - - it('"wsl"', function() - if 1 == funcs.has('win32') or 1 == funcs.has('mac') then - eq(0, funcs.has('wsl')) - end - end) -end) diff --git a/test/functional/eval/hostname_spec.lua b/test/functional/eval/hostname_spec.lua deleted file mode 100644 index 6112cf64e3..0000000000 --- a/test/functional/eval/hostname_spec.lua +++ /dev/null @@ -1,20 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local ok = helpers.ok -local call = helpers.call -local clear = helpers.clear -local iswin = helpers.iswin - -describe('hostname()', function() - before_each(clear) - - it('returns hostname string', function() - local actual = call('hostname') - ok(string.len(actual) > 0) - if call('executable', 'hostname') == 1 then - local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '') - eq((iswin() and expected:upper() or expected), - (iswin() and actual:upper() or actual)) - end - end) -end) diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua deleted file mode 100644 index 14c02f9eb2..0000000000 --- a/test/functional/eval/input_spec.lua +++ /dev/null @@ -1,483 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local eq = helpers.eq -local feed = helpers.feed -local meths = helpers.meths -local clear = helpers.clear -local source = helpers.source -local command = helpers.command -local exc_exec = helpers.exc_exec -local nvim_async = helpers.nvim_async - -local screen - -before_each(function() - clear() - screen = Screen.new(25, 5) - screen:attach() - source([[ - hi Test ctermfg=Red guifg=Red term=bold - function CustomCompl(...) - return 'TEST' - endfunction - function CustomListCompl(...) - return ['FOO'] - endfunction - - highlight RBP1 guibg=Red - highlight RBP2 guibg=Yellow - highlight RBP3 guibg=Green - highlight RBP4 guibg=Blue - let g:NUM_LVLS = 4 - function Redraw() - redraw! - return '' - endfunction - cnoremap <expr> {REDRAW} Redraw() - function RainBowParens(cmdline) - let ret = [] - let i = 0 - let lvl = 0 - while i < len(a:cmdline) - if a:cmdline[i] is# '(' - call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) - let lvl += 1 - elseif a:cmdline[i] is# ')' - let lvl -= 1 - call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) - endif - let i += 1 - endwhile - return ret - endfunction - ]]) - screen:set_default_attr_ids({ - EOB={bold = true, foreground = Screen.colors.Blue1}, - T={foreground=Screen.colors.Red}, - RBP1={background=Screen.colors.Red}, - RBP2={background=Screen.colors.Yellow}, - RBP3={background=Screen.colors.Green}, - RBP4={background=Screen.colors.Blue}, - SEP={bold = true, reverse = true}, - CONFIRM={bold = true, foreground = Screen.colors.SeaGreen4}, - }) -end) - -describe('input()', function() - it('works with multiline prompts', function() - feed([[:call input("Test\nFoo")<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - Test | - Foo^ | - ]]) - end) - it('works with multiline prompts and :echohl', function() - feed([[:echohl Test | call input("Test\nFoo")<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - {T:Test} | - {T:Foo}^ | - ]]) - command('redraw!') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo}^ | - ]]) - end) - it('allows unequal numeric arguments when using multiple args', function() - command('echohl Test') - feed([[:call input(1, 2)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}2^ | - ]]) - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}^ | - ]]) - end) - it('allows unequal numeric values when using {opts} dictionary', function() - command('echohl Test') - meths.set_var('opts', {prompt=1, default=2, cancelreturn=3}) - feed([[:echo input(opts)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}2^ | - ]]) - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}^ | - ]]) - feed('<Esc>') - screen:expect([[ - ^ | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:3} | - ]]) - end) - it('works with redraw', function() - command('echohl Test') - meths.set_var('opts', {prompt='Foo>', default='Bar'}) - feed([[:echo inputdialog(opts)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Bar^ | - ]]) - command('mode') - screen:expect{grid=[[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Bar^ | - ]], reset=true} - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Ba^ | - ]]) - command('mode') - screen:expect{grid=[[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Ba^ | - ]], reset=true} - end) - it('allows omitting everything with dictionary argument', function() - command('echohl Test') - feed([[:call input({})<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - ^ | - ]]) - end) - it('supports completion', function() - feed(':let var = input("", "", "custom,CustomCompl")<CR>') - feed('<Tab><CR>') - eq('TEST', meths.get_var('var')) - - feed(':let var = input({"completion": "customlist,CustomListCompl"})<CR>') - feed('<Tab><CR>') - eq('FOO', meths.get_var('var')) - end) - it('supports cancelreturn', function() - feed(':let var = input({"cancelreturn": "BAR"})<CR>') - feed('<Esc>') - eq('BAR', meths.get_var('var')) - end) - it('supports default string', function() - feed(':let var = input("", "DEF1")<CR>') - feed('<CR>') - eq('DEF1', meths.get_var('var')) - - feed(':let var = input({"default": "DEF2"})<CR>') - feed('<CR>') - eq('DEF2', meths.get_var('var')) - end) - it('errors out on invalid inputs', function() - eq('Vim(call):E730: using List as a String', - exc_exec('call input([])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input("", [])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input("", "", [])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input({"prompt": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input({"cancelreturn": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input({"default": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call input({"completion": []})')) - eq('Vim(call):E5050: {opts} must be the only argument', - exc_exec('call input({}, "default")')) - eq('Vim(call):E118: Too many arguments for function: input', - exc_exec('call input("prompt> ", "default", "file", "extra")')) - end) - it('supports highlighting', function() - command('nnoremap <expr> X input({"highlight": "RainBowParens"})[-1]') - feed([[X]]) - feed('(())') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {RBP1:(}{RBP2:()}{RBP1:)}^ | - ]]) - end) - it('is not hidden by :silent', function() - feed([[:silent call input('Foo: ')<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - Foo: ^ | - | - ]]) - feed('Bar') - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - Foo: Bar^ | - | - ]]) - feed('<CR>') - end) -end) -describe('inputdialog()', function() - it('works with multiline prompts', function() - feed([[:call inputdialog("Test\nFoo")<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - Test | - Foo^ | - ]]) - end) - it('works with multiline prompts and :echohl', function() - feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {SEP: }| - {T:Test} | - {T:Foo}^ | - ]]) - command('redraw!') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo}^ | - ]]) - end) - it('allows unequal numeric arguments when using multiple args', function() - command('echohl Test') - feed([[:call inputdialog(1, 2)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}2^ | - ]]) - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}^ | - ]]) - end) - it('allows unequal numeric values when using {opts} dictionary', function() - command('echohl Test') - meths.set_var('opts', {prompt=1, default=2, cancelreturn=3}) - feed([[:echo input(opts)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}2^ | - ]]) - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:1}^ | - ]]) - feed('<Esc>') - screen:expect([[ - ^ | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:3} | - ]]) - end) - it('works with redraw', function() - command('echohl Test') - meths.set_var('opts', {prompt='Foo>', default='Bar'}) - feed([[:echo input(opts)<CR>]]) - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Bar^ | - ]]) - command('mode') - screen:expect{grid=[[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Bar^ | - ]], reset=true} - feed('<BS>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Ba^ | - ]]) - command('mode') - screen:expect{grid=[[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {T:Foo>}Ba^ | - ]], reset=true} - end) - it('allows omitting everything with dictionary argument', function() - command('echohl Test') - feed(':echo inputdialog({})<CR>') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - ^ | - ]]) - end) - it('supports completion', function() - feed(':let var = inputdialog({"completion": "customlist,CustomListCompl"})<CR>') - feed('<Tab><CR>') - eq('FOO', meths.get_var('var')) - end) - it('supports cancelreturn', function() - feed(':let var = inputdialog("", "", "CR1")<CR>') - feed('<Esc>') - eq('CR1', meths.get_var('var')) - - feed(':let var = inputdialog({"cancelreturn": "BAR"})<CR>') - feed('<Esc>') - eq('BAR', meths.get_var('var')) - end) - it('supports default string', function() - feed(':let var = inputdialog("", "DEF1")<CR>') - feed('<CR>') - eq('DEF1', meths.get_var('var')) - - feed(':let var = inputdialog({"default": "DEF2"})<CR>') - feed('<CR>') - eq('DEF2', meths.get_var('var')) - end) - it('errors out on invalid inputs', function() - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog([])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog("", [])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog("", "", [])')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog({"prompt": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog({"cancelreturn": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog({"default": []})')) - eq('Vim(call):E730: using List as a String', - exc_exec('call inputdialog({"completion": []})')) - eq('Vim(call):E5050: {opts} must be the only argument', - exc_exec('call inputdialog({}, "default")')) - eq('Vim(call):E118: Too many arguments for function: inputdialog', - exc_exec('call inputdialog("prompt> ", "default", "file", "extra")')) - end) - it('supports highlighting', function() - command('nnoremap <expr> X inputdialog({"highlight": "RainBowParens"})[-1]') - feed([[X]]) - feed('(())') - screen:expect([[ - | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - {RBP1:(}{RBP2:()}{RBP1:)}^ | - ]]) - end) -end) - -describe('confirm()', function() - it("shows dialog even if :silent #8788", function() - command("autocmd BufNewFile * call confirm('test')") - - local function check_and_clear(edit_line) - screen:expect([[ - | - {SEP: }| - ]]..edit_line..[[ - {CONFIRM:test} | - {CONFIRM:[O]k: }^ | - ]]) - feed('<cr>') - command('redraw') - command('bdelete!') - end - - -- With shortmess-=F - command('set shortmess-=F') - feed(':edit foo<cr>') - check_and_clear('"foo" [New] |\n') - - -- With shortmess+=F - command('set shortmess+=F') - feed(':edit foo<cr>') - check_and_clear(':edit foo |\n') - - -- With :silent - feed(':silent edit foo<cr>') - check_and_clear(':silent edit foo |\n') - - -- With API (via eval/VimL) call and shortmess+=F - feed(':call nvim_command("edit x")<cr>') - check_and_clear(':call nvim_command("edit |\n') - - nvim_async('command', 'edit x') - check_and_clear(' |\n') - end) -end) diff --git a/test/functional/eval/interrupt_spec.lua b/test/functional/eval/interrupt_spec.lua deleted file mode 100644 index 05b1f4ff57..0000000000 --- a/test/functional/eval/interrupt_spec.lua +++ /dev/null @@ -1,61 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local command = helpers.command -local meths = helpers.meths -local clear = helpers.clear -local sleep = helpers.sleep -local poke_eventloop = helpers.poke_eventloop -local feed = helpers.feed -local eq = helpers.eq - -local dur -local min_dur = 8 -local len = 131072 - -describe('List support code', function() - if not pending('does not actually allows interrupting with just got_int', function() end) then return end - -- The following tests are confirmed to work with os_breakcheck() just before - -- `if (got_int) {break;}` in tv_list_copy and list_join_inner() and not to - -- work without. - setup(function() - clear() - dur = 0 - while true do - command(([[ - let rt = reltime() - let bl = range(%u) - let dur = reltimestr(reltime(rt)) - ]]):format(len)) - dur = tonumber(meths.get_var('dur')) - if dur >= min_dur then - -- print(('Using len %u, dur %g'):format(len, dur)) - break - else - len = len * 2 - end - end - end) - it('allows interrupting copy', function() - feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>') - sleep(min_dur / 16 * 1000) - feed('<C-c>') - poke_eventloop() - command('let t_dur = reltimestr(reltime(t_rt))') - local t_dur = tonumber(meths.get_var('t_dur')) - if t_dur >= dur / 8 then - eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8)) - end - end) - it('allows interrupting join', function() - feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>') - sleep(min_dur / 16 * 1000) - feed('<C-c>') - poke_eventloop() - command('let t_dur = reltimestr(reltime(t_rt))') - local t_dur = tonumber(meths.get_var('t_dur')) - print(('t_dur: %g'):format(t_dur)) - if t_dur >= dur / 8 then - eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8)) - end - end) -end) diff --git a/test/functional/eval/json_functions_spec.lua b/test/functional/eval/json_functions_spec.lua deleted file mode 100644 index 9b5e207c07..0000000000 --- a/test/functional/eval/json_functions_spec.lua +++ /dev/null @@ -1,795 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local funcs = helpers.funcs -local meths = helpers.meths -local eq = helpers.eq -local eval = helpers.eval -local command = helpers.command -local exc_exec = helpers.exc_exec -local redir_exec = helpers.redir_exec -local NIL = helpers.NIL -local source = helpers.source - -describe('json_decode() function', function() - local restart = function(...) - clear(...) - source([[ - language C - function Eq(exp, act) - let act = a:act - let exp = a:exp - if type(exp) != type(act) - return 0 - endif - if type(exp) == type({}) - if sort(keys(exp)) !=# sort(keys(act)) - return 0 - endif - if sort(keys(exp)) ==# ['_TYPE', '_VAL'] - let exp_typ = v:msgpack_types[exp._TYPE] - let act_typ = act._TYPE - if exp_typ isnot act_typ - return 0 - endif - return Eq(exp._VAL, act._VAL) - else - return empty(filter(copy(exp), '!Eq(v:val, act[v:key])')) - endif - else - if type(exp) == type([]) - if len(exp) != len(act) - return 0 - endif - return empty(filter(copy(exp), '!Eq(v:val, act[v:key])')) - endif - return exp ==# act - endif - return 1 - endfunction - function EvalEq(exp, act_expr) - let act = eval(a:act_expr) - if Eq(a:exp, act) - return 1 - else - return string(act) - endif - endfunction - ]]) - end - before_each(restart) - - local speq = function(expected, actual_expr) - eq(1, funcs.EvalEq(expected, actual_expr)) - end - - it('accepts readfile()-style list', function() - eq({Test=1}, funcs.json_decode({ - '{', - '\t"Test": 1', - '}', - })) - end) - - it('accepts strings with newlines', function() - eq({Test=1}, funcs.json_decode([[ - { - "Test": 1 - } - ]])) - end) - - it('parses null, true, false', function() - eq(NIL, funcs.json_decode('null')) - eq(true, funcs.json_decode('true')) - eq(false, funcs.json_decode('false')) - end) - - it('fails to parse incomplete null, true, false', function() - eq('Vim(call):E474: Expected null: n', - exc_exec('call json_decode("n")')) - eq('Vim(call):E474: Expected null: nu', - exc_exec('call json_decode("nu")')) - eq('Vim(call):E474: Expected null: nul', - exc_exec('call json_decode("nul")')) - eq('Vim(call):E474: Expected null: nul\n\t', - exc_exec('call json_decode("nul\\n\\t")')) - - eq('Vim(call):E474: Expected true: t', - exc_exec('call json_decode("t")')) - eq('Vim(call):E474: Expected true: tr', - exc_exec('call json_decode("tr")')) - eq('Vim(call):E474: Expected true: tru', - exc_exec('call json_decode("tru")')) - eq('Vim(call):E474: Expected true: tru\t\n', - exc_exec('call json_decode("tru\\t\\n")')) - - eq('Vim(call):E474: Expected false: f', - exc_exec('call json_decode("f")')) - eq('Vim(call):E474: Expected false: fa', - exc_exec('call json_decode("fa")')) - eq('Vim(call):E474: Expected false: fal', - exc_exec('call json_decode("fal")')) - eq('Vim(call):E474: Expected false: fal <', - exc_exec('call json_decode(" fal <")')) - eq('Vim(call):E474: Expected false: fals', - exc_exec('call json_decode("fals")')) - end) - - it('parses integer numbers', function() - eq(100000, funcs.json_decode('100000')) - eq(-100000, funcs.json_decode('-100000')) - eq(100000, funcs.json_decode(' 100000 ')) - eq(-100000, funcs.json_decode(' -100000 ')) - eq(0, funcs.json_decode('0')) - eq(0, funcs.json_decode('-0')) - end) - - it('fails to parse +numbers and .number', function() - eq('Vim(call):E474: Unidentified byte: +1000', - exc_exec('call json_decode("+1000")')) - eq('Vim(call):E474: Unidentified byte: .1000', - exc_exec('call json_decode(".1000")')) - end) - - it('fails to parse numbers with leading zeroes', function() - eq('Vim(call):E474: Leading zeroes are not allowed: 00.1', - exc_exec('call json_decode("00.1")')) - eq('Vim(call):E474: Leading zeroes are not allowed: 01', - exc_exec('call json_decode("01")')) - eq('Vim(call):E474: Leading zeroes are not allowed: -01', - exc_exec('call json_decode("-01")')) - eq('Vim(call):E474: Leading zeroes are not allowed: -001.0', - exc_exec('call json_decode("-001.0")')) - end) - - it('fails to parse incomplete numbers', function() - eq('Vim(call):E474: Missing number after minus sign: -.1', - exc_exec('call json_decode("-.1")')) - eq('Vim(call):E474: Missing number after minus sign: -', - exc_exec('call json_decode("-")')) - eq('Vim(call):E474: Missing number after decimal dot: -1.', - exc_exec('call json_decode("-1.")')) - eq('Vim(call):E474: Missing number after decimal dot: 0.', - exc_exec('call json_decode("0.")')) - eq('Vim(call):E474: Missing exponent: 0.0e', - exc_exec('call json_decode("0.0e")')) - eq('Vim(call):E474: Missing exponent: 0.0e+', - exc_exec('call json_decode("0.0e+")')) - eq('Vim(call):E474: Missing exponent: 0.0e-', - exc_exec('call json_decode("0.0e-")')) - eq('Vim(call):E474: Missing exponent: 0.0e-', - exc_exec('call json_decode("0.0e-")')) - eq('Vim(call):E474: Missing number after decimal dot: 1.e5', - exc_exec('call json_decode("1.e5")')) - eq('Vim(call):E474: Missing number after decimal dot: 1.e+5', - exc_exec('call json_decode("1.e+5")')) - eq('Vim(call):E474: Missing number after decimal dot: 1.e+', - exc_exec('call json_decode("1.e+")')) - end) - - it('parses floating-point numbers', function() - eq('100000.0', eval('string(json_decode("100000.0"))')) - eq(100000.5, funcs.json_decode('100000.5')) - eq(-100000.5, funcs.json_decode('-100000.5')) - eq(-100000.5e50, funcs.json_decode('-100000.5e50')) - eq(100000.5e50, funcs.json_decode('100000.5e50')) - eq(100000.5e50, funcs.json_decode('100000.5e+50')) - eq(-100000.5e-50, funcs.json_decode('-100000.5e-50')) - eq(100000.5e-50, funcs.json_decode('100000.5e-50')) - eq(100000e-50, funcs.json_decode('100000e-50')) - eq(0.5, funcs.json_decode('0.5')) - eq(0.005, funcs.json_decode('0.005')) - eq(0.005, funcs.json_decode('0.00500')) - eq(0.5, funcs.json_decode('0.00500e+002')) - eq(0.00005, funcs.json_decode('0.00500e-002')) - - eq(-0.0, funcs.json_decode('-0.0')) - eq(-0.0, funcs.json_decode('-0.0e0')) - eq(-0.0, funcs.json_decode('-0.0e+0')) - eq(-0.0, funcs.json_decode('-0.0e-0')) - eq(-0.0, funcs.json_decode('-0e-0')) - eq(-0.0, funcs.json_decode('-0e-2')) - eq(-0.0, funcs.json_decode('-0e+2')) - - eq(0.0, funcs.json_decode('0.0')) - eq(0.0, funcs.json_decode('0.0e0')) - eq(0.0, funcs.json_decode('0.0e+0')) - eq(0.0, funcs.json_decode('0.0e-0')) - eq(0.0, funcs.json_decode('0e-0')) - eq(0.0, funcs.json_decode('0e-2')) - eq(0.0, funcs.json_decode('0e+2')) - end) - - it('fails to parse numbers with spaces inside', function() - eq('Vim(call):E474: Missing number after minus sign: - 1000', - exc_exec('call json_decode("- 1000")')) - eq('Vim(call):E474: Missing number after decimal dot: 0. ', - exc_exec('call json_decode("0. ")')) - eq('Vim(call):E474: Missing number after decimal dot: 0. 0', - exc_exec('call json_decode("0. 0")')) - eq('Vim(call):E474: Missing exponent: 0.0e 1', - exc_exec('call json_decode("0.0e 1")')) - eq('Vim(call):E474: Missing exponent: 0.0e+ 1', - exc_exec('call json_decode("0.0e+ 1")')) - eq('Vim(call):E474: Missing exponent: 0.0e- 1', - exc_exec('call json_decode("0.0e- 1")')) - end) - - it('fails to parse "," and ":"', function() - eq('Vim(call):E474: Comma not inside container: , ', - exc_exec('call json_decode(" , ")')) - eq('Vim(call):E474: Colon not inside container: : ', - exc_exec('call json_decode(" : ")')) - end) - - it('parses empty containers', function() - eq({}, funcs.json_decode('[]')) - eq('[]', eval('string(json_decode("[]"))')) - end) - - it('fails to parse "[" and "{"', function() - eq('Vim(call):E474: Unexpected end of input: {', - exc_exec('call json_decode("{")')) - eq('Vim(call):E474: Unexpected end of input: [', - exc_exec('call json_decode("[")')) - end) - - it('fails to parse "}" and "]"', function() - eq('Vim(call):E474: No container to close: ]', - exc_exec('call json_decode("]")')) - eq('Vim(call):E474: No container to close: }', - exc_exec('call json_decode("}")')) - end) - - it('fails to parse containers which are closed by different brackets', - function() - eq('Vim(call):E474: Closing dictionary with square bracket: ]', - exc_exec('call json_decode("{]")')) - eq('Vim(call):E474: Closing list with curly bracket: }', - exc_exec('call json_decode("[}")')) - end) - - it('fails to parse concat inside container', function() - eq('Vim(call):E474: Expected comma before list item: []]', - exc_exec('call json_decode("[[][]]")')) - eq('Vim(call):E474: Expected comma before list item: {}]', - exc_exec('call json_decode("[{}{}]")')) - eq('Vim(call):E474: Expected comma before list item: ]', - exc_exec('call json_decode("[1 2]")')) - eq('Vim(call):E474: Expected comma before dictionary key: ": 4}', - exc_exec('call json_decode("{\\"1\\": 2 \\"3\\": 4}")')) - eq('Vim(call):E474: Expected colon before dictionary value: , "3" 4}', - exc_exec('call json_decode("{\\"1\\" 2, \\"3\\" 4}")')) - end) - - it('fails to parse containers with leading comma or colon', function() - eq('Vim(call):E474: Leading comma: ,}', - exc_exec('call json_decode("{,}")')) - eq('Vim(call):E474: Leading comma: ,]', - exc_exec('call json_decode("[,]")')) - eq('Vim(call):E474: Using colon not in dictionary: :]', - exc_exec('call json_decode("[:]")')) - eq('Vim(call):E474: Unexpected colon: :}', - exc_exec('call json_decode("{:}")')) - end) - - it('fails to parse containers with trailing comma', function() - eq('Vim(call):E474: Trailing comma: ]', - exc_exec('call json_decode("[1,]")')) - eq('Vim(call):E474: Trailing comma: }', - exc_exec('call json_decode("{\\"1\\": 2,}")')) - end) - - it('fails to parse dictionaries with missing value', function() - eq('Vim(call):E474: Expected value after colon: }', - exc_exec('call json_decode("{\\"1\\":}")')) - eq('Vim(call):E474: Expected value: }', - exc_exec('call json_decode("{\\"1\\"}")')) - end) - - it('fails to parse containers with two commas or colons', function() - eq('Vim(call):E474: Duplicate comma: , "2": 2}', - exc_exec('call json_decode("{\\"1\\": 1,, \\"2\\": 2}")')) - eq('Vim(call):E474: Duplicate comma: , "2", 2]', - exc_exec('call json_decode("[\\"1\\", 1,, \\"2\\", 2]")')) - eq('Vim(call):E474: Duplicate colon: : 2}', - exc_exec('call json_decode("{\\"1\\": 1, \\"2\\":: 2}")')) - eq('Vim(call):E474: Comma after colon: , 2}', - exc_exec('call json_decode("{\\"1\\": 1, \\"2\\":, 2}")')) - eq('Vim(call):E474: Unexpected colon: : "2": 2}', - exc_exec('call json_decode("{\\"1\\": 1,: \\"2\\": 2}")')) - eq('Vim(call):E474: Unexpected colon: :, "2": 2}', - exc_exec('call json_decode("{\\"1\\": 1:, \\"2\\": 2}")')) - end) - - it('fails to parse concat of two values', function() - eq('Vim(call):E474: Trailing characters: []', - exc_exec('call json_decode("{}[]")')) - end) - - it('parses containers', function() - eq({1}, funcs.json_decode('[1]')) - eq({NIL, 1}, funcs.json_decode('[null, 1]')) - eq({['1']=2}, funcs.json_decode('{"1": 2}')) - eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}}, - funcs.json_decode('{"1": 2, "3": [{"4": {"5": [[], 1]}}]}')) - end) - - it('fails to parse incomplete strings', function() - eq('Vim(call):E474: Expected string end: \t"', - exc_exec('call json_decode("\\t\\"")')) - eq('Vim(call):E474: Expected string end: \t"abc', - exc_exec('call json_decode("\\t\\"abc")')) - eq('Vim(call):E474: Unfinished escape sequence: \t"abc\\', - exc_exec('call json_decode("\\t\\"abc\\\\")')) - eq('Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u', - exc_exec('call json_decode("\\t\\"abc\\\\u")')) - eq('Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u0', - exc_exec('call json_decode("\\t\\"abc\\\\u0")')) - eq('Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u00', - exc_exec('call json_decode("\\t\\"abc\\\\u00")')) - eq('Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u000', - exc_exec('call json_decode("\\t\\"abc\\\\u000")')) - eq('Vim(call):E474: Expected four hex digits after \\u: \\u" ', - exc_exec('call json_decode("\\t\\"abc\\\\u\\" ")')) - eq('Vim(call):E474: Expected four hex digits after \\u: \\u0" ', - exc_exec('call json_decode("\\t\\"abc\\\\u0\\" ")')) - eq('Vim(call):E474: Expected four hex digits after \\u: \\u00" ', - exc_exec('call json_decode("\\t\\"abc\\\\u00\\" ")')) - eq('Vim(call):E474: Expected four hex digits after \\u: \\u000" ', - exc_exec('call json_decode("\\t\\"abc\\\\u000\\" ")')) - eq('Vim(call):E474: Expected string end: \t"abc\\u0000', - exc_exec('call json_decode("\\t\\"abc\\\\u0000")')) - end) - - it('fails to parse unknown escape sequnces', function() - eq('Vim(call):E474: Unknown escape sequence: \\a"', - exc_exec('call json_decode("\\t\\"\\\\a\\"")')) - end) - - it('parses strings properly', function() - eq('\n', funcs.json_decode('"\\n"')) - eq('', funcs.json_decode('""')) - eq('\\/"\t\b\n\r\f', funcs.json_decode([["\\\/\"\t\b\n\r\f"]])) - eq('/a', funcs.json_decode([["\/a"]])) - -- Unicode characters: 2-byte, 3-byte, 4-byte - eq({ - '«', - 'ફ', - '\240\144\128\128', - }, funcs.json_decode({ - '[', - '"«",', - '"ફ",', - '"\240\144\128\128"', - ']', - })) - end) - - it('fails on strings with invalid bytes', function() - eq('Vim(call):E474: Only UTF-8 strings allowed: \255"', - exc_exec('call json_decode("\\t\\"\\xFF\\"")')) - eq('Vim(call):E474: ASCII control characters cannot be present inside string: ', - exc_exec('call json_decode(["\\"\\n\\""])')) - -- 0xC2 starts 2-byte unicode character - eq('Vim(call):E474: Only UTF-8 strings allowed: \194"', - exc_exec('call json_decode("\\t\\"\\xC2\\"")')) - -- 0xE0 0xAA starts 3-byte unicode character - eq('Vim(call):E474: Only UTF-8 strings allowed: \224"', - exc_exec('call json_decode("\\t\\"\\xE0\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \224\170"', - exc_exec('call json_decode("\\t\\"\\xE0\\xAA\\"")')) - -- 0xF0 0x90 0x80 starts 4-byte unicode character - eq('Vim(call):E474: Only UTF-8 strings allowed: \240"', - exc_exec('call json_decode("\\t\\"\\xF0\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \240\144"', - exc_exec('call json_decode("\\t\\"\\xF0\\x90\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \240\144\128"', - exc_exec('call json_decode("\\t\\"\\xF0\\x90\\x80\\"")')) - -- 0xF9 0x80 0x80 0x80 starts 5-byte unicode character - eq('Vim(call):E474: Only UTF-8 strings allowed: \249"', - exc_exec('call json_decode("\\t\\"\\xF9\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \249\128"', - exc_exec('call json_decode("\\t\\"\\xF9\\x80\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \249\128\128"', - exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \249\128\128\128"', - exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\x80\\"")')) - -- 0xFC 0x90 0x80 0x80 0x80 starts 6-byte unicode character - eq('Vim(call):E474: Only UTF-8 strings allowed: \252"', - exc_exec('call json_decode("\\t\\"\\xFC\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \252\144"', - exc_exec('call json_decode("\\t\\"\\xFC\\x90\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \252\144\128"', - exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \252\144\128\128"', - exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\"")')) - eq('Vim(call):E474: Only UTF-8 strings allowed: \252\144\128\128\128"', - exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\x80\\"")')) - -- Specification does not allow unquoted characters above 0x10FFFF - eq('Vim(call):E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \249\128\128\128\128"', - exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\x80\\x80\\"")')) - eq('Vim(call):E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"', - exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\x80\\x80\\"")')) - -- '"\249\128\128\128\128"', - -- '"\252\144\128\128\128\128"', - end) - - it('parses surrogate pairs properly', function() - eq('\240\144\128\128', funcs.json_decode('"\\uD800\\uDC00"')) - eq('\237\160\128a\237\176\128', funcs.json_decode('"\\uD800a\\uDC00"')) - eq('\237\160\128\t\237\176\128', funcs.json_decode('"\\uD800\\t\\uDC00"')) - - eq('\237\160\128', funcs.json_decode('"\\uD800"')) - eq('\237\160\128a', funcs.json_decode('"\\uD800a"')) - eq('\237\160\128\t', funcs.json_decode('"\\uD800\\t"')) - - eq('\237\176\128', funcs.json_decode('"\\uDC00"')) - eq('\237\176\128a', funcs.json_decode('"\\uDC00a"')) - eq('\237\176\128\t', funcs.json_decode('"\\uDC00\\t"')) - - eq('\237\176\128', funcs.json_decode('"\\uDC00"')) - eq('a\237\176\128', funcs.json_decode('"a\\uDC00"')) - eq('\t\237\176\128', funcs.json_decode('"\\t\\uDC00"')) - - eq('\237\160\128¬', funcs.json_decode('"\\uD800\\u00AC"')) - - eq('\237\160\128\237\160\128', funcs.json_decode('"\\uD800\\uD800"')) - end) - - local sp_decode_eq = function(expected, json) - meths.set_var('__json', json) - speq(expected, 'json_decode(g:__json)') - command('unlet! g:__json') - end - - it('parses strings with NUL properly', function() - sp_decode_eq({_TYPE='string', _VAL={'\n'}}, '"\\u0000"') - sp_decode_eq({_TYPE='string', _VAL={'\n', '\n'}}, '"\\u0000\\n\\u0000"') - sp_decode_eq({_TYPE='string', _VAL={'\n«\n'}}, '"\\u0000\\u00AB\\u0000"') - end) - - it('parses dictionaries with duplicate keys to special maps', function() - sp_decode_eq({_TYPE='map', _VAL={{'a', 1}, {'a', 2}}}, - '{"a": 1, "a": 2}') - sp_decode_eq({_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'a', 2}}}, - '{"b": 3, "a": 1, "a": 2}') - sp_decode_eq({_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}}}, - '{"b": 3, "a": 1, "c": 4, "a": 2}') - sp_decode_eq({_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}, {'c', 4}}}, - '{"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}') - sp_decode_eq({{_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}, {'c', 4}}}}, - '[{"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}]') - sp_decode_eq({{d={_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}, {'c', 4}}}}}, - '[{"d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') - sp_decode_eq({1, {d={_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}, {'c', 4}}}}}, - '[1, {"d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') - sp_decode_eq({1, {a={}, d={_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'a', 2}, {'c', 4}}}}}, - '[1, {"a": [], "d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') - end) - - it('parses dictionaries with empty keys to special maps', function() - sp_decode_eq({_TYPE='map', _VAL={{'', 4}}}, - '{"": 4}') - sp_decode_eq({_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'d', 2}, {'', 4}}}, - '{"b": 3, "a": 1, "c": 4, "d": 2, "": 4}') - sp_decode_eq({_TYPE='map', _VAL={{'', 3}, {'a', 1}, {'c', 4}, {'d', 2}, {'', 4}}}, - '{"": 3, "a": 1, "c": 4, "d": 2, "": 4}') - sp_decode_eq({{_TYPE='map', _VAL={{'', 3}, {'a', 1}, {'c', 4}, {'d', 2}, {'', 4}}}}, - '[{"": 3, "a": 1, "c": 4, "d": 2, "": 4}]') - end) - - it('parses dictionaries with keys with NUL bytes to special maps', function() - sp_decode_eq({_TYPE='map', _VAL={{{_TYPE='string', _VAL={'a\n', 'b'}}, 4}}}, - '{"a\\u0000\\nb": 4}') - sp_decode_eq({_TYPE='map', _VAL={{{_TYPE='string', _VAL={'a\n', 'b', ''}}, 4}}}, - '{"a\\u0000\\nb\\n": 4}') - sp_decode_eq({_TYPE='map', _VAL={{'b', 3}, {'a', 1}, {'c', 4}, {'d', 2}, {{_TYPE='string', _VAL={'\n'}}, 4}}}, - '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}') - end) - - it('parses U+00C3 correctly', function() - eq('\195\131', funcs.json_decode('"\195\131"')) - end) - - it('fails to parse empty string', function() - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode("")')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode([])')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode([""])')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode(" ")')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode("\\t")')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode("\\n")')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode(" \\t\\n \\n\\t\\t \\n\\t\\n \\n \\t\\n\\t ")')) - end) - - it('accepts all spaces in every position where space may be put', function() - local s = ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t' - local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s) - eq({key={'val', 'val2'}, key2=1}, funcs.json_decode(str)) - end) - - it('does not overflow when writing error message about decoding ["", ""]', - function() - eq('\nE474: Attempt to decode a blank string' - .. '\nE474: Failed to parse \n', - redir_exec('call json_decode(["", ""])')) - end) -end) - -describe('json_encode() function', function() - before_each(function() - clear() - command('language C') - end) - - it('dumps strings', function() - eq('"Test"', funcs.json_encode('Test')) - eq('""', funcs.json_encode('')) - eq('"\\t"', funcs.json_encode('\t')) - eq('"\\n"', funcs.json_encode('\n')) - eq('"\\u001B"', funcs.json_encode('\27')) - eq('"þÿþ"', funcs.json_encode('þÿþ')) - end) - - it('dumps blobs', function() - eq('[]', eval('json_encode(0z)')) - eq('[222, 173, 190, 239]', eval('json_encode(0zDEADBEEF)')) - end) - - it('dumps numbers', function() - eq('0', funcs.json_encode(0)) - eq('10', funcs.json_encode(10)) - eq('-10', funcs.json_encode(-10)) - end) - - it('dumps floats', function() - eq('0.0', eval('json_encode(0.0)')) - eq('10.5', funcs.json_encode(10.5)) - eq('-10.5', funcs.json_encode(-10.5)) - eq('-1.0e-5', funcs.json_encode(-1e-5)) - eq('1.0e50', eval('json_encode(1.0e50)')) - end) - - it('fails to dump NaN and infinite values', function() - eq('Vim(call):E474: Unable to represent NaN value in JSON', - exc_exec('call json_encode(str2float("nan"))')) - eq('Vim(call):E474: Unable to represent infinity in JSON', - exc_exec('call json_encode(str2float("inf"))')) - eq('Vim(call):E474: Unable to represent infinity in JSON', - exc_exec('call json_encode(-str2float("inf"))')) - end) - - it('dumps lists', function() - eq('[]', funcs.json_encode({})) - eq('[[]]', funcs.json_encode({{}})) - eq('[[], []]', funcs.json_encode({{}, {}})) - end) - - it('dumps dictionaries', function() - eq('{}', eval('json_encode({})')) - eq('{"d": []}', funcs.json_encode({d={}})) - eq('{"d": [], "e": []}', funcs.json_encode({d={}, e={}})) - end) - - it('cannot dump generic mapping with generic mapping keys and values', - function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('call add(todump._VAL, [todumpv1, todumpv2])') - eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) - end) - - it('cannot dump generic mapping with ext key', function() - command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) - end) - - it('cannot dump generic mapping with array key', function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) - end) - - it('cannot dump generic mapping with UINT64_MAX key', function() - command('let todump = {"_TYPE": v:msgpack_types.integer}') - command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) - end) - - it('cannot dump generic mapping with floating-point key', function() - command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) - end) - - it('can dump generic mapping with STR special key and NUL', function() - command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('{"\\u0000": 1}', eval('json_encode(todump)')) - end) - - it('can dump generic mapping with BIN special key and NUL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}') - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') - eq('{"\\u0000": 1}', eval('json_encode(todump)')) - end) - - it('can dump STR special mapping with NUL and NL', function() - command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}') - eq('"\\u0000\\n"', eval('json_encode(todump)')) - end) - - it('can dump BIN special mapping with NUL and NL', function() - command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}') - eq('"\\u0000\\n"', eval('json_encode(todump)')) - end) - - it('cannot dump special ext mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') - eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)')) - end) - - it('can dump special array mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') - eq('[5, [""]]', eval('json_encode(todump)')) - end) - - it('can dump special UINT64_MAX mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.integer}') - command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') - eq('18446744073709551615', eval('json_encode(todump)')) - end) - - it('can dump special INT64_MIN mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.integer}') - command('let todump._VAL = [-1, 2, 0, 0]') - eq('-9223372036854775808', eval('json_encode(todump)')) - end) - - it('can dump special BOOLEAN true mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}') - eq('true', eval('json_encode(todump)')) - end) - - it('can dump special BOOLEAN false mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}') - eq('false', eval('json_encode(todump)')) - end) - - it('can dump special NIL mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}') - eq('null', eval('json_encode(todump)')) - end) - - it('fails to dump a function reference', function() - eq('Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference', - exc_exec('call json_encode(function("tr"))')) - end) - - it('fails to dump a partial', function() - command('function T() dict\nendfunction') - eq('Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference', - exc_exec('call json_encode(function("T", [1, 2], {}))')) - end) - - it('fails to dump a function reference in a list', function() - eq('Vim(call):E474: Error while dumping encode_tv2json() argument, index 0: attempt to dump function reference', - exc_exec('call json_encode([function("tr")])')) - end) - - it('fails to dump a recursive list', function() - command('let todump = [[[]]]') - command('call add(todump[0][0], todump)') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode(todump)')) - end) - - it('fails to dump a recursive dict', function() - command('let todump = {"d": {"d": {}}}') - command('call extend(todump.d.d, {"d": todump})') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode([todump])')) - end) - - it('can dump dict with two same dicts inside', function() - command('let inter = {}') - command('let todump = {"a": inter, "b": inter}') - eq('{"a": {}, "b": {}}', eval('json_encode(todump)')) - end) - - it('can dump list with two same lists inside', function() - command('let inter = []') - command('let todump = [inter, inter]') - eq('[[], []]', eval('json_encode(todump)')) - end) - - it('fails to dump a recursive list in a special dict', function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') - command('call add(todump._VAL, todump)') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode(todump)')) - end) - - it('fails to dump a recursive (val) map in a special dict', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('call add(todump._VAL, ["", todump])') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode([todump])')) - end) - - it('fails to dump a recursive (val) map in a special dict, _VAL reference', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}') - command('call add(todump._VAL[0][1], todump._VAL)') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode(todump)')) - end) - - it('fails to dump a recursive (val) special list in a special dict', - function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') - command('call add(todump._VAL, ["", todump._VAL])') - eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', - exc_exec('call json_encode(todump)')) - end) - - it('fails when called with no arguments', function() - eq('Vim(call):E119: Not enough arguments for function: json_encode', - exc_exec('call json_encode()')) - end) - - it('fails when called with two arguments', function() - eq('Vim(call):E118: Too many arguments for function: json_encode', - exc_exec('call json_encode(["", ""], 1)')) - end) - - it('ignores improper values in &isprint', function() - meths.set_option('isprint', '1') - eq(1, eval('"\1" =~# "\\\\p"')) - eq('"\\u0001"', funcs.json_encode('\1')) - end) - - it('fails when using surrogate character in a UTF-8 string', function() - eq('Vim(call):E474: UTF-8 string contains code point which belongs to a surrogate pair: \237\160\128', - exc_exec('call json_encode("\237\160\128")')) - eq('Vim(call):E474: UTF-8 string contains code point which belongs to a surrogate pair: \237\175\191', - exc_exec('call json_encode("\237\175\191")')) - end) - - it('dumps control characters as expected', function() - eq([["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000B\f\r\u000E\u000F\u0010\u0011\u0012\u0013"]], - eval('json_encode({"_TYPE": v:msgpack_types.string, "_VAL": ["\n\1\2\3\4\5\6\7\8\9", "\11\12\13\14\15\16\17\18\19"]})')) - end) - - it('can dump NULL string', function() - eq('""', eval('json_encode($XXX_UNEXISTENT_VAR_XXX)')) - end) - - it('can dump NULL blob', function() - eq('[]', eval('json_encode(v:_null_blob)')) - end) - - it('can dump NULL list', function() - eq('[]', eval('json_encode(v:_null_list)')) - end) - - it('can dump NULL dictionary', function() - eq('{}', eval('json_encode(v:_null_dict)')) - end) - - it('fails to parse NULL strings and lists', function() - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode($XXX_UNEXISTENT_VAR_XXX)')) - eq('Vim(call):E474: Attempt to decode a blank string', - exc_exec('call json_decode(v:_null_list)')) - end) -end) diff --git a/test/functional/eval/let_spec.lua b/test/functional/eval/let_spec.lua deleted file mode 100644 index 5bc703b567..0000000000 --- a/test/functional/eval/let_spec.lua +++ /dev/null @@ -1,93 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local clear = helpers.clear -local command = helpers.command -local eval = helpers.eval -local meths = helpers.meths -local redir_exec = helpers.redir_exec -local source = helpers.source -local nvim_dir = helpers.nvim_dir - -before_each(clear) - -describe(':let', function() - it('correctly lists variables with curly-braces', function() - meths.set_var('v', {0}) - eq('\nv [0]', redir_exec('let {"v"}')) - end) - - it('correctly lists variables with subscript', function() - meths.set_var('v', {0}) - eq('\nv[0] #0', redir_exec('let v[0]')) - eq('\ng:["v"][0] #0', redir_exec('let g:["v"][0]')) - eq('\n{"g:"}["v"][0] #0', redir_exec('let {"g:"}["v"][0]')) - end) - - it(":unlet self-referencing node in a List graph #6070", function() - -- :unlet-ing a self-referencing List must not allow GC on indirectly - -- referenced in-scope Lists. Before #6070 this caused use-after-free. - source([=[ - let [l1, l2] = [[], []] - echo 'l1:' . id(l1) - echo 'l2:' . id(l2) - echo '' - let [l3, l4] = [[], []] - call add(l4, l4) - call add(l4, l3) - call add(l3, 1) - call add(l2, l2) - call add(l2, l1) - call add(l1, 1) - unlet l2 - unlet l4 - call garbagecollect(1) - call feedkeys(":\e:echo l1 l3\n:echo 42\n:cq\n", "t") - ]=]) - end) - - it("multibyte env var #8398 #9267", function() - command("let $NVIM_TEST = 'AìaB'") - eq('AìaB', eval('$NVIM_TEST')) - command("let $NVIM_TEST = 'AaあB'") - eq('AaあB', eval('$NVIM_TEST')) - local mbyte = [[\p* .ม .ม .ม .ม่ .ม่ .ม่ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ ֹֻ - .ֹֻ .ֹֻ .ֹֻ ֹֻ ֹֻ ֹֻ .ֹֻ .ֹֻ .ֹֻ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ - .ֹֻ .ֹֻ .ֹֻ a a a ca ca ca à à à]] - command("let $NVIM_TEST = '"..mbyte.."'") - eq(mbyte, eval('$NVIM_TEST')) - end) - - it("multibyte env var to child process #8398 #9267", function() - local cmd_get_child_env = "let g:env_from_child = system(['"..nvim_dir.."/printenv-test', 'NVIM_TEST'])" - command("let $NVIM_TEST = 'AìaB'") - command(cmd_get_child_env) - eq(eval('$NVIM_TEST'), eval('g:env_from_child')) - - command("let $NVIM_TEST = 'AaあB'") - command(cmd_get_child_env) - eq(eval('$NVIM_TEST'), eval('g:env_from_child')) - - local mbyte = [[\p* .ม .ม .ม .ม่ .ม่ .ม่ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ ֹֻ - .ֹֻ .ֹֻ .ֹֻ ֹֻ ֹֻ ֹֻ .ֹֻ .ֹֻ .ֹֻ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ - .ֹֻ .ֹֻ .ֹֻ a a a ca ca ca à à à]] - command("let $NVIM_TEST = '"..mbyte.."'") - command(cmd_get_child_env) - eq(eval('$NVIM_TEST'), eval('g:env_from_child')) - end) - - it("release of list assigned to l: variable does not trigger assertion #12387, #12430", function() - source([[ - func! s:f() - let l:x = [1] - let g:x = l: - endfunc - for _ in range(2) - call s:f() - endfor - call garbagecollect() - call feedkeys('i', 't') - ]]) - eq(1, eval('1')) - end) -end) diff --git a/test/functional/eval/map_functions_spec.lua b/test/functional/eval/map_functions_spec.lua deleted file mode 100644 index 275c72d212..0000000000 --- a/test/functional/eval/map_functions_spec.lua +++ /dev/null @@ -1,163 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local eq = helpers.eq -local eval = helpers.eval -local funcs = helpers.funcs -local nvim = helpers.nvim -local source = helpers.source -local command = helpers.command - -describe('maparg()', function() - before_each(clear) - - local foo_bar_map_table = { - lhs='foo', - script=0, - silent=0, - rhs='bar', - expr=0, - sid=0, - buffer=0, - nowait=0, - mode='n', - noremap=1, - lnum=0, - } - - it('returns a dictionary', function() - nvim('command', 'nnoremap foo bar') - eq('bar', funcs.maparg('foo')) - eq(foo_bar_map_table, funcs.maparg('foo', 'n', false, true)) - end) - - it('returns 1 for silent when <silent> is used', function() - nvim('command', 'nnoremap <silent> foo bar') - eq(1, funcs.maparg('foo', 'n', false, true)['silent']) - - nvim('command', 'nnoremap baz bat') - eq(0, funcs.maparg('baz', 'n', false, true)['silent']) - end) - - it('returns an empty string when no map is present', function() - eq('', funcs.maparg('not a mapping')) - end) - - it('returns an empty dictionary when no map is present and dict is requested', function() - eq({}, funcs.maparg('not a mapping', 'n', false, true)) - end) - - it('returns the same value for noremap and <script>', function() - nvim('command', 'inoremap <script> hello world') - nvim('command', 'inoremap this that') - eq( - funcs.maparg('hello', 'i', false, true)['noremap'], - funcs.maparg('this', 'i', false, true)['noremap'] - ) - end) - - it('returns a boolean for buffer', function() - -- Open enough windows to know we aren't on buffer number 1 - nvim('command', 'new') - nvim('command', 'new') - nvim('command', 'new') - nvim('command', 'cnoremap <buffer> this that') - eq(1, funcs.maparg('this', 'c', false, true)['buffer']) - - -- Global will return 0 always - nvim('command', 'nnoremap other another') - eq(0, funcs.maparg('other', 'n', false, true)['buffer']) - end) - - it('returns script numbers', function() - source([[ - function! s:maparg_test_function() abort - return 'testing' - endfunction - - nnoremap fizz :call <SID>maparg_test_function()<CR> - ]]) - eq(1, funcs.maparg('fizz', 'n', false, true)['sid']) - eq('testing', nvim('call_function', '<SNR>1_maparg_test_function', {})) - end) - - it('works with <F12> and others', function() - source([[ - let g:maparg_test_var = 0 - - nnoremap <F12> :let g:maparg_test_var = 1<CR> - ]]) - eq(0, eval('g:maparg_test_var')) - source([[ - call feedkeys("\<F12>") - ]]) - eq(1, eval('g:maparg_test_var')) - - eq(':let g:maparg_test_var = 1<CR>', funcs.maparg('<F12>', 'n', false, true)['rhs']) - end) - - it('works with <expr>', function() - source([[ - let counter = 0 - inoremap <expr> <C-L> ListItem() - inoremap <expr> <C-R> ListReset() - - func ListItem() - let g:counter += 1 - return g:counter . '. ' - endfunc - - func ListReset() - let g:counter = 0 - return '' - endfunc - - call feedkeys("i\<C-L>") - ]]) - eq(1, eval('g:counter')) - - local map_dict = funcs.maparg('<C-L>', 'i', false, true) - eq(1, map_dict['expr']) - eq('i', map_dict['mode']) - end) - - it('works with combining characters', function() - -- Using addacutes to make combining character better visible - local function ac(s) - local acute = '\204\129' -- U+0301 COMBINING ACUTE ACCENT - local ret = s:gsub('`', acute) - return ret - end - command(ac([[ - nnoremap a b` - nnoremap c` d - nnoremap e` f` - ]])) - eq(ac('b`'), funcs.maparg(ac('a'))) - eq(ac(''), funcs.maparg(ac('c'))) - eq(ac('d'), funcs.maparg(ac('c`'))) - eq(ac('f`'), funcs.maparg(ac('e`'))) - - local function acmap(lhs, rhs) - return { - lhs = ac(lhs), - rhs = ac(rhs), - - buffer = 0, - expr = 0, - mode = 'n', - noremap = 1, - nowait = 0, - script=0, - sid = 0, - silent = 0, - lnum = 0, - } - end - - eq({}, funcs.maparg(ac('c'), 'n', 0, 1)) - eq(acmap('a', 'b`'), funcs.maparg(ac('a'), 'n', 0, 1)) - eq(acmap('c`', 'd'), funcs.maparg(ac('c`'), 'n', 0, 1)) - eq(acmap('e`', 'f`'), funcs.maparg(ac('e`'), 'n', 0, 1)) - end) -end) diff --git a/test/functional/eval/match_functions_spec.lua b/test/functional/eval/match_functions_spec.lua deleted file mode 100644 index 9f168c913a..0000000000 --- a/test/functional/eval/match_functions_spec.lua +++ /dev/null @@ -1,157 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local eq = helpers.eq -local clear = helpers.clear -local funcs = helpers.funcs -local command = helpers.command -local exc_exec = helpers.exc_exec - -before_each(clear) - -describe('setmatches()', function() - it('correctly handles case when both group and pattern entries are numbers', - function() - command('hi def link 1 PreProc') - eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}})) - eq({{ - group='1', - pattern='2', - id=3, - priority=4, - }}, funcs.getmatches()) - eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4, conceal=5}})) - eq({{ - group='1', - pattern='2', - id=3, - priority=4, - conceal='5', - }}, funcs.getmatches()) - eq(0, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}})) - eq({{ - group='1', - pos1={2}, - pos2={6}, - id=3, - priority=4, - conceal='5', - }}, funcs.getmatches()) - end) - - it('does not fail if highlight group is not defined', function() - eq(0, funcs.setmatches{{group=1, pattern=2, id=3, priority=4}}) - eq({{group='1', pattern='2', id=3, priority=4}}, - funcs.getmatches()) - eq(0, funcs.setmatches{{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}) - eq({{group='1', pos1={2}, pos2={6}, id=3, priority=4, conceal='5'}}, - funcs.getmatches()) - end) -end) - -describe('matchadd()', function() - it('correctly works when first two arguments and conceal are numbers at once', - function() - command('hi def link 1 PreProc') - eq(4, funcs.matchadd(1, 2, 3, 4, {conceal=5})) - eq({{ - group='1', - pattern='2', - priority=3, - id=4, - conceal='5', - }}, funcs.getmatches()) - end) -end) - -describe('matchaddpos()', function() - it('errors out on invalid input', function() - command('hi clear PreProc') - eq('Vim(let):E5030: Empty list at position 0', - exc_exec('let val = matchaddpos("PreProc", [[]])')) - eq('Vim(let):E5030: Empty list at position 1', - exc_exec('let val = matchaddpos("PreProc", [1, v:_null_list])')) - eq('Vim(let):E5031: List or number required at position 1', - exc_exec('let val = matchaddpos("PreProc", [1, v:_null_dict])')) - end) - it('works with 0 lnum', function() - command('hi clear PreProc') - eq(4, funcs.matchaddpos('PreProc', {1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - funcs.matchdelete(4) - eq(4, funcs.matchaddpos('PreProc', {{0}, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - funcs.matchdelete(4) - eq(4, funcs.matchaddpos('PreProc', {0, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - end) - it('works with negative numbers', function() - command('hi clear PreProc') - eq(4, funcs.matchaddpos('PreProc', {-10, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - funcs.matchdelete(4) - eq(4, funcs.matchaddpos('PreProc', {{-10}, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - funcs.matchdelete(4) - eq(4, funcs.matchaddpos('PreProc', {{2, -1}, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - funcs.matchdelete(4) - eq(4, funcs.matchaddpos('PreProc', {{2, 0, -1}, 1}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1}, - priority=3, - id=4, - }}, funcs.getmatches()) - end) - it('works with zero length', function() - local screen = Screen.new(40, 5) - screen:attach() - funcs.setline(1, 'abcdef') - command('hi PreProc guifg=Red') - eq(4, funcs.matchaddpos('PreProc', {{1, 2, 0}}, 3, 4)) - eq({{ - group='PreProc', - pos1 = {1, 2, 0}, - priority=3, - id=4, - }}, funcs.getmatches()) - screen:expect([[ - ^a{1:b}cdef | - {2:~ }| - {2:~ }| - {2:~ }| - | - ]], {[1] = {foreground = Screen.colors.Red}, [2] = {bold = true, foreground = Screen.colors.Blue1}}) - end) -end) diff --git a/test/functional/eval/minmax_functions_spec.lua b/test/functional/eval/minmax_functions_spec.lua deleted file mode 100644 index c6eb754f91..0000000000 --- a/test/functional/eval/minmax_functions_spec.lua +++ /dev/null @@ -1,51 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local eval = helpers.eval -local clear = helpers.clear -local funcs = helpers.funcs -local redir_exec = helpers.redir_exec - -before_each(clear) -for _, func in ipairs({'min', 'max'}) do - describe(func .. '()', function() - it('gives a single error message when multiple values failed conversions', - function() - eq('\nE745: Using a List as a Number\n0', - redir_exec('echo ' .. func .. '([-5, [], [], [], 5])')) - eq('\nE745: Using a List as a Number\n0', - redir_exec('echo ' .. func .. '({1:-5, 2:[], 3:[], 4:[], 5:5})')) - for errmsg, errinput in pairs({ - ['E745: Using a List as a Number'] = '[]', - ['E805: Using a Float as a Number'] = '0.0', - ['E703: Using a Funcref as a Number'] = 'function("tr")', - ['E728: Using a Dictionary as a Number'] = '{}', - }) do - eq('\n' .. errmsg .. '\n0', - redir_exec('echo ' .. func .. '([' .. errinput .. '])')) - eq('\n' .. errmsg .. '\n0', - redir_exec('echo ' .. func .. '({1:' .. errinput .. '})')) - end - end) - it('works with arrays/dictionaries with zero items', function() - eq(0, funcs[func]({})) - eq(0, eval(func .. '({})')) - end) - it('works with arrays/dictionaries with one item', function() - eq(5, funcs[func]({5})) - eq(5, funcs[func]({test=5})) - end) - it('works with NULL arrays/dictionaries', function() - eq(0, eval(func .. '(v:_null_list)')) - eq(0, eval(func .. '(v:_null_dict)')) - end) - it('errors out for invalid types', function() - for _, errinput in ipairs({'1', 'v:true', 'v:false', 'v:null', - 'function("tr")', '""'}) do - eq(('\nE712: Argument of %s() must be a List or Dictionary\n0'):format( - func), - redir_exec('echo ' .. func .. '(' .. errinput .. ')')) - end - end) - end) -end diff --git a/test/functional/eval/modeline_spec.lua b/test/functional/eval/modeline_spec.lua deleted file mode 100644 index b2346079a1..0000000000 --- a/test/functional/eval/modeline_spec.lua +++ /dev/null @@ -1,19 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local assert_alive = helpers.assert_alive -local clear, command, write_file = helpers.clear, helpers.command, helpers.write_file - -describe("modeline", function() - local tempfile = helpers.tmpname() - before_each(clear) - - after_each(function() - os.remove(tempfile) - end) - - it('does not crash with a large version number', function() - write_file(tempfile, 'vim100000000000000000000000') - command('e! ' .. tempfile) - - assert_alive() - end) -end) diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua deleted file mode 100644 index 837b629858..0000000000 --- a/test/functional/eval/msgpack_functions_spec.lua +++ /dev/null @@ -1,755 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local funcs = helpers.funcs -local eval, eq = helpers.eval, helpers.eq -local command = helpers.command -local nvim = helpers.nvim -local exc_exec = helpers.exc_exec - -describe('msgpack*() functions', function() - before_each(clear) - - local obj_test = function(msg, obj) - it(msg, function() - nvim('set_var', 'obj', obj) - eq(obj, eval('msgpackparse(msgpackdump(g:obj))')) - eq(obj, eval('msgpackparse(msgpackdump(g:obj, "B"))')) - end) - end - - -- Regression test: msgpack_list_write was failing to write buffer with zero - -- length. - obj_test('are able to dump and restore {"file": ""}', {{file=''}}) - -- Regression test: msgpack_list_write was failing to write buffer with NL at - -- the end. - obj_test('are able to dump and restore {0, "echo mpack"}', {{0, 'echo mpack'}}) - obj_test('are able to dump and restore "Test\\n"', {'Test\n'}) - -- Regression test: msgpack_list_write was failing to write buffer with NL - -- inside. - obj_test('are able to dump and restore "Test\\nTest 2"', {'Test\nTest 2'}) - -- Test that big objects (requirement: dump to something that is bigger then - -- IOSIZE) are also fine. This particular object is obtained by concatenating - -- 5 identical shada files. - local big_obj = { - 1, 1436711454, 78, { - encoding="utf-8", - max_kbyte=10, - pid=19269, - version="NVIM 0.0.0-alpha+201507121634" - }, - 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 8, 1436711391, 8, { file="" }, - 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" }, - 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" }, - 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" }, - 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" }, - 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" }, - 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" }, - 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" }, - 4, 1436708101, 25, { 0, "echo msgpackdump([1])" }, - 4, 1436708966, 6, { 0, "cq" }, - 4, 1436709606, 25, { 0, "echo msgpackdump([5])" }, - 4, 1436709610, 26, { 0, "echo msgpackdump([10])" }, - 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" }, - 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" }, - 4, 1436709634, 57, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])" - }, - 4, 1436709651, 67, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])" - }, - 4, 1436709660, 70, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])" - }, - 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" }, - 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" }, - 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" }, - 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" }, - 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" }, - 4, 1436711142, 14, { 0, "echo mpack" }, - 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" }, - 4, 1436711206, 16, { 0, "echo lengths" }, - 4, 1436711244, 92, { - 0, - ("let sum = len(lengths) - 1 | call map(copy(lengths), " - .. "'extend(g:, {\"sum\": sum + v:val})')") - }, - 4, 1436711245, 12, { 0, "echo sum" }, - 4, 1436711398, 10, { 0, "echo s" }, - 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" }, - 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" }, - 4, 1436711415, 22, { 0, "echo shada_objects" }, - 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" }, - 4, 1436711454, 6, { 0, "qa" }, - 4, 1436711442, 9, { 1, "test", 47 }, - 4, 1436711443, 15, { 1, "aontsuesan", 47 }, - 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 }, - 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 }, - 3, 0, 3, { "" }, - 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 1, 1436711454, 78, { - encoding="utf-8", - max_kbyte=10, - pid=19269, - version="NVIM 0.0.0-alpha+201507121634" - }, - 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 8, 1436711391, 8, { file="" }, - 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" }, - 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" }, - 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" }, - 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" }, - 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" }, - 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" }, - 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" }, - 4, 1436708101, 25, { 0, "echo msgpackdump([1])" }, - 4, 1436708966, 6, { 0, "cq" }, - 4, 1436709606, 25, { 0, "echo msgpackdump([5])" }, - 4, 1436709610, 26, { 0, "echo msgpackdump([10])" }, - 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" }, - 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" }, - 4, 1436709634, 57, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])" - }, - 4, 1436709651, 67, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])" - }, - 4, 1436709660, 70, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])" - }, - 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" }, - 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" }, - 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" }, - 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" }, - 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" }, - 4, 1436711142, 14, { 0, "echo mpack" }, - 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" }, - 4, 1436711206, 16, { 0, "echo lengths" }, - 4, 1436711244, 92, { - 0, - ("let sum = len(lengths) - 1 | call map(copy(lengths), " - .. "'extend(g:, {\"sum\": sum + v:val})')") - }, - 4, 1436711245, 12, { 0, "echo sum" }, - 4, 1436711398, 10, { 0, "echo s" }, - 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" }, - 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" }, - 4, 1436711415, 22, { 0, "echo shada_objects" }, - 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" }, - 4, 1436711454, 6, { 0, "qa" }, - 4, 1436711442, 9, { 1, "test", 47 }, - 4, 1436711443, 15, { 1, "aontsuesan", 47 }, - 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 }, - 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 }, - 3, 0, 3, { "" }, - 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 1, 1436711454, 78, { - encoding="utf-8", - max_kbyte=10, - pid=19269, - version="NVIM 0.0.0-alpha+201507121634" - }, - 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 8, 1436711391, 8, { file="" }, - 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" }, - 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" }, - 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" }, - 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" }, - 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" }, - 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" }, - 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" }, - 4, 1436708101, 25, { 0, "echo msgpackdump([1])" }, - 4, 1436708966, 6, { 0, "cq" }, - 4, 1436709606, 25, { 0, "echo msgpackdump([5])" }, - 4, 1436709610, 26, { 0, "echo msgpackdump([10])" }, - 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" }, - 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" }, - 4, 1436709634, 57, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])" - }, - 4, 1436709651, 67, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])" - }, - 4, 1436709660, 70, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])" - }, - 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" }, - 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" }, - 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" }, - 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" }, - 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" }, - 4, 1436711142, 14, { 0, "echo mpack" }, - 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" }, - 4, 1436711206, 16, { 0, "echo lengths" }, - 4, 1436711244, 92, { - 0, - ("let sum = len(lengths) - 1 | call map(copy(lengths), " - .. "'extend(g:, {\"sum\": sum + v:val})')") - }, - 4, 1436711245, 12, { 0, "echo sum" }, - 4, 1436711398, 10, { 0, "echo s" }, - 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" }, - 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" }, - 4, 1436711415, 22, { 0, "echo shada_objects" }, - 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" }, - 4, 1436711454, 6, { 0, "qa" }, - 4, 1436711442, 9, { 1, "test", 47 }, - 4, 1436711443, 15, { 1, "aontsuesan", 47 }, - 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 }, - 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 }, - 3, 0, 3, { "" }, - 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 1, 1436711454, 78, { - encoding="utf-8", - max_kbyte=10, - pid=19269, - version="NVIM 0.0.0-alpha+201507121634" - }, - 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 8, 1436711391, 8, { file="" }, - 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" }, - 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" }, - 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" }, - 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" }, - 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" }, - 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" }, - 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" }, - 4, 1436708101, 25, { 0, "echo msgpackdump([1])" }, - 4, 1436708966, 6, { 0, "cq" }, - 4, 1436709606, 25, { 0, "echo msgpackdump([5])" }, - 4, 1436709610, 26, { 0, "echo msgpackdump([10])" }, - 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" }, - 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" }, - 4, 1436709634, 57, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])" - }, - 4, 1436709651, 67, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])" - }, - 4, 1436709660, 70, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])" - }, - 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" }, - 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" }, - 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" }, - 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" }, - 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" }, - 4, 1436711142, 14, { 0, "echo mpack" }, - 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" }, - 4, 1436711206, 16, { 0, "echo lengths" }, - 4, 1436711244, 92, { - 0, - ("let sum = len(lengths) - 1 | call map(copy(lengths), " - .. "'extend(g:, {\"sum\": sum + v:val})')") - }, - 4, 1436711245, 12, { 0, "echo sum" }, - 4, 1436711398, 10, { 0, "echo s" }, - 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" }, - 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" }, - 4, 1436711415, 22, { 0, "echo shada_objects" }, - 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" }, - 4, 1436711454, 6, { 0, "qa" }, - 4, 1436711442, 9, { 1, "test", 47 }, - 4, 1436711443, 15, { 1, "aontsuesan", 47 }, - 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 }, - 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 }, - 3, 0, 3, { "" }, - 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 1, 1436711454, 78, { - encoding="utf-8", - max_kbyte=10, - pid=19269, - version="NVIM 0.0.0-alpha+201507121634" - }, - 8, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" }, - 8, 1436711391, 8, { file="" }, - 4, 1436700940, 30, { 0, "call mkdir('/tmp/tty/tty')" }, - 4, 1436701355, 35, { 0, "call mkdir('/tmp/tty/tty', 'p')" }, - 4, 1436701368, 24, { 0, "call mkdir('/', 'p')" }, - 4, 1436701375, 26, { 0, "call mkdir('/tty/tty')" }, - 4, 1436701383, 30, { 0, "call mkdir('/tty/tty/tty')" }, - 4, 1436701407, 35, { 0, "call mkdir('/usr/tty/tty', 'p')" }, - 4, 1436701666, 35, { 0, "call mkdir('/tty/tty/tty', 'p')" }, - 4, 1436708101, 25, { 0, "echo msgpackdump([1])" }, - 4, 1436708966, 6, { 0, "cq" }, - 4, 1436709606, 25, { 0, "echo msgpackdump([5])" }, - 4, 1436709610, 26, { 0, "echo msgpackdump([10])" }, - 4, 1436709615, 31, { 0, "echo msgpackdump([5, 5, 5])" }, - 4, 1436709618, 35, { 0, "echo msgpackdump([5, 5, 5, 10])" }, - 4, 1436709634, 57, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1}]])" - }, - 4, 1436709651, 67, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}]])" - }, - 4, 1436709660, 70, { - 0, - "echo msgpackdump([5, 5, 5, 10, [10, 20, {\"abc\": 1, \"def\": 0}], 0])" - }, - 4, 1436710095, 29, { 0, "echo msgpackparse([\"\\n\"])" }, - 4, 1436710100, 28, { 0, "echo msgpackparse([\"j\"])" }, - 4, 1436710109, 31, { 0, "echo msgpackparse([\"\", \"\"])" }, - 4, 1436710424, 33, { 0, "echo msgpackparse([\"\", \"\\n\"])" }, - 4, 1436710428, 32, { 0, "echo msgpackparse([\"\", \"j\"])" }, - 4, 1436711142, 14, { 0, "echo mpack" }, - 4, 1436711196, 45, { 0, "let lengths = map(mpack[:], 'len(v:val)')" }, - 4, 1436711206, 16, { 0, "echo lengths" }, - 4, 1436711244, 92, { - 0, - ("let sum = len(lengths) - 1 | call map(copy(lengths), " - .. "'extend(g:, {\"sum\": sum + v:val})')") - }, - 4, 1436711245, 12, { 0, "echo sum" }, - 4, 1436711398, 10, { 0, "echo s" }, - 4, 1436711404, 41, { 0, "let mpack = readfile('/tmp/foo', 'b')" }, - 4, 1436711408, 41, { 0, "let shada_objects=msgpackparse(mpack)" }, - 4, 1436711415, 22, { 0, "echo shada_objects" }, - 4, 1436711451, 30, { 0, "e ~/.nvim/shada/main.shada" }, - 4, 1436711454, 6, { 0, "qa" }, - 4, 1436711442, 9, { 1, "test", 47 }, - 4, 1436711443, 15, { 1, "aontsuesan", 47 }, - 2, 1436711443, 38, { hlsearch=1, pat="aontsuesan", smartcase=1 }, - 2, 0, 31, { islast=0, pat="", smartcase=1, sub=1 }, - 3, 0, 3, { "" }, - 10, 1436711451, 40, { file="/home/zyx/.nvim/shada/main.shada" } - } - obj_test('are able to dump and restore rather big object', big_obj) - - obj_test('are able to dump and restore floating-point value', {0.125}) - - it('can restore and dump UINT64_MAX', function() - command('let dumped = ["\\xCF" . repeat("\\xFF", 8)]') - command('let parsed = msgpackparse(dumped)') - command('let dumped2 = msgpackdump(parsed)') - eq(1, eval('type(parsed[0]) == type(0) ' .. - '|| parsed[0]._TYPE is v:msgpack_types.integer')) - if eval('type(parsed[0]) == type(0)') == 1 then - command('call assert_equal(0xFFFFFFFFFFFFFFFF, parsed[0])') - eq({}, eval('v:errors')) - else - eq({_TYPE={}, _VAL={1, 3, 0x7FFFFFFF, 0x7FFFFFFF}}, eval('parsed[0]')) - end - eq(1, eval('dumped ==# dumped2')) - end) - - it('can restore and dump INT64_MIN', function() - command('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]') - command('let parsed = msgpackparse(dumped)') - command('let dumped2 = msgpackdump(parsed)') - eq(1, eval('type(parsed[0]) == type(0) ' .. - '|| parsed[0]._TYPE is v:msgpack_types.integer')) - if eval('type(parsed[0]) == type(0)') == 1 then - command('call assert_equal(-0x7fffffffffffffff - 1, parsed[0])') - eq({}, eval('v:errors')) - else - eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]')) - end - eq(1, eval('dumped ==# dumped2')) - end) - - it('can restore and dump BIN string with zero byte', function() - command('let dumped = ["\\xC4\\x01\\n"]') - command('let parsed = msgpackparse(dumped)') - command('let dumped2 = msgpackdump(parsed)') - eq({'\000'}, eval('parsed')) - eq(1, eval('dumped ==# dumped2')) - end) - - it('can restore and dump STR string with zero byte', function() - command('let dumped = ["\\xA1\\n"]') - command('let parsed = msgpackparse(dumped)') - command('let dumped2 = msgpackdump(parsed)') - eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed')) - eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string')) - eq(1, eval('dumped ==# dumped2')) - end) - - it('can restore and dump BIN string with NL', function() - command('let dumped = ["\\xC4\\x01", ""]') - command('let parsed = msgpackparse(dumped)') - command('let dumped2 = msgpackdump(parsed)') - eq({"\n"}, eval('parsed')) - eq(1, eval('dumped ==# dumped2')) - end) - - it('dump and restore special mapping with floating-point value', function() - command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}') - eq({0.125}, eval('msgpackparse(msgpackdump([todump]))')) - end) -end) - -local blobstr = function(list) - local l = {} - for i,v in ipairs(list) do - l[i] = v:gsub('\n', '\000') - end - return table.concat(l, '\n') -end - --- Test msgpackparse() with a readfile()-style list and a blob argument -local parse_eq = function(expect, list_arg) - local blob_expr = '0z' .. blobstr(list_arg):gsub('(.)', function(c) - return ('%.2x'):format(c:byte()) - end) - eq(expect, funcs.msgpackparse(list_arg)) - command('let g:parsed = msgpackparse(' .. blob_expr .. ')') - eq(expect, eval('g:parsed')) -end - -describe('msgpackparse() function', function() - before_each(clear) - - it('restores nil as v:null', function() - parse_eq(eval('[v:null]'), {'\192'}) - end) - - it('restores boolean false as v:false', function() - parse_eq({false}, {'\194'}) - end) - - it('restores boolean true as v:true', function() - parse_eq({true}, {'\195'}) - end) - - it('restores FIXSTR as special dict', function() - parse_eq({{_TYPE={}, _VAL={'ab'}}}, {'\162ab'}) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string')) - end) - - it('restores BIN 8 as string', function() - parse_eq({'ab'}, {'\196\002ab'}) - end) - - it('restores FIXEXT1 as special dictionary', function() - parse_eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, {'\212\016', ''}) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext')) - end) - - it('restores MAP with BIN key as special dictionary', function() - parse_eq({{_TYPE={}, _VAL={{'a', ''}}}}, {'\129\196\001a\196\n'}) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) - end) - - it('restores MAP with duplicate STR keys as special dictionary', function() - command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]') - -- FIXME Internal error bug, can't use parse_eq() here - command('silent! let parsed = msgpackparse(dumped)') - eq({{_TYPE={}, _VAL={ {{_TYPE={}, _VAL={'a'}}, ''}, - {{_TYPE={}, _VAL={'a'}}, ''}}} }, eval('parsed')) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) - eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string')) - eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string')) - end) - - it('restores MAP with MAP key as special dictionary', function() - parse_eq({{_TYPE={}, _VAL={{{}, ''}}}}, {'\129\128\196\n'}) - eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map')) - end) - - it('msgpackparse(systemlist(...)) does not segfault. #3135', function() - local cmd = "sort(keys(msgpackparse(systemlist('" - ..helpers.nvim_prog.." --api-info'))[0]))" - eval(cmd) - eval(cmd) -- do it again (try to force segfault) - local api_info = eval(cmd) -- do it again - eq({'error_types', 'functions', 'types', - 'ui_events', 'ui_options', 'version'}, api_info) - end) - - it('fails when called with no arguments', function() - eq('Vim(call):E119: Not enough arguments for function: msgpackparse', - exc_exec('call msgpackparse()')) - end) - - it('fails when called with two arguments', function() - eq('Vim(call):E118: Too many arguments for function: msgpackparse', - exc_exec('call msgpackparse(["", ""], 1)')) - end) - - it('fails to parse a string', function() - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse("abcdefghijklmnopqrstuvwxyz")')) - end) - - it('fails to parse a number', function() - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse(127)')) - end) - - it('fails to parse a dictionary', function() - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse({})')) - end) - - it('fails to parse a funcref', function() - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse(function("tr"))')) - end) - - it('fails to parse a partial', function() - command('function T() dict\nendfunction') - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse(function("T", [1, 2], {}))')) - end) - - it('fails to parse a float', function() - eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob', - exc_exec('call msgpackparse(0.0)')) - end) - - it('fails on incomplete msgpack string', function() - local expected = 'Vim(call):E475: Invalid argument: Incomplete msgpack string' - eq(expected, exc_exec([[call msgpackparse(["\xc4"])]])) - eq(expected, exc_exec([[call msgpackparse(["\xca", "\x02\x03"])]])) - eq(expected, exc_exec('call msgpackparse(0zc4)')) - eq(expected, exc_exec('call msgpackparse(0zca0a0203)')) - end) - - it('fails when unable to parse msgpack string', function() - local expected = 'Vim(call):E475: Invalid argument: Failed to parse msgpack string' - eq(expected, exc_exec([[call msgpackparse(["\xc1"])]])) - eq(expected, exc_exec('call msgpackparse(0zc1)')) - end) -end) - -describe('msgpackdump() function', function() - before_each(clear) - - local dump_eq = function(exp_list, arg_expr) - eq(exp_list, eval('msgpackdump(' .. arg_expr .. ')')) - eq(blobstr(exp_list), eval('msgpackdump(' .. arg_expr .. ', "B")')) - end - - it('dumps string as BIN 8', function() - dump_eq({'\196\004Test'}, '["Test"]') - end) - - it('dumps blob as BIN 8', function() - dump_eq({'\196\005Bl\nb!'}, '[0z426c006221]') - end) - - it('can dump generic mapping with generic mapping keys and values', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('call add(todump._VAL, [todumpv1, todumpv2])') - dump_eq({'\129\128\128'}, '[todump]') - end) - - it('can dump v:true', function() - dump_eq({'\195'}, '[v:true]') - end) - - it('can dump v:false', function() - dump_eq({'\194'}, '[v:false]') - end) - - it('can dump v:null', function() - dump_eq({'\192'}, '[v:null]') - end) - - it('can dump special bool mapping (true)', function() - command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}') - dump_eq({'\195'}, '[todump]') - end) - - it('can dump special bool mapping (false)', function() - command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}') - dump_eq({'\194'}, '[todump]') - end) - - it('can dump special nil mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}') - dump_eq({'\192'}, '[todump]') - end) - - it('can dump special ext mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') - dump_eq({'\212\005', ''}, '[todump]') - end) - - it('can dump special array mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') - dump_eq({'\146\005\145\196\n'}, '[todump]') - end) - - it('can dump special UINT64_MAX mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.integer}') - command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') - dump_eq({'\207\255\255\255\255\255\255\255\255'}, '[todump]') - end) - - it('can dump special INT64_MIN mapping', function() - command('let todump = {"_TYPE": v:msgpack_types.integer}') - command('let todump._VAL = [-1, 2, 0, 0]') - dump_eq({'\211\128\n\n\n\n\n\n\n'}, '[todump]') - end) - - it('fails to dump a function reference', function() - command('let Todump = function("tr")') - eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference', - exc_exec('call msgpackdump([Todump])')) - end) - - it('fails to dump a partial', function() - command('function T() dict\nendfunction') - command('let Todump = function("T", [1, 2], {})') - eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference', - exc_exec('call msgpackdump([Todump])')) - end) - - it('fails to dump a function reference in a list', function() - command('let todump = [function("tr")]') - eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive list', function() - command('let todump = [[[]]]') - command('call add(todump[0][0], todump)') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive dict', function() - command('let todump = {"d": {"d": {}}}') - command('call extend(todump.d.d, {"d": todump})') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'', - exc_exec('call msgpackdump([todump])')) - end) - - it('can dump dict with two same dicts inside', function() - command('let inter = {}') - command('let todump = {"a": inter, "b": inter}') - dump_eq({"\130\161a\128\161b\128"}, '[todump]') - end) - - it('can dump list with two same lists inside', function() - command('let inter = []') - command('let todump = [inter, inter]') - dump_eq({"\146\144\144"}, '[todump]') - end) - - it('fails to dump a recursive list in a special dict', function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') - command('call add(todump._VAL, todump)') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive (key) map in a special dict', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('call add(todump._VAL, [todump, 0])') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive (val) map in a special dict', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') - command('call add(todump._VAL, [0, todump])') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive (key) map in a special dict, _VAL reference', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}') - command('call add(todump._VAL[0][0], todump._VAL)') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive (val) map in a special dict, _VAL reference', function() - command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}') - command('call add(todump._VAL[0][1], todump._VAL)') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails to dump a recursive (val) special list in a special dict', - function() - command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') - command('call add(todump._VAL, [0, todump._VAL])') - eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1', - exc_exec('call msgpackdump([todump])')) - end) - - it('fails when called with no arguments', function() - eq('Vim(call):E119: Not enough arguments for function: msgpackdump', - exc_exec('call msgpackdump()')) - end) - - it('fails when called with three arguments', function() - eq('Vim(call):E118: Too many arguments for function: msgpackdump', - exc_exec('call msgpackdump(["", ""], 1, 2)')) - end) - - it('fails to dump a string', function() - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump("abcdefghijklmnopqrstuvwxyz")')) - end) - - it('fails to dump a number', function() - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump(127)')) - end) - - it('fails to dump a dictionary', function() - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump({})')) - end) - - it('fails to dump a funcref', function() - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump(function("tr"))')) - end) - - it('fails to dump a partial', function() - command('function T() dict\nendfunction') - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump(function("T", [1, 2], {}))')) - end) - - it('fails to dump a float', function() - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump(0.0)')) - end) - - it('fails to dump special value', function() - for _, val in ipairs({'v:true', 'v:false', 'v:null'}) do - eq('Vim(call):E686: Argument of msgpackdump() must be a List', - exc_exec('call msgpackdump(' .. val .. ')')) - end - end) - - it('can dump NULL string', function() - dump_eq({'\196\n'}, '[$XXX_UNEXISTENT_VAR_XXX]') - dump_eq({'\196\n'}, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') - dump_eq({'\160'}, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]') - end) - - it('can dump NULL blob', function() - eq({'\196\n'}, eval('msgpackdump([v:_null_blob])')) - end) - - it('can dump NULL list', function() - eq({'\144'}, eval('msgpackdump([v:_null_list])')) - end) - - it('can dump NULL dictionary', function() - eq({'\128'}, eval('msgpackdump([v:_null_dict])')) - end) -end) diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua deleted file mode 100644 index bc88e6c8b3..0000000000 --- a/test/functional/eval/null_spec.lua +++ /dev/null @@ -1,170 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local curbufmeths = helpers.curbufmeths -local redir_exec = helpers.redir_exec -local exc_exec = helpers.exc_exec -local command = helpers.command -local clear = helpers.clear -local meths = helpers.meths -local funcs = helpers.funcs -local eq = helpers.eq - -describe('NULL', function() - before_each(function() - clear() - command('let L = v:_null_list') - command('let D = v:_null_dict') - command('let S = v:_null_string') - command('let V = $XXX_NONEXISTENT_VAR_XXX') - end) - local tmpfname = 'Xtest-functional-viml-null' - after_each(function() - os.remove(tmpfname) - end) - local null_test = function(name, cmd, err) - it(name, function() - eq(err, exc_exec(cmd)) - end) - end - local null_expr_test = function(name, expr, err, val, after) - it(name, function() - eq((err == 0) and ('') or ('\n' .. err), - redir_exec('let g:_var = ' .. expr)) - if val == nil then - eq(0, funcs.exists('g:_var')) - else - eq(val, meths.get_var('_var')) - end - if after ~= nil then - after() - end - end) - end - describe('list', function() - -- Incorrect behaviour - -- FIXME Should error out with different message - null_test('makes :unlet act as if it is not a list', ':unlet L[0]', - 'Vim(unlet):E689: Can only index a List, Dictionary or Blob') - - -- Subjectable behaviour - - null_expr_test('is equal to empty list', 'L == []', 0, 1) - null_expr_test('is equal to empty list (reverse order)', '[] == L', 0, 1) - - -- Correct behaviour - null_expr_test('can be indexed with error message for empty list', 'L[0]', - 'E684: list index out of range: 0', nil) - null_expr_test('can be splice-indexed', 'L[:]', 0, {}) - null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0) - null_test('is accepted by :for', 'for x in L|throw x|endfor', 0) - null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function() - eq({''}, curbufmeths.get_lines(0, -1, false)) - end) - null_expr_test('does not crash setline()', 'setline(1, L)', 0, 0, function() - eq({''}, curbufmeths.get_lines(0, -1, false)) - end) - null_expr_test('is identical to itself', 'L is L', 0, 1) - null_expr_test('can be sliced', 'L[:]', 0, {}) - null_expr_test('can be copied', 'copy(L)', 0, {}) - null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {}) - null_expr_test('does not crash when indexed', 'L[1]', - 'E684: list index out of range: 1', nil) - null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0) - null_expr_test('does not crash col()', 'col(L)', 0, 0) - null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0) - null_expr_test('does not crash line()', 'line(L)', 0, 0) - null_expr_test('does not crash line() with window id', 'line(L, 1000)', 0, 0) - null_expr_test('does not crash count()', 'count(L, 1)', 0, 0) - null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1) - null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {}) - null_expr_test('does not crash filter()', 'filter(L, "1")', 0, {}) - null_expr_test('is empty', 'empty(L)', 0, 1) - null_expr_test('does not crash get()', 'get(L, 1, 10)', 0, 10) - null_expr_test('has zero length', 'len(L)', 0, 0) - null_expr_test('is accepted as an empty list by max()', 'max(L)', 0, 0) - null_expr_test('is accepted as an empty list by min()', 'min(L)', 0, 0) - null_expr_test('is stringified correctly', 'string(L)', 0, '[]') - null_expr_test('is JSON encoded correctly', 'json_encode(L)', 0, '[]') - null_test('does not crash lockvar', 'lockvar! L', 0) - null_expr_test('can be added to itself', '(L + L)', 0, {}) - null_expr_test('can be added to itself', '(L + L) is L', 0, 1) - null_expr_test('can be added to non-empty list', '([1] + L)', 0, {1}) - null_expr_test('can be added to non-empty list (reversed)', '(L + [1])', 0, {1}) - null_expr_test('is equal to itself', 'L == L', 0, 1) - null_expr_test('is not not equal to itself', 'L != L', 0, 0) - null_expr_test('counts correctly', 'count([L], L)', 0, 1) - null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 1) - null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1) - null_test('is treated by :let as empty list', ':let [l] = L', 'Vim(let):E688: More targets than List items') - null_expr_test('is accepted as an empty list by inputlist()', '[feedkeys("\\n"), inputlist(L)]', - 'Type number and <Enter> or click with the mouse (q or empty cancels): ', {0, 0}) - null_expr_test('is accepted as an empty list by writefile()', - ('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname), - 0, {0, {}}) - null_expr_test('makes add() error out', 'add(L, 0)', - 'E742: Cannot change value of add() argument', 1) - null_expr_test('makes insert() error out', 'insert(L, 1)', - 'E742: Cannot change value of insert() argument', 0) - null_expr_test('does not crash remove()', 'remove(L, 0)', - 'E742: Cannot change value of remove() argument', 0) - null_expr_test('makes reverse() error out', 'reverse(L)', - 'E742: Cannot change value of reverse() argument', 0) - null_expr_test('makes sort() error out', 'sort(L)', - 'E742: Cannot change value of sort() argument', 0) - null_expr_test('makes uniq() error out', 'uniq(L)', - 'E742: Cannot change value of uniq() argument', 0) - null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0) - null_expr_test('does not crash extend() (second position)', 'extend([1], L)', 0, {1}) - null_expr_test('makes join() return empty string', 'join(L, "")', 0, '') - null_expr_test('makes msgpackdump() return empty list', 'msgpackdump(L)', 0, {}) - null_expr_test('does not crash system()', 'system("cat", L)', 0, '') - null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0) - null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {}) - null_test('does not make Neovim crash when v:oldfiles gets assigned to that', ':let v:oldfiles = L|oldfiles', 0) - null_expr_test('does not make complete() crash or error out', - 'execute(":normal i\\<C-r>=complete(1, L)[-1]\\n")', - '', '\n', function() - eq({''}, curbufmeths.get_lines(0, -1, false)) - end) - null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, 0) - null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, 0) - null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0) - null_test('is accepted by :cexpr', 'cexpr L', 0) - null_test('is accepted by :lexpr', 'lexpr L', 0) - null_expr_test('does not crash execute()', 'execute(L)', 0, '') - end) - describe('dict', function() - it('does not crash when indexing NULL dict', function() - eq('\nE716: Key not present in Dictionary: "test"', - redir_exec('echo v:_null_dict.test')) - end) - null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0) - null_expr_test('makes extend do nothing', 'extend({1: 2}, D)', 0, {['1']=2}) - null_expr_test('does not crash map()', 'map(D, "v:val")', 0, {}) - null_expr_test('does not crash filter()', 'filter(D, "1")', 0, {}) - null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1) - null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1) - end) - describe('string', function() - null_test('does not crash :echomsg', 'echomsg S', 0) - null_test('does not crash :execute', 'execute S', 0) - null_expr_test('does not crash execute()', 'execute(S)', 0, '') - null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0) - null_expr_test('makes timer_start() error out', 'timer_start(0, S)', 'E921: Invalid callback argument', -1) - null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0) - null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0) - null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '') - null_expr_test('does not crash getfperm()', 'getfperm(S)', 0, '') - null_expr_test('does not crash getfsize()', 'getfsize(S)', 0, -1) - null_expr_test('does not crash getftime()', 'getftime(S)', 0, -1) - null_expr_test('does not crash getftype()', 'getftype(S)', 0, '') - null_expr_test('does not crash glob()', 'glob(S)', 0, '') - null_expr_test('does not crash globpath()', 'globpath(S, S)', 0, '') - null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0) - null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'}) - null_expr_test('does not crash split()', 'split(S)', 0, {}) - null_test('can be used to set an option', 'let &grepprg = S', 0) - - null_expr_test('is equal to non-existent variable', 'S == V', 0, 1) - end) -end) diff --git a/test/functional/eval/operators_spec.lua b/test/functional/eval/operators_spec.lua deleted file mode 100644 index 4d07bc1b05..0000000000 --- a/test/functional/eval/operators_spec.lua +++ /dev/null @@ -1,28 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local eval = helpers.eval -local clear = helpers.clear - -describe('Division operator', function() - before_each(clear) - - it('returns infinity on {positive}/0.0', function() - eq('str2float(\'inf\')', eval('string(1.0/0.0)')) - eq('str2float(\'inf\')', eval('string(1.0e-100/0.0)')) - eq('str2float(\'inf\')', eval('string(1.0e+100/0.0)')) - eq('str2float(\'inf\')', eval('string((1.0/0.0)/0.0)')) - end) - - it('returns -infinity on {negative}/0.0', function() - eq('-str2float(\'inf\')', eval('string((-1.0)/0.0)')) - eq('-str2float(\'inf\')', eval('string((-1.0e-100)/0.0)')) - eq('-str2float(\'inf\')', eval('string((-1.0e+100)/0.0)')) - eq('-str2float(\'inf\')', eval('string((-1.0/0.0)/0.0)')) - end) - - it('returns NaN on 0.0/0.0', function() - eq('str2float(\'nan\')', eval('string(0.0/0.0)')) - eq('str2float(\'nan\')', eval('string(-(0.0/0.0))')) - eq('str2float(\'nan\')', eval('string((-0.0)/0.0)')) - end) -end) diff --git a/test/functional/eval/printf_spec.lua b/test/functional/eval/printf_spec.lua deleted file mode 100644 index 27e24c4118..0000000000 --- a/test/functional/eval/printf_spec.lua +++ /dev/null @@ -1,92 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local eq = helpers.eq -local eval = helpers.eval -local funcs = helpers.funcs -local meths = helpers.meths -local exc_exec = helpers.exc_exec - -describe('printf()', function() - before_each(clear) - - it('works with zero and %b', function() - eq('0', funcs.printf('%lb', 0)) - eq('0', funcs.printf('%llb', 0)) - eq('0', funcs.printf('%zb', 0)) - end) - it('works with one and %b', function() - eq('1', funcs.printf('%b', 1)) - eq('1', funcs.printf('%lb', 1)) - eq('1', funcs.printf('%llb', 1)) - eq('1', funcs.printf('%zb', 1)) - end) - it('works with 0xff and %b', function() - eq('11111111', funcs.printf('%b', 0xff)) - eq('11111111', funcs.printf('%lb', 0xff)) - eq('11111111', funcs.printf('%llb', 0xff)) - eq('11111111', funcs.printf('%zb', 0xff)) - end) - it('accepts width modifier with %b', function() - eq(' 1', funcs.printf('%3b', 1)) - end) - it('accepts prefix modifier with %b', function() - eq('0b1', funcs.printf('%#b', 1)) - end) - it('writes capital B with %B', function() - eq('0B1', funcs.printf('%#B', 1)) - end) - it('accepts prefix, zero-fill and width modifiers with %b', function() - eq('0b001', funcs.printf('%#05b', 1)) - end) - it('accepts prefix and width modifiers with %b', function() - eq(' 0b1', funcs.printf('%#5b', 1)) - end) - it('does not write prefix for zero with prefix and width modifier used with %b', function() - eq(' 0', funcs.printf('%#5b', 0)) - end) - it('accepts precision modifier with %b', function() - eq('00000', funcs.printf('%.5b', 0)) - end) - it('accepts all modifiers with %b at once', function() - -- zero-fill modifier is ignored when used with left-align - -- force-sign and add-blank are ignored - -- use-grouping-characters modifier is ignored always - eq('0b00011 ', funcs.printf('% \'+#0-10.5b', 3)) - end) - it('errors out when %b modifier is used for a list', function() - eq('Vim(call):E745: Using a List as a Number', exc_exec('call printf("%b", [])')) - end) - it('errors out when %b modifier is used for a float', function() - eq('Vim(call):E805: Using a Float as a Number', exc_exec('call printf("%b", 3.1415926535)')) - end) - it('works with %p correctly', function() - local null_ret = nil - local seen_rets = {} - -- Collect all args in an array to avoid possible allocation of the same - -- address after freeing unreferenced values. - meths.set_var('__args', {}) - local function check_printf(expr, is_null) - eq(0, exc_exec('call add(__args, ' .. expr .. ')')) - eq(0, exc_exec('let __result = printf("%p", __args[-1])')) - local id_ret = eval('id(__args[-1])') - eq(id_ret, meths.get_var('__result')) - if is_null then - if null_ret then - eq(null_ret, id_ret) - else - null_ret = id_ret - end - else - eq(nil, seen_rets[id_ret]) - seen_rets[id_ret] = expr - end - meths.del_var('__result') - end - check_printf('v:_null_list', true) - check_printf('v:_null_dict', true) - check_printf('[]') - check_printf('{}') - check_printf('function("tr", ["a"])') - end) -end) diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua deleted file mode 100644 index d87943e485..0000000000 --- a/test/functional/eval/reltime_spec.lua +++ /dev/null @@ -1,53 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok -local neq, command, funcs = helpers.neq, helpers.command, helpers.funcs -local reltime, reltimestr, reltimefloat = funcs.reltime, funcs.reltimestr, funcs.reltimefloat - -describe('reltimestr(), reltimefloat()', function() - before_each(clear) - - it('acceptance', function() - local now = reltime() - command('sleep 10m') - local later = reltime() - local elapsed = reltime(now) - - neq(reltimestr(elapsed), '0.0') - ok(reltimefloat(elapsed) > 0.0) - -- original vim test for < 0.1, but easily fails on travis - ok(nil ~= string.match(reltimestr(elapsed), "0%.")) - ok(reltimefloat(elapsed) < 1.0) - - local same = reltime(now, now) - local samestr = string.gsub(reltimestr(same), ' ', '') - samestr = string.sub(samestr, 1, 5) - - eq('0.000', samestr) - eq(0.0, reltimefloat(same)) - - local differs = reltime(now, later) - neq(reltimestr(differs), '0.0') - ok(reltimefloat(differs) > 0.0) - -- original vim test for < 0.1, but easily fails on travis - ok(nil ~= string.match(reltimestr(differs), "0%.")) - ok(reltimefloat(differs) < 1.0) - end) - - it('(start - end) returns negative #10452', function() - local older_time = reltime() - command('sleep 1m') - local newer_time = reltime() - - -- Start/end swapped: should be something like -0.002123. - local tm_s = tonumber(reltimestr(reltime(newer_time, older_time))) - local tm_f = reltimefloat(reltime(newer_time, older_time)) - ok(tm_s < 0 and tm_s > -10) - ok(tm_f < 0 and tm_f > -10) - - -- Not swapped: should be something like 0.002123. - tm_s = tonumber(reltimestr(reltime(older_time, newer_time))) - tm_f = reltimefloat(reltime(older_time, newer_time)) - ok(tm_s > 0 and tm_s < 10) - ok(tm_f > 0 and tm_f < 10) - end) -end) diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua deleted file mode 100644 index 238d1aeb0f..0000000000 --- a/test/functional/eval/server_spec.lua +++ /dev/null @@ -1,156 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval -local command = helpers.command -local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths -local iswin = helpers.iswin -local ok = helpers.ok -local matches = helpers.matches -local pcall_err = helpers.pcall_err - -local function clear_serverlist() - for _, server in pairs(funcs.serverlist()) do - funcs.serverstop(server) - end -end - -describe('server', function() - before_each(clear) - - it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function() - -- Unset $NVIM_LISTEN_ADDRESS - command('let $NVIM_LISTEN_ADDRESS = ""') - - local s = eval('serverstart()') - assert(s ~= nil and s:len() > 0, "serverstart() returned empty") - eq(s, eval('$NVIM_LISTEN_ADDRESS')) - eq(1, eval("serverstop('"..s.."')")) - eq('', eval('$NVIM_LISTEN_ADDRESS')) - end) - - it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function() - clear({env={NVIM_LISTEN_ADDRESS='.'}}) - eq('.', eval('$NVIM_LISTEN_ADDRESS')) - local servers = funcs.serverlist() - eq(1, #servers) - ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\… - end) - - it('sets v:servername at startup or if all servers were stopped', - function() - local initial_server = meths.get_vvar('servername') - assert(initial_server ~= nil and initial_server:len() > 0, - 'v:servername was not initialized') - - -- v:servername is readonly so we cannot unset it--but we can test that it - -- does not get set again thereafter. - local s = funcs.serverstart() - assert(s ~= nil and s:len() > 0, "serverstart() returned empty") - neq(initial_server, s) - - -- serverstop() does _not_ modify v:servername... - eq(1, funcs.serverstop(s)) - eq(initial_server, meths.get_vvar('servername')) - - -- ...unless we stop _all_ servers. - eq(1, funcs.serverstop(funcs.serverlist()[1])) - eq('', meths.get_vvar('servername')) - - -- v:servername will take the next available server. - local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]] - or 'Xtest-functional-server-socket') - funcs.serverstart(servername) - eq(servername, meths.get_vvar('servername')) - end) - - it('serverstop() returns false for invalid input', function() - eq(0, eval("serverstop('')")) - eq(0, eval("serverstop('bogus-socket-name')")) - end) - - it('parses endpoints correctly', function() - clear_serverlist() - eq({}, funcs.serverlist()) - - local s = funcs.serverstart('127.0.0.1:0') -- assign random port - if #s > 0 then - assert(string.match(s, '127.0.0.1:%d+')) - eq(s, funcs.serverlist()[1]) - clear_serverlist() - end - - s = funcs.serverstart('127.0.0.1:') -- assign random port - if #s > 0 then - assert(string.match(s, '127.0.0.1:%d+')) - eq(s, funcs.serverlist()[1]) - clear_serverlist() - end - - local expected = {} - local v4 = '127.0.0.1:12345' - local status, _ = pcall(funcs.serverstart, v4) - if status then - table.insert(expected, v4) - pcall(funcs.serverstart, v4) -- exists already; ignore - end - - local v6 = '::1:12345' - status, _ = pcall(funcs.serverstart, v6) - if status then - table.insert(expected, v6) - pcall(funcs.serverstart, v6) -- exists already; ignore - end - eq(expected, funcs.serverlist()) - clear_serverlist() - - eq('Vim:Failed to start server: invalid argument', - pcall_err(funcs.serverstart, '127.0.0.1:65536')) -- invalid port - eq({}, funcs.serverlist()) - end) - - it('serverlist() returns the list of servers', function() - -- There should already be at least one server. - local n = eval('len(serverlist())') - - -- Add some servers. - local servs = (iswin() - and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] } - or { [[Xtest-pipe0934]], [[Xtest-pipe4324]] }) - for _, s in ipairs(servs) do - eq(s, eval("serverstart('"..s.."')")) - end - - local new_servs = eval('serverlist()') - - -- Exactly #servs servers should be added. - eq(n + #servs, #new_servs) - -- The new servers should be at the end of the list. - for i = 1, #servs do - eq(servs[i], new_servs[i + n]) - eq(1, eval("serverstop('"..servs[i].."')")) - end - -- After serverstop() the servers should NOT be in the list. - eq(n, eval('len(serverlist())')) - end) -end) - -describe('startup --listen', function() - it('validates', function() - clear() - - local cmd = { unpack(helpers.nvim_argv) } - table.insert(cmd, '--listen') - matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd)) - - cmd = { unpack(helpers.nvim_argv) } - table.insert(cmd, '--listen2') - matches('nvim.*: Garbage after option argument: "%-%-listen2"', funcs.system(cmd)) - end) - - it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function() - local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]] - or 'Xtest-listen-pipe') - clear({ env={ NVIM_LISTEN_ADDRESS='Xtest-env-pipe' }, - args={ '--listen', addr } }) - eq(addr, meths.get_vvar('servername')) - end) -end) diff --git a/test/functional/eval/setpos_spec.lua b/test/functional/eval/setpos_spec.lua deleted file mode 100644 index 935f387bcc..0000000000 --- a/test/functional/eval/setpos_spec.lua +++ /dev/null @@ -1,64 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local setpos = helpers.funcs.setpos -local getpos = helpers.funcs.getpos -local insert = helpers.insert -local clear = helpers.clear -local command = helpers.command -local eval = helpers.eval -local eq = helpers.eq -local exc_exec = helpers.exc_exec - - -describe('setpos() function', function() - before_each(function() - clear() - insert([[ - First line of text - Second line of text - Third line of text]]) - command('new') - insert([[ - Line of text 1 - Line of text 2 - Line of text 3]]) - end) - it('can set the current cursor position', function() - setpos(".", {0, 2, 1, 0}) - eq(getpos("."), {0, 2, 1, 0}) - setpos(".", {2, 1, 1, 0}) - eq(getpos("."), {0, 1, 1, 0}) - local ret = exc_exec('call setpos(".", [1, 1, 1, 0])') - eq(0, ret) - end) - it('can set lowercase marks in the current buffer', function() - setpos("'d", {0, 2, 1, 0}) - eq(getpos("'d"), {0, 2, 1, 0}) - command('undo') - command('call setpos("\'d", [2, 3, 1, 0])') - eq(getpos("'d"), {0, 3, 1, 0}) - end) - it('can set lowercase marks in other buffers', function() - local retval = setpos("'d", {1, 2, 1, 0}) - eq(0, retval) - setpos("'d", {1, 2, 1, 0}) - eq(getpos("'d"), {0, 0, 0, 0}) - command('wincmd w') - eq(eval('bufnr("%")'), 1) - eq(getpos("'d"), {0, 2, 1, 0}) - end) - it("fails when setting a mark in a buffer that doesn't exist", function() - local retval = setpos("'d", {3, 2, 1, 0}) - eq(-1, retval) - eq(getpos("'d"), {0, 0, 0, 0}) - retval = setpos("'D", {3, 2, 1, 0}) - eq(-1, retval) - eq(getpos("'D"), {0, 0, 0, 0}) - end) - it('can set uppercase marks', function() - setpos("'D", {2, 2, 3, 0}) - eq(getpos("'D"), {2, 2, 3, 0}) - -- Can set a mark in another buffer - setpos("'D", {1, 2, 2, 0}) - eq(getpos("'D"), {1, 2, 2, 0}) - end) -end) diff --git a/test/functional/eval/sort_spec.lua b/test/functional/eval/sort_spec.lua deleted file mode 100644 index e1cc2c2924..0000000000 --- a/test/functional/eval/sort_spec.lua +++ /dev/null @@ -1,57 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local NIL = helpers.NIL -local eval = helpers.eval -local clear = helpers.clear -local meths = helpers.meths -local funcs = helpers.funcs -local command = helpers.command -local exc_exec = helpers.exc_exec -local redir_exec = helpers.redir_exec - -before_each(clear) - -describe('sort()', function() - it('errors out when sorting special values', function() - eq('Vim(call):E362: Using a boolean value as a Float', - exc_exec('call sort([v:true, v:false], "f")')) - end) - - it('sorts “wrong” values between -0.0001 and 0.0001, preserving order', - function() - meths.set_var('list', {true, false, NIL, {}, {a=42}, 'check', - 0.0001, -0.0001}) - command('call insert(g:list, function("tr"))') - local error_lines = funcs.split( - funcs.execute('silent! call sort(g:list, "f")'), '\n') - local errors = {} - for _, err in ipairs(error_lines) do - errors[err] = true - end - eq({ - ['E362: Using a boolean value as a Float']=true, - ['E891: Using a Funcref as a Float']=true, - ['E892: Using a String as a Float']=true, - ['E893: Using a List as a Float']=true, - ['E894: Using a Dictionary as a Float']=true, - ['E907: Using a special value as a Float']=true, - }, errors) - eq('[-1.0e-4, function(\'tr\'), v:true, v:false, v:null, [], {\'a\': 42}, \'check\', 1.0e-4]', - eval('string(g:list)')) - end) - - it('can yield E702 and stop sorting after that', function() - command([[ - function Cmp(a, b) - if type(a:a) == type([]) || type(a:b) == type([]) - return [] - endif - return (a:a > a:b) - (a:a < a:b) - endfunction - ]]) - eq('\nE745: Using a List as a Number\nE702: Sort compare function failed', - redir_exec('let sl = sort([1, 0, [], 3, 2], "Cmp")')) - eq({1, 0, {}, 3, 2}, meths.get_var('sl')) - end) -end) diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/eval/special_vars_spec.lua deleted file mode 100644 index 97a12d490d..0000000000 --- a/test/functional/eval/special_vars_spec.lua +++ /dev/null @@ -1,190 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local exc_exec = helpers.exc_exec -local command = helpers.command -local funcs = helpers.funcs -local clear = helpers.clear -local eval = helpers.eval -local eq = helpers.eq -local meths = helpers.meths -local NIL = helpers.NIL - -describe('Special values', function() - before_each(clear) - - it('do not cause error when freed', function() - command([[ - function Test() - try - return v:true - finally - return 'something else' - endtry - endfunction - ]]) - eq(0, exc_exec('call Test()')) - end) - - it('work with empty()', function() - eq(0, funcs.empty(true)) - eq(1, funcs.empty(false)) - eq(1, funcs.empty(NIL)) - end) - - it('can be stringified and eval’ed back', function() - eq(true, funcs.eval(funcs.string(true))) - eq(false, funcs.eval(funcs.string(false))) - eq(NIL, funcs.eval(funcs.string(NIL))) - end) - - it('work with is/isnot properly', function() - eq(1, eval('v:null is v:null')) - eq(0, eval('v:null is v:true')) - eq(0, eval('v:null is v:false')) - eq(1, eval('v:true is v:true')) - eq(0, eval('v:true is v:false')) - eq(1, eval('v:false is v:false')) - - eq(0, eval('v:null is 0')) - eq(0, eval('v:true is 0')) - eq(0, eval('v:false is 0')) - - eq(0, eval('v:null is 1')) - eq(0, eval('v:true is 1')) - eq(0, eval('v:false is 1')) - - eq(0, eval('v:null is ""')) - eq(0, eval('v:true is ""')) - eq(0, eval('v:false is ""')) - - eq(0, eval('v:null is "null"')) - eq(0, eval('v:true is "true"')) - eq(0, eval('v:false is "false"')) - - eq(0, eval('v:null is []')) - eq(0, eval('v:true is []')) - eq(0, eval('v:false is []')) - - eq(0, eval('v:null isnot v:null')) - eq(1, eval('v:null isnot v:true')) - eq(1, eval('v:null isnot v:false')) - eq(0, eval('v:true isnot v:true')) - eq(1, eval('v:true isnot v:false')) - eq(0, eval('v:false isnot v:false')) - - eq(1, eval('v:null isnot 0')) - eq(1, eval('v:true isnot 0')) - eq(1, eval('v:false isnot 0')) - - eq(1, eval('v:null isnot 1')) - eq(1, eval('v:true isnot 1')) - eq(1, eval('v:false isnot 1')) - - eq(1, eval('v:null isnot ""')) - eq(1, eval('v:true isnot ""')) - eq(1, eval('v:false isnot ""')) - - eq(1, eval('v:null isnot "null"')) - eq(1, eval('v:true isnot "true"')) - eq(1, eval('v:false isnot "false"')) - - eq(1, eval('v:null isnot []')) - eq(1, eval('v:true isnot []')) - eq(1, eval('v:false isnot []')) - end) - - it('work with +/-/* properly', function() - eq(1, eval('0 + v:true')) - eq(0, eval('0 + v:null')) - eq(0, eval('0 + v:false')) - - eq(-1, eval('0 - v:true')) - eq( 0, eval('0 - v:null')) - eq( 0, eval('0 - v:false')) - - eq(1, eval('1 * v:true')) - eq(0, eval('1 * v:null')) - eq(0, eval('1 * v:false')) - end) - - it('does not work with +=/-=/.=', function() - meths.set_var('true', true) - meths.set_var('false', false) - command('let null = v:null') - - eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let true += 1')) - eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let false += 1')) - eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let null += 1')) - - eq('Vim(let):E734: Wrong variable type for -=', exc_exec('let true -= 1')) - eq('Vim(let):E734: Wrong variable type for -=', exc_exec('let false -= 1')) - eq('Vim(let):E734: Wrong variable type for -=', exc_exec('let null -= 1')) - - eq('Vim(let):E734: Wrong variable type for .=', exc_exec('let true .= 1')) - eq('Vim(let):E734: Wrong variable type for .=', exc_exec('let false .= 1')) - eq('Vim(let):E734: Wrong variable type for .=', exc_exec('let null .= 1')) - end) - - it('work with . (concat) properly', function() - eq("true", eval('"" . v:true')) - eq("null", eval('"" . v:null')) - eq("false", eval('"" . v:false')) - end) - - it('work with type()', function() - eq(6, funcs.type(true)) - eq(6, funcs.type(false)) - eq(7, funcs.type(NIL)) - end) - - it('work with copy() and deepcopy()', function() - eq(true, funcs.deepcopy(true)) - eq(false, funcs.deepcopy(false)) - eq(NIL, funcs.deepcopy(NIL)) - - eq(true, funcs.copy(true)) - eq(false, funcs.copy(false)) - eq(NIL, funcs.copy(NIL)) - end) - - it('fails in index', function() - eq('Vim(echo):E909: Cannot index a special variable', exc_exec('echo v:true[0]')) - eq('Vim(echo):E909: Cannot index a special variable', exc_exec('echo v:false[0]')) - eq('Vim(echo):E909: Cannot index a special variable', exc_exec('echo v:null[0]')) - end) - - it('is accepted by assert_true and assert_false', function() - funcs.assert_false(false) - funcs.assert_false(true) - funcs.assert_false(NIL) - - funcs.assert_true(false) - funcs.assert_true(true) - funcs.assert_true(NIL) - - eq({ - 'Expected False but got v:true', - 'Expected False but got v:null', - 'Expected True but got v:false', - 'Expected True but got v:null', - }, meths.get_vvar('errors')) - end) - - describe('compat', function() - it('v:count is distinct from count', function() - command('let count = []') -- v:count is readonly - eq(1, eval('count is# g:["count"]')) - end) - it('v:errmsg is distinct from errmsg', function() - command('let errmsg = 1') - eq(1, eval('errmsg is# g:["errmsg"]')) - end) - it('v:shell_error is distinct from shell_error', function() - command('let shell_error = []') -- v:shell_error is readonly - eq(1, eval('shell_error is# g:["shell_error"]')) - end) - it('v:this_session is distinct from this_session', function() - command('let this_session = []') - eq(1, eval('this_session is# g:["this_session"]')) - end) - end) -end) diff --git a/test/functional/eval/string_spec.lua b/test/functional/eval/string_spec.lua deleted file mode 100644 index adc1af9b8e..0000000000 --- a/test/functional/eval/string_spec.lua +++ /dev/null @@ -1,277 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq = helpers.eq -local command = helpers.command -local meths = helpers.meths -local eval = helpers.eval -local exc_exec = helpers.exc_exec -local redir_exec = helpers.redir_exec -local funcs = helpers.funcs -local NIL = helpers.NIL -local source = helpers.source -local dedent = helpers.dedent - -describe('string() function', function() - before_each(clear) - - describe('used to represent floating-point values', function() - it('dumps NaN values', function() - eq('str2float(\'nan\')', eval('string(str2float(\'nan\'))')) - end) - - it('dumps infinite values', function() - eq('str2float(\'inf\')', eval('string(str2float(\'inf\'))')) - eq('-str2float(\'inf\')', eval('string(str2float(\'-inf\'))')) - end) - - it('dumps regular values', function() - eq('1.5', funcs.string(1.5)) - eq('1.56e-20', funcs.string(1.56000e-020)) - eq('0.0', eval('string(0.0)')) - end) - - it('dumps special v: values', function() - eq('v:true', eval('string(v:true)')) - eq('v:false', eval('string(v:false)')) - eq('v:null', eval('string(v:null)')) - eq('v:true', funcs.string(true)) - eq('v:false', funcs.string(false)) - eq('v:null', funcs.string(NIL)) - end) - - it('dumps values with at most six digits after the decimal point', - function() - eq('1.234568e-20', funcs.string(1.23456789123456789123456789e-020)) - eq('1.234568', funcs.string(1.23456789123456789123456789)) - end) - - it('dumps values with at most seven digits before the decimal point', - function() - eq('1234567.891235', funcs.string(1234567.89123456789123456789)) - eq('1.234568e7', funcs.string(12345678.9123456789123456789)) - end) - - it('dumps negative values', function() - eq('-1.5', funcs.string(-1.5)) - eq('-1.56e-20', funcs.string(-1.56000e-020)) - eq('-1.234568e-20', funcs.string(-1.23456789123456789123456789e-020)) - eq('-1.234568', funcs.string(-1.23456789123456789123456789)) - eq('-1234567.891235', funcs.string(-1234567.89123456789123456789)) - eq('-1.234568e7', funcs.string(-12345678.9123456789123456789)) - end) - end) - - describe('used to represent numbers', function() - it('dumps regular values', function() - eq('0', funcs.string(0)) - eq('-1', funcs.string(-1)) - eq('1', funcs.string(1)) - end) - - it('dumps large values', function() - eq('2147483647', funcs.string(2^31-1)) - eq('-2147483648', funcs.string(-2^31)) - end) - end) - - describe('used to represent strings', function() - it('dumps regular strings', function() - eq('\'test\'', funcs.string('test')) - end) - - it('dumps empty strings', function() - eq('\'\'', funcs.string('')) - end) - - it('dumps strings with \' inside', function() - eq('\'\'\'\'\'\'\'\'', funcs.string('\'\'\'')) - eq('\'a\'\'b\'\'\'\'\'', funcs.string('a\'b\'\'')) - eq('\'\'\'b\'\'\'\'d\'', funcs.string('\'b\'\'d')) - eq('\'a\'\'b\'\'c\'\'d\'', funcs.string('a\'b\'c\'d')) - end) - - it('dumps NULL strings', function() - eq('\'\'', eval('string($XXX_UNEXISTENT_VAR_XXX)')) - end) - - it('dumps NULL lists', function() - eq('[]', eval('string(v:_null_list)')) - end) - - it('dumps NULL dictionaries', function() - eq('{}', eval('string(v:_null_dict)')) - end) - end) - - describe('used to represent funcrefs', function() - before_each(function() - source([[ - function Test1() - endfunction - - function s:Test2() dict - endfunction - - function g:Test3() dict - endfunction - - let g:Test2_f = function('s:Test2') - ]]) - end) - - it('dumps references to built-in functions', function() - eq('function(\'function\')', eval('string(function("function"))')) - end) - - it('dumps references to user functions', function() - eq('function(\'Test1\')', eval('string(function("Test1"))')) - eq('function(\'g:Test3\')', eval('string(function("g:Test3"))')) - end) - - it('dumps references to script functions', function() - eq('function(\'<SNR>1_Test2\')', eval('string(Test2_f)')) - end) - - it('dumps partials with self referencing a partial', function() - source([[ - function TestDict() dict - endfunction - let d = {} - let TestDictRef = function('TestDict', d) - let d.tdr = TestDictRef - ]]) - eq("\nE724: unable to correctly dump variable with self-referencing container\nfunction('TestDict', {'tdr': function('TestDict', {E724@1})})", - redir_exec('echo string(d.tdr)')) - end) - - it('dumps automatically created partials', function() - eq('function(\'<SNR>1_Test2\', {\'f\': function(\'<SNR>1_Test2\')})', - eval('string({"f": Test2_f}.f)')) - eq('function(\'<SNR>1_Test2\', [1], {\'f\': function(\'<SNR>1_Test2\', [1])})', - eval('string({"f": function(Test2_f, [1])}.f)')) - end) - - it('dumps manually created partials', function() - eq('function(\'Test3\', [1, 2], {})', - eval('string(function("Test3", [1, 2], {}))')) - eq('function(\'Test3\', {})', - eval('string(function("Test3", {}))')) - eq('function(\'Test3\', [1, 2])', - eval('string(function("Test3", [1, 2]))')) - end) - - it('does not crash or halt when dumping partials with reference cycles in self', - function() - meths.set_var('d', {v=true}) - eq(dedent([[ - - E724: unable to correctly dump variable with self-referencing container - {'p': function('<SNR>1_Test2', {E724@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]), - redir_exec('echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))')) - end) - - it('does not show errors when dumping partials referencing the same dictionary', - function() - command('let d = {}') - -- Regression for “eval/typval_encode: Dump empty dictionary before - -- checking for refcycle”, results in error. - eq('[function(\'tr\', {}), function(\'tr\', {})]', eval('string([function("tr", d), function("tr", d)])')) - -- Regression for “eval: Work with reference cycles in partials (self) - -- properly”, results in crash. - eval('extend(d, {"a": 1})') - eq('[function(\'tr\', {\'a\': 1}), function(\'tr\', {\'a\': 1})]', eval('string([function("tr", d), function("tr", d)])')) - end) - - it('does not crash or halt when dumping partials with reference cycles in arguments', - function() - meths.set_var('l', {}) - eval('add(l, l)') - -- Regression: the below line used to crash (add returns original list and - -- there was error in dumping partials). Tested explicitly in - -- test/unit/api/private_helpers_spec.lua. - eval('add(l, function("Test1", l))') - eq(dedent([=[ - - E724: unable to correctly dump variable with self-referencing container - function('Test1', [[{E724@2}, function('Test1', [{E724@2}])], function('Test1', [[{E724@4}, function('Test1', [{E724@4}])]])])]=]), - redir_exec('echo string(function("Test1", l))')) - end) - - it('does not crash or halt when dumping partials with reference cycles in self and arguments', - function() - meths.set_var('d', {v=true}) - meths.set_var('l', {}) - eval('add(l, l)') - eval('add(l, function("Test1", l))') - eval('add(l, function("Test1", d))') - eq(dedent([=[ - - E724: unable to correctly dump variable with self-referencing container - {'p': function('<SNR>1_Test2', [[{E724@3}, function('Test1', [{E724@3}]), function('Test1', {E724@0})], function('Test1', [[{E724@5}, function('Test1', [{E724@5}]), function('Test1', {E724@0})]]), function('Test1', {E724@0})], {E724@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]), - redir_exec('echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))')) - end) - end) - - describe('used to represent lists', function() - it('dumps empty list', function() - eq('[]', funcs.string({})) - end) - - it('dumps nested lists', function() - eq('[[[[[]]]]]', funcs.string({{{{{}}}}})) - end) - - it('dumps nested non-empty lists', function() - eq('[1, [[3, [[5], 4]], 2]]', funcs.string({1, {{3, {{5}, 4}}, 2}})) - end) - - it('errors when dumping recursive lists', function() - meths.set_var('l', {}) - eval('add(l, l)') - eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container', - exc_exec('echo string(l)')) - end) - - it('dumps recursive lists despite the error', function() - meths.set_var('l', {}) - eval('add(l, l)') - eq('\nE724: unable to correctly dump variable with self-referencing container\n[{E724@0}]', - redir_exec('echo string(l)')) - eq('\nE724: unable to correctly dump variable with self-referencing container\n[[{E724@1}]]', - redir_exec('echo string([l])')) - end) - end) - - describe('used to represent dictionaries', function() - it('dumps empty dictionary', function() - eq('{}', eval('string({})')) - end) - - it('dumps list with two same empty dictionaries, also in partials', function() - command('let d = {}') - eq('[{}, {}]', eval('string([d, d])')) - eq('[function(\'tr\', {}), {}]', eval('string([function("tr", d), d])')) - eq('[{}, function(\'tr\', {})]', eval('string([d, function("tr", d)])')) - end) - - it('dumps non-empty dictionary', function() - eq('{\'t\'\'est\': 1}', funcs.string({['t\'est']=1})) - end) - - it('errors when dumping recursive dictionaries', function() - meths.set_var('d', {d=1}) - eval('extend(d, {"d": d})') - eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container', - exc_exec('echo string(d)')) - end) - - it('dumps recursive dictionaries despite the error', function() - meths.set_var('d', {d=1}) - eval('extend(d, {"d": d})') - eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'d\': {E724@0}}', - redir_exec('echo string(d)')) - eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'out\': {\'d\': {E724@1}}}', - redir_exec('echo string({"out": d})')) - end) - end) -end) diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua deleted file mode 100644 index 24a1f05390..0000000000 --- a/test/functional/eval/system_spec.lua +++ /dev/null @@ -1,589 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local assert_alive = helpers.assert_alive -local nvim_dir = helpers.nvim_dir -local eq, call, clear, eval, feed_command, feed, nvim = - helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command, - helpers.feed, helpers.nvim -local command = helpers.command -local exc_exec = helpers.exc_exec -local iswin = helpers.iswin -local os_kill = helpers.os_kill -local pcall_err = helpers.pcall_err - -local Screen = require('test.functional.ui.screen') - -local function create_file_with_nuls(name) - return function() - feed('ipart1<C-V>000part2<C-V>000part3<ESC>:w '..name..'<CR>') - eval('1') -- wait for the file to be created - end -end - -local function delete_file(name) - return function() - eval("delete('"..name.."')") - end -end - -describe('system()', function() - before_each(clear) - - describe('command passed as a List', function() - local function printargs_path() - return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '') - end - - it('throws error if cmd[0] is not executable', function() - eq("Vim:E475: Invalid value for argument cmd: 'this-should-not-exist' is not executable", - pcall_err(call, 'system', { 'this-should-not-exist' })) - eq(-1, eval('v:shell_error')) - end) - - it('parameter validation does NOT modify v:shell_error', function() - -- 1. Call system() with invalid parameters. - -- 2. Assert that v:shell_error was NOT set. - feed_command('call system({})') - eq('E475: Invalid argument: expected String or List', eval('v:errmsg')) - eq(0, eval('v:shell_error')) - feed_command('call system([])') - eq('E474: Invalid argument', eval('v:errmsg')) - eq(0, eval('v:shell_error')) - - -- Provoke a non-zero v:shell_error. - eq("Vim:E475: Invalid value for argument cmd: 'this-should-not-exist' is not executable", - pcall_err(call, 'system', { 'this-should-not-exist' })) - local old_val = eval('v:shell_error') - eq(-1, old_val) - - -- 1. Call system() with invalid parameters. - -- 2. Assert that v:shell_error was NOT modified. - feed_command('call system({})') - eq(old_val, eval('v:shell_error')) - feed_command('call system([])') - eq(old_val, eval('v:shell_error')) - end) - - it('quotes arguments correctly #5280', function() - local out = call('system', - { printargs_path(), [[1]], [[2 "3]], [[4 ' 5]], [[6 ' 7']] }) - - eq(0, eval('v:shell_error')) - eq([[arg1=1;arg2=2 "3;arg3=4 ' 5;arg4=6 ' 7';]], out) - - out = call('system', { printargs_path(), [['1]], [[2 "3]] }) - eq(0, eval('v:shell_error')) - eq([[arg1='1;arg2=2 "3;]], out) - - out = call('system', { printargs_path(), "A\nB" }) - eq(0, eval('v:shell_error')) - eq("arg1=A\nB;", out) - end) - - it('calls executable in $PATH', function() - if 0 == eval("executable('python')") then pending("missing `python`") end - eq("foo\n", eval([[system(['python', '-c', 'print("foo")'])]])) - eq(0, eval('v:shell_error')) - end) - - it('does NOT run in shell', function() - if iswin() then - eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'Write-Output', '%PATH%'])")) - else - eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])")) - end - end) - end) - - it('sets v:shell_error', function() - if iswin() then - eval([[system("cmd.exe /c exit")]]) - eq(0, eval('v:shell_error')) - eval([[system("cmd.exe /c exit 1")]]) - eq(1, eval('v:shell_error')) - eval([[system("cmd.exe /c exit 5")]]) - eq(5, eval('v:shell_error')) - eval([[system('this-should-not-exist')]]) - eq(1, eval('v:shell_error')) - else - eval([[system("sh -c 'exit'")]]) - eq(0, eval('v:shell_error')) - eval([[system("sh -c 'exit 1'")]]) - eq(1, eval('v:shell_error')) - eval([[system("sh -c 'exit 5'")]]) - eq(5, eval('v:shell_error')) - eval([[system('this-should-not-exist')]]) - eq(127, eval('v:shell_error')) - end - end) - - describe('executes shell function', function() - local screen - - before_each(function() - screen = Screen.new() - screen:attach() - end) - - if iswin() then - local function test_more() - eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]])) - end - local function test_shell_unquoting() - eval([[system('"ping" "-n" "1" "127.0.0.1"')]]) - eq(0, eval('v:shell_error')) - eq('"a b"\n', eval([[system('cmd /s/c "cmd /s/c "cmd /s/c "echo "a b""""')]])) - eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command Write-Output ''\^"a b\^"''')]])) - end - - it('with shell=cmd.exe', function() - command('set shell=cmd.exe') - eq('""\n', eval([[system('echo ""')]])) - eq('"a b"\n', eval([[system('echo "a b"')]])) - eq('a \nb\n', eval([[system('echo a & echo b')]])) - eq('a \n', eval([[system('echo a 2>&1')]])) - test_more() - eval([[system('cd "C:\Program Files"')]]) - eq(0, eval('v:shell_error')) - test_shell_unquoting() - end) - - it('with shell=cmd', function() - command('set shell=cmd') - eq('"a b"\n', eval([[system('echo "a b"')]])) - test_more() - test_shell_unquoting() - end) - - it('with shell=$COMSPEC', function() - local comspecshell = eval("fnamemodify($COMSPEC, ':t')") - if comspecshell == 'cmd.exe' then - command('set shell=$COMSPEC') - eq('"a b"\n', eval([[system('echo "a b"')]])) - test_more() - test_shell_unquoting() - else - pending('$COMSPEC is not cmd.exe: ' .. comspecshell) - end - end) - - it('works with powershell', function() - helpers.set_shell_powershell() - eq('a\nb\n', eval([[system('Write-Output a b')]])) - eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]])) - eq('a b\n', eval([[system('Write-Output "a b"')]])) - end) - end - - it('works with powershell w/ UTF-8 text (#13713)', function() - if not helpers.has_powershell() then - pending("not tested; powershell was not found", function() end) - return - end - -- Should work with recommended config used in helper - helpers.set_shell_powershell() - eq('ああ\n', eval([[system('Write-Output "ああ"')]])) - -- Sanity test w/ default encoding - -- * on Windows, expected to default to Western European enc - -- * on Linux, expected to default to UTF8 - command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']]) - eq(iswin() and '??\n' or 'ああ\n', eval([[system('Write-Output "ああ"')]])) - end) - - it('`echo` and waits for its return', function() - feed(':call system("echo")<cr>') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - :call system("echo") | - ]]) - end) - - it('prints verbose information', function() - nvim('set_option', 'shell', 'fake_shell') - nvim('set_option', 'shellcmdflag', 'cmdflag') - - screen:try_resize(72, 14) - feed(':4verbose echo system("echo hi")<cr>') - if iswin() then - screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' '"echo hi"'"]]} - else - screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' 'echo hi'"]]} - end - feed('<cr>') - end) - - it('self and total time recorded separately', function() - local tempfile = helpers.tmpname() - - feed(':function! AlmostNoSelfTime()<cr>') - feed('echo system("echo hi")<cr>') - feed('endfunction<cr>') - - feed(':profile start ' .. tempfile .. '<cr>') - feed(':profile func AlmostNoSelfTime<cr>') - feed(':call AlmostNoSelfTime()<cr>') - feed(':profile dump<cr>') - - feed(':edit ' .. tempfile .. '<cr>') - - local command_total_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[2]) - local command_self_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[3]) - - helpers.neq(nil, command_total_time) - helpers.neq(nil, command_self_time) - end) - - it('`yes` interrupted with CTRL-C', function() - feed(':call system("' .. (iswin() - and 'for /L %I in (1,0,2) do @echo y' - or 'yes') .. '")<cr>') - screen:expect([[ - | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | -]] .. (iswin() - and [[ - :call system("for /L %I in (1,0,2) do @echo y") |]] - or [[ - :call system("yes") |]])) - feed('<c-c>') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - Type :qa and press <Enter> to exit Nvim | - ]]) - end) - end) - - describe('passing no input', function() - it('returns the program output', function() - if iswin() then - eq("echoed\n", eval('system("echo echoed")')) - else - eq("echoed", eval('system("echo -n echoed")')) - end - end) - it('to backgrounded command does not crash', function() - -- This is indeterminate, just exercise the codepath. May get E5677. - feed_command('call system(has("win32") ? "start /b /wait cmd /c echo echoed" : "echo -n echoed &")') - local v_errnum = string.match(eval("v:errmsg"), "^E%d*:") - if v_errnum then - eq("E5677:", v_errnum) - end - assert_alive() - end) - end) - - describe('passing input', function() - it('returns the program output', function() - eq("input", eval('system("cat -", "input")')) - end) - it('to backgrounded command does not crash', function() - -- This is indeterminate, just exercise the codepath. May get E5677. - feed_command('call system(has("win32") ? "start /b /wait more" : "cat - &", "input")') - local v_errnum = string.match(eval("v:errmsg"), "^E%d*:") - if v_errnum then - eq("E5677:", v_errnum) - end - assert_alive() - end) - it('works with an empty string', function() - eq("test\n", eval('system("echo test", "")')) - assert_alive() - end) - end) - - describe('passing a lot of input', function() - it('returns the program output', function() - local input = {} - -- write more than 1mb of data, which should be enough to overcome - -- the os buffer limit and force multiple event loop iterations to write - -- everything - for _ = 1, 0xffff do - input[#input + 1] = '01234567890ABCDEFabcdef' - end - input = table.concat(input, '\n') - nvim('set_var', 'input', input) - eq(input, eval('system("cat -", g:input)')) - end) - end) - - describe('Number input', function() - it('is treated as a buffer id', function() - command("put ='text in buffer 1'") - eq('\ntext in buffer 1\n', eval('system("cat", 1)')) - eq('Vim(echo):E86: Buffer 42 does not exist', - exc_exec('echo system("cat", 42)')) - end) - end) - - describe('with output containing NULs', function() - local fname = 'Xtest' - - before_each(create_file_with_nuls(fname)) - after_each(delete_file(fname)) - - it('replaces NULs by SOH characters', function() - eq('part1\001part2\001part3\n', eval([[system('"cat" "]]..fname..[["')]])) - end) - end) - - describe('input passed as List', function() - it('joins List items with linefeed characters', function() - eq('line1\nline2\nline3', - eval("system('cat -', ['line1', 'line2', 'line3'])")) - end) - - -- Notice that NULs are converted to SOH when the data is read back. This - -- is inconsistent and is a good reason for the existence of the - -- `systemlist()` function, where input and output map to the same - -- characters(see the following tests with `systemlist()` below) - describe('with linefeed characters inside List items', function() - it('converts linefeed characters to NULs', function() - eq('l1\001p2\nline2\001a\001b\nl3', - eval([[system('cat -', ["l1\np2", "line2\na\nb", 'l3'])]])) - end) - end) - - describe('with leading/trailing whitespace characters on items', function() - it('preserves whitespace, replacing linefeeds by NULs', function() - eq('line \nline2\001\n\001line3', - eval([[system('cat -', ['line ', "line2\n", "\nline3"])]])) - end) - end) - end) - - it("with a program that doesn't close stdout will exit properly after passing input", function() - local out = eval(string.format("system('%s', 'clip-data')", nvim_dir..'/streams-test')) - assert(out:sub(0, 5) == 'pid: ', out) - os_kill(out:match("%d+")) - end) -end) - -describe('systemlist()', function() - -- Similar to `system()`, but returns List instead of String. - before_each(clear) - - it('sets v:shell_error', function() - if iswin() then - eval([[systemlist("cmd.exe /c exit")]]) - eq(0, eval('v:shell_error')) - eval([[systemlist("cmd.exe /c exit 1")]]) - eq(1, eval('v:shell_error')) - eval([[systemlist("cmd.exe /c exit 5")]]) - eq(5, eval('v:shell_error')) - eval([[systemlist('this-should-not-exist')]]) - eq(1, eval('v:shell_error')) - else - eval([[systemlist("sh -c 'exit'")]]) - eq(0, eval('v:shell_error')) - eval([[systemlist("sh -c 'exit 1'")]]) - eq(1, eval('v:shell_error')) - eval([[systemlist("sh -c 'exit 5'")]]) - eq(5, eval('v:shell_error')) - eval([[systemlist('this-should-not-exist')]]) - eq(127, eval('v:shell_error')) - end - end) - - describe('executes shell function', function() - local screen - - before_each(function() - screen = Screen.new() - screen:attach() - end) - - after_each(function() - screen:detach() - end) - - it('`echo` and waits for its return', function() - feed(':call systemlist("echo")<cr>') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - :call systemlist("echo") | - ]]) - end) - - it('`yes` interrupted with CTRL-C', function() - feed(':call systemlist("yes | xargs")<cr>') - screen:expect([[ - | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - :call systemlist("yes | xargs") | - ]]) - feed('<c-c>') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - ~ | - Type :qa and press <Enter> to exit Nvim | - ]]) - end) - end) - - describe('passing string with linefeed characters as input', function() - it('splits the output on linefeed characters', function() - eq({'abc', 'def', 'ghi'}, eval([[systemlist("cat -", "abc\ndef\nghi")]])) - end) - end) - - describe('passing a lot of input', function() - it('returns the program output', function() - local input = {} - for _ = 1, 0xffff do - input[#input + 1] = '01234567890ABCDEFabcdef' - end - nvim('set_var', 'input', input) - eq(input, eval('systemlist("cat -", g:input)')) - end) - end) - - describe('with output containing NULs', function() - local fname = 'Xtest' - - before_each(function() - command('set ff=unix') - create_file_with_nuls(fname)() - end) - after_each(delete_file(fname)) - - it('replaces NULs by newline characters', function() - eq({'part1\npart2\npart3'}, eval([[systemlist('"cat" "]]..fname..[["')]])) - end) - end) - - describe('input passed as List', function() - it('joins list items with linefeed characters', function() - eq({'line1', 'line2', 'line3'}, - eval("systemlist('cat -', ['line1', 'line2', 'line3'])")) - end) - - -- Unlike `system()` which uses SOH to represent NULs, with `systemlist()` - -- input and ouput are the same. - describe('with linefeed characters inside list items', function() - it('converts linefeed characters to NULs', function() - eq({'l1\np2', 'line2\na\nb', 'l3'}, - eval([[systemlist('cat -', ["l1\np2", "line2\na\nb", 'l3'])]])) - end) - end) - - describe('with leading/trailing whitespace characters on items', function() - it('preserves whitespace, replacing linefeeds by NULs', function() - eq({'line ', 'line2\n', '\nline3'}, - eval([[systemlist('cat -', ['line ', "line2\n", "\nline3"])]])) - end) - end) - end) - - describe('handles empty lines', function() - it('in the middle', function() - eq({'line one','','line two'}, eval("systemlist('cat',['line one','','line two'])")) - end) - - it('in the beginning', function() - eq({'','line one','line two'}, eval("systemlist('cat',['','line one','line two'])")) - end) - end) - - describe('when keepempty option is', function() - it('0, ignores trailing newline', function() - eq({'aa','bb'}, eval("systemlist('cat',['aa','bb'],0)")) - eq({'aa','bb'}, eval("systemlist('cat',['aa','bb',''],0)")) - end) - - it('1, preserves trailing newline', function() - eq({'aa','bb'}, eval("systemlist('cat',['aa','bb'],1)")) - eq({'aa','bb',''}, eval("systemlist('cat',['aa','bb',''],2)")) - end) - end) - - it("with a program that doesn't close stdout will exit properly after passing input", function() - local out = eval(string.format("systemlist('%s', 'clip-data')", nvim_dir..'/streams-test')) - assert(out[1]:sub(0, 5) == 'pid: ', out) - os_kill(out[1]:match("%d+")) - end) - - it('works with powershell w/ UTF-8 text (#13713)', function() - if not helpers.has_powershell() then - pending("not tested; powershell was not found", function() end) - return - end - -- Should work with recommended config used in helper - helpers.set_shell_powershell() - eq({iswin() and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) - -- Sanity test w/ default encoding - -- * on Windows, expected to default to Western European enc - -- * on Linux, expected to default to UTF8 - command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']]) - eq({iswin() and '?\r' or 'あ'}, eval([[systemlist('Write-Output あ')]])) - end) - -end) diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua deleted file mode 100644 index 9ee0735e40..0000000000 --- a/test/functional/eval/timer_spec.lua +++ /dev/null @@ -1,265 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') -local feed, eq, eval, ok = helpers.feed, helpers.eq, helpers.eval, helpers.ok -local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run -local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs -local curbufmeths = helpers.curbufmeths -local load_adjust = helpers.load_adjust -local retry = helpers.retry - -describe('timers', function() - before_each(function() - clear() - source([[ - let g:val = 0 - func MyHandler(timer) - let g:val += 1 - endfunc - ]]) - end) - - it('works one-shot', function() - eq(0, eval("[timer_start(10, 'MyHandler'), g:val][1]")) - run(nil, nil, nil, load_adjust(100)) - eq(1,eval("g:val")) - end) - - it('works one-shot when repeat=0', function() - eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 0}), g:val][1]")) - run(nil, nil, nil, load_adjust(100)) - eq(1, eval("g:val")) - end) - - it('works with repeat two', function() - eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]")) - run(nil, nil, nil, load_adjust(20)) - retry(nil, load_adjust(300), function() - eq(2, eval("g:val")) - end) - end) - - it('are triggered during sleep', function() - source([[ - let g:val = -1 - func! MyHandler(timer) - if g:val >= 0 - let g:val += 1 - if g:val == 2 - call timer_stop(a:timer) - endif - endif - endfunc - ]]) - eval("timer_start(10, 'MyHandler', {'repeat': -1})") - nvim_async("command", "sleep 10") - eq(-1, eval("g:val")) -- timer did nothing yet. - nvim_async("command", "let g:val = 0") - run(nil, nil, nil, load_adjust(20)) - retry(nil, nil, function() - eq(2, eval("g:val")) - end) - end) - - it('works with zero timeout', function() - -- timer_start does still not invoke the callback immediately - eq(0, eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]")) - retry(nil, nil, function() - eq(1000, eval("g:val")) - end) - end) - - it('can be started during sleep', function() - nvim_async("command", "sleep 10") - -- this also tests that remote requests works during sleep - eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]")) - run(nil, nil, nil, load_adjust(20)) - retry(nil, load_adjust(300), function() eq(2,eval("g:val")) end) - end) - - it('are paused when event processing is disabled', function() - command("call timer_start(5, 'MyHandler', {'repeat': -1})") - run(nil, nil, nil, load_adjust(10)) - local count = eval("g:val") - -- shows two line error message and thus invokes the return prompt. - -- if we start to allow event processing here, we need to change this test. - feed(':throw "fatal error"<CR>') - run(nil, nil, nil, load_adjust(30)) - feed("<cr>") - local diff = eval("g:val") - count - assert(0 <= diff and diff <= 4, - 'expected (0 <= diff <= 4), got: '..tostring(diff)) - end) - - it('are triggered in blocking getchar() call', function() - command("call timer_start(5, 'MyHandler', {'repeat': -1})") - nvim_async("command", "let g:val = 0 | let g:c = getchar()") - retry(nil, nil, function() - local val = eval("g:val") - ok(val >= 2, "expected >= 2, got: "..tostring(val)) - eq(0, eval("getchar(1)")) - end) - feed("c") - eq(99, eval("g:c")) - end) - - it('can invoke redraw in blocking getchar() call', function() - local screen = Screen.new(40, 6) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold=true, foreground=Screen.colors.Blue}, - }) - - curbufmeths.set_lines(0, -1, true, {"ITEM 1", "ITEM 2"}) - source([[ - let g:cont = 0 - func! AddItem(timer) - if !g:cont - return - endif - call timer_stop(a:timer) - - call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3']) - - " Meant to test for what Vim tests in Test_peek_and_get_char. - call getchar(1) - - redraw - endfunc - ]]) - nvim_async("command", "let g:c2 = getchar()") - nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})") - - screen:expect([[ - ITEM 1 | - ITEM 2 | - {1:~ }| - {1:~ }| - {1:~ }| - ^ | - ]]) - nvim_async("command", "let g:cont = 1") - - screen:expect([[ - ITEM 1 | - ITEM 2 | - ITEM 3 | - {1:~ }| - {1:~ }| - ^ | - ]]) - - feed("3") - eq(51, eval("g:c2")) - screen:expect([[ - ^ITEM 1 | - ITEM 2 | - ITEM 3 | - {1:~ }| - {1:~ }| - | - ]]) - end) - - it('can be stopped', function() - local t_init_val = eval("[timer_start(5, 'MyHandler', {'repeat': -1}), g:val]") - eq(0, t_init_val[2]) - run(nil, nil, nil, load_adjust(30)) - funcs.timer_stop(t_init_val[1]) - local count = eval("g:val") - run(nil, load_adjust(300), nil, load_adjust(30)) - local count2 = eval("g:val") - -- when count is eval:ed after timer_stop this should be non-racy - eq(count, count2) - end) - - it('can be stopped from the handler', function() - source([[ - func! MyHandler(timer) - let g:val += 1 - if g:val == 3 - call timer_stop(a:timer) - " check double stop is ignored - call timer_stop(a:timer) - endif - endfunc - ]]) - eq(0, eval("g:val")) - command("call timer_start(10, 'MyHandler', {'repeat': -1})") - retry(nil, nil, function() - eq(3, eval("g:val")) - end) - end) - - it('can have two timers', function() - source([[ - let g:val2 = 0 - func! MyHandler2(timer) - let g:val2 += 1 - endfunc - ]]) - command("call timer_start(2, 'MyHandler', {'repeat': 3})") - command("call timer_start(4, 'MyHandler2', {'repeat': 2})") - retry(nil, nil, function() - eq(3, eval("g:val")) - eq(2, eval("g:val2")) - end) - end) - - it('do not crash when processing events in the handler', function() - source([[ - let g:val = 0 - func! MyHandler(timer) - call timer_stop(a:timer) - sleep 10m - let g:val += 1 - endfunc - ]]) - command("call timer_start(5, 'MyHandler', {'repeat': 1})") - run(nil, nil, nil, load_adjust(20)) - retry(nil, load_adjust(150), function() - eq(1, eval("g:val")) - end) - end) - - - it("doesn't mess up the cmdline", function() - local screen = Screen.new(40, 6) - screen:attach() - screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} ) - source([[ - let g:val = 0 - func! MyHandler(timer) - while !g:val - return - endwhile - call timer_stop(a:timer) - - echo "evil" - redraw - let g:val = 2 - endfunc - ]]) - command("call timer_start(100, 'MyHandler', {'repeat': -1})") - feed(":good") - screen:expect([[ - | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - :good^ | - ]]) - command('let g:val = 1') - - screen:expect{grid=[[ - | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - :good^ | - ]], intermediate=true, timeout=load_adjust(200)} - - eq(2, eval('g:val')) - end) -end) diff --git a/test/functional/eval/uniq_spec.lua b/test/functional/eval/uniq_spec.lua deleted file mode 100644 index 5cdba0a0f6..0000000000 --- a/test/functional/eval/uniq_spec.lua +++ /dev/null @@ -1,31 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local clear = helpers.clear -local meths = helpers.meths -local command = helpers.command -local exc_exec = helpers.exc_exec -local redir_exec = helpers.redir_exec - -before_each(clear) - -describe('uniq()', function() - it('errors out when processing special values', function() - eq('Vim(call):E362: Using a boolean value as a Float', - exc_exec('call uniq([v:true, v:false], "f")')) - end) - - it('can yield E882 and stop filtering after that', function() - command([[ - function Cmp(a, b) - if type(a:a) == type([]) || type(a:b) == type([]) - return [] - endif - return (a:a > a:b) - (a:a < a:b) - endfunction - ]]) - eq('\nE745: Using a List as a Number\nE882: Uniq compare function failed', - redir_exec('let fl = uniq([0, 0, [], 1, 1], "Cmp")')) - eq({0, {}, 1, 1}, meths.get_var('fl')) - end) -end) diff --git a/test/functional/eval/vvar_event_spec.lua b/test/functional/eval/vvar_event_spec.lua deleted file mode 100644 index eec8aa917a..0000000000 --- a/test/functional/eval/vvar_event_spec.lua +++ /dev/null @@ -1,15 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq -local command = helpers.command -describe('v:event', function() - before_each(clear) - it('is empty before any autocommand', function() - eq({}, eval('v:event')) - end) - - it('is immutable', function() - eq(false, pcall(command, 'let v:event = {}')) - eq(false, pcall(command, 'let v:event.mykey = {}')) - end) -end) - diff --git a/test/functional/eval/wait_spec.lua b/test/functional/eval/wait_spec.lua deleted file mode 100644 index ee95e02a7f..0000000000 --- a/test/functional/eval/wait_spec.lua +++ /dev/null @@ -1,78 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local call = helpers.call -local clear = helpers.clear -local command = helpers.command -local eval = helpers.eval -local eq = helpers.eq -local feed = helpers.feed -local feed_command = helpers.feed_command -local next_msg = helpers.next_msg -local nvim = helpers.nvim -local source = helpers.source -local pcall_err = helpers.pcall_err - -before_each(function() - clear() - local channel = nvim('get_api_info')[1] - nvim('set_var', 'channel', channel) -end) - -describe('wait()', function() - it('waits and returns 0 when condition is satisfied', function() - source([[ - let g:_awake = 0 - call timer_start(100, { -> nvim_command('let g:_awake = 1') }) - ]]) - eq(0, eval('g:_awake')) - eq(0, eval('wait(1500, { -> g:_awake })')) - eq(1, eval('g:_awake')) - - eq(0, eval('wait(0, 1)')) - end) - - it('returns -1 on timeout', function() - eq(-1, eval('wait(0, 0)')) - eq(-1, eval('wait(50, 0)')) - end) - - it('returns -2 when interrupted', function() - feed_command('call rpcnotify(g:channel, "ready") | '.. - 'call rpcnotify(g:channel, "wait", wait(-1, 0))') - eq({'notification', 'ready', {}}, next_msg()) - feed('<c-c>') - eq({'notification', 'wait', {-2}}, next_msg()) - end) - - it('returns -3 on error', function() - command('silent! let ret = wait(-1, "error")') - eq(-3, eval('ret')) - command('let ret = 0 | silent! let ret = wait(-1, { -> error })') - eq(-3, eval('ret')) - end) - - it('evaluates the condition on given interval', function() - source([[ - function Count() - let g:counter += 1 - return g:counter - endfunction - ]]) - - -- XXX: flaky (#11137) - helpers.retry(nil, nil, function() - nvim('set_var', 'counter', 0) - eq(-1, call('wait', 20, 'Count() >= 5', 99999)) - end) - - nvim('set_var', 'counter', 0) - eq(0, call('wait', 10000, 'Count() >= 5', 5)) - eq(5, nvim('get_var', 'counter')) - end) - - it('validates args', function() - eq('Vim:E475: Invalid value for argument 1', pcall_err(call, 'wait', '', 1)) - eq('Vim:E475: Invalid value for argument 3', pcall_err(call, 'wait', 0, 1, -1)) - eq('Vim:E475: Invalid value for argument 3', pcall_err(call, 'wait', 0, 1, 0)) - eq('Vim:E475: Invalid value for argument 3', pcall_err(call, 'wait', 0, 1, '')) - end) -end) diff --git a/test/functional/eval/writefile_spec.lua b/test/functional/eval/writefile_spec.lua deleted file mode 100644 index 14be8c377c..0000000000 --- a/test/functional/eval/writefile_spec.lua +++ /dev/null @@ -1,156 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') - -local clear = helpers.clear -local eq = helpers.eq -local funcs = helpers.funcs -local meths = helpers.meths -local exc_exec = helpers.exc_exec -local read_file = helpers.read_file -local write_file = helpers.write_file -local redir_exec = helpers.redir_exec - -local fname = 'Xtest-functional-eval-writefile' -local dname = fname .. '.d' -local dfname_tail = '1' -local dfname = dname .. '/' .. dfname_tail -local ddname_tail = '2' -local ddname = dname .. '/' .. ddname_tail - -before_each(function() - lfs.mkdir(dname) - lfs.mkdir(ddname) - clear() -end) - -after_each(function() - os.remove(fname) - os.remove(dfname) - lfs.rmdir(ddname) - lfs.rmdir(dname) -end) - -describe('writefile()', function() - it('writes empty list to a file', function() - eq(nil, read_file(fname)) - eq(0, funcs.writefile({}, fname)) - eq('', read_file(fname)) - os.remove(fname) - eq(nil, read_file(fname)) - eq(0, funcs.writefile({}, fname, 'b')) - eq('', read_file(fname)) - os.remove(fname) - eq(nil, read_file(fname)) - eq(0, funcs.writefile({}, fname, 'ab')) - eq('', read_file(fname)) - os.remove(fname) - eq(nil, read_file(fname)) - eq(0, funcs.writefile({}, fname, 'a')) - eq('', read_file(fname)) - end) - - it('writes list with an empty string to a file', function() - eq(0, exc_exec( - ('call writefile([$XXX_NONEXISTENT_VAR_XXX], "%s", "b")'):format( - fname))) - eq('', read_file(fname)) - eq(0, exc_exec(('call writefile([$XXX_NONEXISTENT_VAR_XXX], "%s")'):format( - fname))) - eq('\n', read_file(fname)) - end) - - it('writes list with a null string to a file', function() - eq(0, exc_exec( - ('call writefile([v:_null_string], "%s", "b")'):format( - fname))) - eq('', read_file(fname)) - eq(0, exc_exec(('call writefile([v:_null_string], "%s")'):format( - fname))) - eq('\n', read_file(fname)) - end) - - it('appends to a file', function() - eq(nil, read_file(fname)) - eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname)) - eq('abc\ndef\nghi\n', read_file(fname)) - eq(0, funcs.writefile({'jkl'}, fname, 'a')) - eq('abc\ndef\nghi\njkl\n', read_file(fname)) - os.remove(fname) - eq(nil, read_file(fname)) - eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname, 'b')) - eq('abc\ndef\nghi', read_file(fname)) - eq(0, funcs.writefile({'jkl'}, fname, 'ab')) - eq('abc\ndef\nghijkl', read_file(fname)) - end) - - it('correctly treats NLs', function() - eq(0, funcs.writefile({'\na\nb\n'}, fname, 'b')) - eq('\0a\0b\0', read_file(fname)) - eq(0, funcs.writefile({'a\n\n\nb'}, fname, 'b')) - eq('a\0\0\0b', read_file(fname)) - end) - - it('writes with s and S', function() - eq(0, funcs.writefile({'\na\nb\n'}, fname, 'bs')) - eq('\0a\0b\0', read_file(fname)) - eq(0, funcs.writefile({'a\n\n\nb'}, fname, 'bS')) - eq('a\0\0\0b', read_file(fname)) - end) - - it('correctly overwrites file', function() - eq(0, funcs.writefile({'\na\nb\n'}, fname, 'b')) - eq('\0a\0b\0', read_file(fname)) - eq(0, funcs.writefile({'a\n'}, fname, 'b')) - eq('a\0', read_file(fname)) - end) - - it('shows correct file name when supplied numbers', function() - meths.set_current_dir(dname) - eq('\nE482: Can\'t open file 2 for writing: illegal operation on a directory', - redir_exec(('call writefile([42], %s)'):format(ddname_tail))) - end) - - it('errors out with invalid arguments', function() - write_file(fname, 'TEST') - eq('\nE119: Not enough arguments for function: writefile', - redir_exec('call writefile()')) - eq('\nE119: Not enough arguments for function: writefile', - redir_exec('call writefile([])')) - eq('\nE118: Too many arguments for function: writefile', - redir_exec(('call writefile([], "%s", "b", 1)'):format(fname))) - for _, arg in ipairs({'0', '0.0', 'function("tr")', '{}', '"test"'}) do - eq('\nE475: Invalid argument: writefile() first argument must be a List or a Blob', - redir_exec(('call writefile(%s, "%s", "b")'):format(arg, fname))) - end - for _, args in ipairs({'[], %s, "b"', '[], "' .. fname .. '", %s'}) do - eq('\nE806: using Float as a String', - redir_exec(('call writefile(%s)'):format(args:format('0.0')))) - eq('\nE730: using List as a String', - redir_exec(('call writefile(%s)'):format(args:format('[]')))) - eq('\nE731: using Dictionary as a String', - redir_exec(('call writefile(%s)'):format(args:format('{}')))) - eq('\nE729: using Funcref as a String', - redir_exec(('call writefile(%s)'):format(args:format('function("tr")')))) - end - eq('\nE5060: Unknown flag: «»', - redir_exec(('call writefile([], "%s", "bs«»")'):format(fname))) - eq('TEST', read_file(fname)) - end) - - it('does not write to file if error in list', function() - local args = '["tset"] + repeat([%s], 3), "' .. fname .. '"' - eq('\nE805: Expected a Number or a String, Float found', - redir_exec(('call writefile(%s)'):format(args:format('0.0')))) - eq(nil, read_file(fname)) - write_file(fname, 'TEST') - eq('\nE745: Expected a Number or a String, List found', - redir_exec(('call writefile(%s)'):format(args:format('[]')))) - eq('TEST', read_file(fname)) - eq('\nE728: Expected a Number or a String, Dictionary found', - redir_exec(('call writefile(%s)'):format(args:format('{}')))) - eq('TEST', read_file(fname)) - eq('\nE703: Expected a Number or a String, Funcref found', - redir_exec(('call writefile(%s)'):format(args:format('function("tr")')))) - eq('TEST', read_file(fname)) - end) -end) |